// returns 0 if NOT in check after the move // return 1 if in check after the move int simCheck(struct board * b, struct piece * p, struct pos * move, struct piece * k ) { struct piece * inactivePiece = NULL; struct pos * tempLoc; struct board * nBoard = copyBoard(b); struct pos * nMove = makeLoc(move->x, move->y); nMove->type = move->type; if(move->type ==4) { nMove->additionalM1 = move->additionalM1; nMove->additionalM2 = move->additionalM2; nMove->additionalP = getSpace(nBoard, move->x, move->y); } int temp = getOrder(b, p); int temp1; if(move->taken != NULL) { temp1 = getOrder(b,move->taken); nMove->taken = nBoard->pieces[temp1]; } else{ nMove->taken = NULL; } // printAllMoves(nBoard); movePiece(nBoard,nBoard->pieces[temp],nMove); updateAllMovesSim(nBoard); free(nMove); if(move->type == 4) { if(incheckCheck(nBoard,move->additionalP,move->additionalP->loc) == 1) { deleteBoard(nBoard); return 1; } deleteBoard(nBoard); return 0; } if(incheckCheck(nBoard,k,k->loc) == 1) { deleteBoard(nBoard); return 1; } deleteBoard(nBoard); return 0; }
void AIMediocrePlayer::requestMove(PieceColor moveType) { assert(m_array); auto gameLogic = m_gameLogic.lock(); std::vector<int> scores; auto lockedGameLogic = m_gameLogic.lock(); std::vector<PieceMove> moves = lockedGameLogic->getAllPossibleMoves(*m_array, moveType); std::vector<std::future<int>> futures; for(const auto& move: moves) { Array copyOfArray = *m_array; copyOfArray.move(move.source().m_row, move.source().m_col, move.destination().m_row, move.destination().m_col); for(const auto& pos: move.capturedPieces()) { copyOfArray.erase(pos.m_row, pos.m_col); } int newScore = move.numberOfCapturedPieces(); auto score = std::async(std::launch::async, &minMaxWithAlphaBetaPruning, lockedGameLogic, copyOfArray, m_maxDepth, newScore, getOppositeColor(moveType), moveType, gMinusInfinity, gPlusInfinity); futures.push_back(std::move(score)); } for(auto& future: futures) { auto result = future.get(); scores.push_back(result); } auto it = std::max_element(scores.begin(), scores.end()); PieceMove move = moves.at(std::distance(scores.begin(), it)); std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); }
bool AI::makeMove(SDL_Event *event){ // Init enemyTeam that this class can use getEnemyTeam(); for(int index=0;index<team.size();index++){ currentIndex = index; team[index].directionValues[0] = maxValue(Board->virtualBoard, team, enemyTeam, MAX_DEPTH, LEFT); team[index].directionValues[1] = maxValue(Board->virtualBoard, team, enemyTeam, MAX_DEPTH, RIGHT); if (team[index].isKing()) { team[index].directionValues[3] = maxValue(Board->virtualBoard, team, enemyTeam, MAX_DEPTH, BACK_RIGHT); team[index].directionValues[2] = maxValue(Board->virtualBoard, team, enemyTeam, MAX_DEPTH, BACK_LEFT); } cout<<"Index: "<<index<<" ("<< team[index].x << "," << team[index].y; cout<<") Left: "<<team[index].directionValues[0]<<" Right: "<<team[index].directionValues[1]; cout<<" bLeft: "<<team[index].directionValues[2]<<" bRight: "<<team[index].directionValues[3]<<endl; team[index].findBestDirection(); team[index].findLargestPotenial(); } int bestPieceIndex = bestPiece(team); cout<< "The chosen one: " << bestPieceIndex << " -> ("<< team[bestPieceIndex].x << "," << team[bestPieceIndex].y; int x = team[bestPieceIndex].x; int y = team[bestPieceIndex].y; // Makes sure the move isnt out of bounds // if (team[bestPieceIndex].potential != OUT_OF_BOUND) { changeWithDirection(x, y, team[bestPieceIndex].bestDirection, false); if(sameTeam(Board->virtualBoard[x][y],ENEMY_TEAM_NUMBER)){ // Changes it again for moving 2 units diagonally // changeWithDirection(x, y, team[bestPieceIndex].bestDirection, false); } cout<<") best move: (" << x << "," << y <<")"<< endl; movePiece(Board->virtualBoard, team, bestPieceIndex, x, y); return true; } return false; }
int AI::minValue(vector<vector<int>> tempBoard, vector<Piece> teamCopy, vector<Piece> enemyTeamCopy, int depth, Directions direction){ bool killMove = false; if(!checkNode(tempBoard, teamCopy, enemyTeamCopy, direction, true)){ return OUT_OF_BOUND; } int x = enemyTeamCopy[enemyCurrentIndex].x; int y = enemyTeamCopy[enemyCurrentIndex].y; changeWithDirection(x, y, direction, true); if(sameTeam(tempBoard[x][y],TEAM_NUMBER)){ if(!killCheckArea(tempBoard, x, y, direction, true)){ return OUT_OF_BOUND; } else{ changeWithDirection(x, y, direction, true); killMove = true; } } //This should move on the tempBoard movePiece(tempBoard, enemyTeamCopy, enemyCurrentIndex, x, y); updateKings(tempBoard, enemyTeamCopy, true); if (killMove) { updateTeam(tempBoard, teamCopy, false); if (teamCopy.size()<=0) { //smallest number return -1 * WIN_VALUE; } } if (depth <= 0) { return valueCalculator(teamCopy, enemyTeamCopy); } else{ return maxMove(tempBoard, teamCopy, enemyTeamCopy, depth-1); } }
/* returns 2 if the move caused a promotion * returns 1 if valid * returns -1 if invalid m1 * returns -2 if invalid m2 * returns -3 if not your turn */ int tryMove(struct board* b,int x1,int y1,int x2,int y2, int player) { if(player != b->currentPlayer) { return -3; } struct pos * m1 = makeLoc(x1,y1); struct pos * m2 = makeLoc(x2,y2); struct piece * mover = getSpace(b,x1,y1); if(mover == NULL) { return -1; } if(mover->player != b->currentPlayer) return -1; struct pos * m3 = validMoveForPiece(mover,m2); free(m1); free(m2); if(m3 != NULL) { movePiece(b, mover, m3); updateAllMoves(b); if(checkPromotion(b)) { b->currentPlayer = (b->currentPlayer+1)%2; return 2; } return 1; } else { return -2; } }
int Game::update() { //This is probably graphical stuff and thus commented out //int currTime = (int)clock.getElapsedTime().asSeconds() + timeOffset; // Update clockstring //This is probably graphical stuff and thus commented out //clockText.setString(std::to_string(currTime / 60) + ":" + std::to_string(currTime % 60)); // Make sure that no moves is asked after checkmate or stalemate // Start new thread and calculate time elapsed for algorithm //clock.restart(); std::pair<int, int> aimove = getAiMove(); movePiece(aimove); //std::cout << "AI(lvl:" << playerOnTurn->getLevel() << ") calculated next turn in " << std::endl; return changeTurn(); }
/* Types of moves: 1) King normal move 2) King captures 3) King castles 4) */ int playMove(const position * const pos, position *newPosition, const move * const m, const int player) { int opponent; opponent = OPPONENT(player); /* assert consistency of position */ assertPosition(pos); /* opponent cannot be check, this should be handled elsewhere */ assert(!inCheck(pos, opponent, pos->kingSquare[opponent])); /* init new position to old position */ *newPosition = *pos; /* opponent has to play in the new position */ newPosition->toPlay = opponent; movePiece(newPosition, m, player); if(IS_CAPTURE(m)) { /* clear bitmask for captured piece */ clearCapturedPiece(newPosition, m); } /* ep is disabled after any move played */ DISABLE_EP(newPosition); /* assert consistency of new position */ assertPosition(newPosition); return 0; }
int Game::play() { while (m_running) { if (m_falling == false) addNewPiece(); if (pieceCanFall()) applyFalling(); else { fixPiece(); cleanLines(); } display(); movePiece(m_controler.getEvent()); display(); usleep((1000000 / 10) * (m_speed / m_speedup)); m_turn++; std::cout << m_turn << " => " << m_piece.getY() << std::endl; if (m_turn % SPEED_UP_DELAY == 0 && m_speed > 1) m_speed--; } return (0); }
int main(){ int in_game=0; int turnPre=0; int mode=-1; /*range 1-3*/ int diff=-1; /*range 0-3, 0 if pvp*/ int timer=-1; /*range 0, 5, 10, 20*/ int side=-1; /*range '0' for white, '1' for black*/ int all41 = -1; /* range 0-5 depending on piece */ char confirm='n'; /*range 'n', 'y'*/ char modeS[26]; char diffS[26]; char timerS[26]; board *board = createNewGame(); int timer1 = 0; int timer2 = 0; int timer3 = 0; int timer4 = 0; int timer5 = 0; int altcounter = 1; do{ /*game setup*/ printf("\nChess v1.0 by nøl / C Gets Degrees\n\n"); while (mode < 1){ printf("Please select game mode:\n"); printf("1. Player versus Player\n"); printf("2. Player versus Computer\n"); printf("3. Computer versus Computer\n\n"); scanf("%d", &mode); switch(mode){ case 1: printf("Player versus Player selected\n"); break; case 2: printf("Player versus Computer selected\n\n"); printf("Choose a side: White(0) or Black(1)?\n"); scanf("%d", &side); switch(side){ case 0: printf("White selected\n"); break; case 1: printf("Black selected\n"); break; default: printe(selection); side = -1; break; } break; case 3: printf("Computer versus Computer selected\n"); break; default: printe(selection); mode = -1; break; } } while (all41 < 0){ printf("\nPlease select game type. All-for-One mode creates all pieces of the same type!\n"); printf("0. Standard Chess\n"); printf("1. All-for-Pawn\n"); printf("2. All-for-Knight\n"); printf("3. All-for-Queen\n"); printf("4. All-for-Rook\n"); printf("5. All-for-Bishop\n"); scanf("%d", &all41); switch(all41){ case 0: printf("Standard chess selected\n"); break; case 1: printf("All-for-Pawn selected\n"); break; case 2: printf("All-for-Knight selected\n"); break; case 3: printf("All-for-Queen selected\n"); break; case 4: printf("All-for-Rook selected\n"); break; case 5: printf("All-for-Bishop selected\n"); break; default: printe(selection); all41 = -1; break; } } while (diff < 0){ if (mode == 1){ diff = 0; break; } printf("\nPlease select computer difficulty:\n"); printf("1. Easy\n"); printf("2. Medium\n"); printf("3. Hard\n\n"); scanf("%d", &diff); switch(diff){ case 1: printf("Easy selected\n"); break; case 2: printf("Medium selected\n"); break; case 3: printf("Hard selected\n"); break; default: printe(selection); diff = -1; break; } } while (timer < 0){ printf("\nPlease select game timer length:\n"); printf("0. No limit\n"); printf("5. 5 minutes\n"); printf("10. 10 minutes\n"); printf("20. 20 minutes\n\n"); scanf("%d", &timer); switch(timer){ case 0: printf("No limit selected\n"); timer = 0; break; case 5: printf("5 minutes selected\n"); timer1 = timer*60; timer3 = timer*60; break; case 10: printf("10 minutes selected\n"); timer1 = timer*60; timer3 = timer*60; break; case 20: printf("20 minutes selected\n"); timer1 = timer*60; timer3 = timer*60; break; default: printe(selection); timer1 = 0; timer3 = 0; timer = -1; break; } } /*CREATE STRINGS FOR SELECTIONS*/ switch(mode){ case 1: strcpy(modeS, "Player versus Player"); break; case 2: strcpy(modeS, "Player versus Computer"); break; case 3: strcpy(modeS, "Computer versus Computer"); break; } switch(diff){ case 0: strcpy(diffS, ""); break; case 1: strcpy(diffS, "\nDifficulty: Easy"); break; case 2: strcpy(diffS, "\nDifficulty: Medium"); break; case 3: strcpy(diffS, "\nDifficulty: Hard"); break; } switch(timer){ case 0: strcpy(timerS, "No time limit"); break; case 5: strcpy(timerS, "5 minutes"); break; case 10: strcpy(timerS, "10 minutes"); break; case 20: strcpy(timerS, "20 minutes"); break; } /*CONFIRM SELECTIONS*/ printf("\n\nPlease confirm selections: [y/n]\n\n"); printf("Mode: %s", modeS); printf("%s", diffS); printf("\nTimer: %s\n\n", timerS); scanf(" %c", &confirm); if (confirm == 'y' || confirm == 'Y'){ in_game = 1; fgetc(stdin); /* absorb the /n produced by the last scanf */ createMoveLog(); } else if (confirm == 'n' || confirm == 'N'){ mode = -1; side = -1; diff = -1; timer = -1; all41 = -1; } else{ printe(selection); } int aiTeam1, aiTeam2; if(mode == 2){ /* Inverts input value 0 -> 1, 1 -> 0, other input will cause assertion failure */ aiTeam1 = oppTeam(side); /* oppTeam function comes from ai.c. Reads an int, returns an int. */ } if(mode == 3){ /* Default for CPU vs CPU */ aiTeam1 = 0; aiTeam2 = 1; } while(in_game){ /* if side = 1, player is black */ if (timer != 0){ /* set up timer */ if (altcounter % 2 != 0){ timer5 = timer4 - timer2; timer1 = timer1 - timer5; altcounter = altcounter+1; } else{ timer5 = timer4 - timer2; timer3 = timer3 - timer5; altcounter = altcounter+1; } if (timer1 <= 0){ printf("\nWhite has run out of time!\n"); exit(0); } if (timer3 <= 0){ printf("\nBlack has run out of time!\n"); exit(0); } } int alpha; cell *tmp1; switch(all41){ case 0: break; case 1: for(alpha = 0; alpha <64; alpha++){ tmp1 = getCell(alpha, board); if (tmp1->piece != NULL && tmp1->piece->type != king){ tmp1->piece->type = pawn; updatePrintPiece(tmp1); } } break; case 2: for(alpha = 0; alpha <64; alpha++){ tmp1 = getCell(alpha, board); if (tmp1->piece != NULL && tmp1->piece->type != king){ tmp1->piece->type = knight; updatePrintPiece(tmp1); } } break; case 3: for(alpha = 0; alpha <64; alpha++){ tmp1 = getCell(alpha, board); if (tmp1->piece != NULL && tmp1->piece->type != king){ tmp1->piece->type = queen; updatePrintPiece(tmp1); } } break; case 4: for(alpha = 0; alpha <64; alpha++){ tmp1 = getCell(alpha, board); if (tmp1->piece != NULL && tmp1->piece->type != king){ tmp1->piece->type = rook; updatePrintPiece(tmp1); } } break; case 5: for(alpha = 0; alpha <64; alpha++){ tmp1 = getCell(alpha, board); if (tmp1->piece != NULL && tmp1->piece->type != king){ tmp1->piece->type = bishop; updatePrintPiece(tmp1); } } break; } turnPre = board->turn; timer2 = (int) time(NULL); updateGameDisplay(board); /* display the entire board only when its a new turn */ while (turnPre == board->turn){ cell *temp; switch(mode){ case 1: /* PvP */ updateMessage(board); /*board->turn++;*/ break; case 2: /* P vs AI */ if(board->turn%2 == aiTeam1){ /* AI's turn */ printMessage(board->turn); if (board->turn == 0){ temp = getCell(12, board); movePiece(temp->piece, getCell(20, board)); temp = NULL; } else if (board->turn == 1){ temp = getCell(52, board); movePiece(temp->piece, getCell(44, board)); } else if (board->turn == 2){ temp = getCell(3, board); movePiece(temp->piece, getCell(21, board)); } else if (board->turn == 3){ temp = getCell(59, board); movePiece(temp->piece, getCell(45, board)); } else if (board->turn == 4){ temp = getCell(5, board); movePiece(temp->piece, getCell(26, board)); } else if (board->turn == 5){ temp = getCell(61, board); movePiece(temp->piece, getCell(34, board)); } else if (board->turn == 6){ temp = getCell(21, board); movePiece(temp->piece, getCell(53, board)); } else if (board->turn == 7){ temp = getCell(45, board); movePiece(temp->piece, getCell(13, board)); } else{ aiMove(diff, aiTeam1, board); } } else{ /* player's turn */ updateMessage(board); /*board->turn++;*/ } break; case 3: /* AI vs AI*/ if(board->turn%2 == 0){ /* White's turn */ /* aiTeam1 goes */ printMessage(board->turn); aiMove(diff, aiTeam1, board); /*board->turn++;*/ } else{ /* Black's turn */ /* aiTeam2 goes */ printMessage(board->turn); aiMove(diff, aiTeam2, board); /*board->turn++;*/ } break; } /* Exits loop when turn is finished */ } timer4 = (int) time(NULL); if (timer != 0 && board->turn > 1){ printf("DEBUG: Current time: %d\n", timer4); printf("DEBUG: Current time: %d\n", timer2); printf("Time remaining for Player 1: %d seconds.\n", timer1); printf("Time remaining for Player 2: %d seconds.\n", timer3); } } } while(!in_game); return 0; }
void IPiece::resetPiece(Place *place) { movePiece(place); isFirstMove = true; }
/* * Executes a command given by the user * * @params: (command) - the command given by the user * @return: relevant exitcode */ int executeCommand(char* command){ char str[64]; sscanf(command, "%s", str); if (str_equals(str, "quit")){ exit(0); } if (state == SETTINGS){ if (str_equals(str, "game_mode")){ return setGameMode(command); } if (str_equals(str, "difficulty")){ return setDifficulty(command); } if (str_equals(str, "user_color")){ return setUserColor(command); } if (str_equals(str, "load")){ return loadGameByCommand(command); } if (str_equals(str, "clear")){ Board_clear(&board); PieceCounter_reset(counter); return 0; } if (str_equals(str, "next_player")){ return setFirstPlayer(command); } if (str_equals(str, "rm")){ return removePiece(command); } if (str_equals(str, "set")){ return setPiece(command); } if (str_equals(str, "print")){ display(); return 0; } if (str_equals(str, "start")){ if(PieceCounter_kingIsMissing(counter)){ return -7; } turn = first; state = GAME; return 2; //special value to break the humanTurn loop so the initial board will always be checked for immediate loss or tie conditions } } else{ if (str_equals(str, "get_moves")){ return printMovesOfPiece(command); } if (str_equals(str, "move")){ return movePiece(command); } if (str_equals(str, "castle")){ return castleRook(command); } if (str_equals(str, "get_best_moves")){ return printBestMoves(command); } if (str_equals(str, "get_score")){ return printMoveValue(command); } if (str_equals(str,"save")){ return saveGameByCommand(command); } } return -1; }
// Undo a previously made move. void unmove(board_t *b, const revMove_t m) { piece_t pieceMoved; int to = m.move.to; int from = m.move.from; int priorCastleBits = m.priorCastleBits; int priorEnPassant = m.priorEnPassant; int priorZobristEnPassant = m.priorZobristEnPassantCol; int priorHalfMoveCount = m.priorHalfMoveCnt; piece_t promote = (piece_t)(m.move.promote); piece_t captured = (piece_t)(m.captured); color_t oppositeColor = (b->toMove == WHITE ? BLACK : WHITE); // STEP 1: Remove the piece at the destination square, return to source square... // SPECIAL CASE: A pawn was promoted. Remove the promoted piece.... if(promote != PIECE_NONE) { removePiece(b, to, promote, oppositeColor); addPiece(b, from, PAWN, oppositeColor); pieceMoved = PAWN; } else { // Determine which piece is there.... pieceMoved = ( (b->pieces[PAWN] & squareMask[to]) ? PAWN : ( (b->pieces[KNIGHT] & squareMask[to]) ? KNIGHT : ( (b->pieces[BISHOP] & squareMask[to]) ? BISHOP : ( (b->pieces[ROOK] & squareMask[to]) ? ROOK : ( (b->pieces[QUEEN] & squareMask[to]) ? QUEEN : KING))))); movePiece(b, to, from, pieceMoved, oppositeColor); } // STEP 2: Return captured piece if any // If a piece was captured last turn if(captured != PIECE_NONE) { int offset = 0; // If it was captured on the enPassant square, assess an offset to where the piece will be returned. if( (to % 8 == priorEnPassant) && ( (to / 8) == (b->toMove == BLACK ? 2 : 5) ) ) { offset = (oppositeColor == BLACK ? -8 : 8); } addPiece(b, to + offset, captured, b->toMove); } // STEP 3: Undo rook moves from any castles... // TODO CHESS960 if(pieceMoved == KING) { if(abs(to-from) == 2) { if(to == C1) { movePiece(b, D1, A1, ROOK, WHITE); } else if(to == G1) { movePiece(b, F1, H1, ROOK, WHITE); } else if(to == C8) { movePiece(b, D8, A8, ROOK, BLACK); } else if(to == G8) { movePiece(b, F8, H8, ROOK, BLACK); } else { ASSERT(0); } } } // Revert castling status if necessary if( (priorCastleBits & WHITE_CASTLE_SHORT) != (b->castleBits & WHITE_CASTLE_SHORT) ) { b->hash ^= Z_WHITE_SHORT_KEY; } if( (priorCastleBits & WHITE_CASTLE_LONG) != (b->castleBits & WHITE_CASTLE_LONG) ) { b->hash ^= Z_WHITE_LONG_KEY; } if( (priorCastleBits & BLACK_CASTLE_SHORT) != (b->castleBits & BLACK_CASTLE_SHORT) ) { b->hash ^= Z_BLACK_SHORT_KEY; } if( (priorCastleBits & BLACK_CASTLE_LONG) != (b->castleBits & BLACK_CASTLE_LONG) ) { b->hash ^= Z_BLACK_LONG_KEY; } b->castleBits = priorCastleBits; // Revert enPassant row if necessary // If current doesn't match prior if(priorZobristEnPassant != b->zobristEnPassantCol) { if(priorZobristEnPassant != 8) { b->hash ^= Z_ENPASSANT_COL_KEY(priorZobristEnPassant); } if( b->zobristEnPassantCol != 8) { b->hash ^= Z_ENPASSANT_COL_KEY(b->zobristEnPassantCol); } } b->zobristEnPassantCol = priorZobristEnPassant; b->enPassantCol = priorEnPassant; if(b->toMove == WHITE) { b->toMove = BLACK; b->moveNumber--; } else { b->toMove = WHITE; } b->hash ^= Z_WHITE_TURN_KEY; // Either side to move will trigger this toggle. b->halfMoves = priorHalfMoveCount; positionIndex--; if(positionIndex < 0) { positionIndex = POSITION_HISTORY_SIZE - 1; } }
// Move assumed valid for this board. // Add/remove functions will ASSERT adds are to empty squares and removes have expected piece there... // Castling moves assumed legal (if to/from square and piece moved match a castle for king), rook is also moved with king revMove_t move(board_t *b, const move_t m) { unsigned char to = m.to; unsigned char from = m.from; int offset = 0; revMove_t retValue; // A place holder for the side to move (saves repeated pointer access) color_t toMove = b->toMove; // A place to hold the "opposite color" calculation color_t oppositeColor = (toMove == WHITE ? BLACK : WHITE); // promotion piece (if any) piece_t promote = (piece_t)(m.promote); // handy marker for piece moved piece_t pieceMoved = ( (b->pieces[PAWN] & squareMask[from]) ? PAWN : ( (b->pieces[KNIGHT] & squareMask[from]) ? KNIGHT : ( (b->pieces[BISHOP] & squareMask[from]) ? BISHOP : ( (b->pieces[ROOK] & squareMask[from]) ? ROOK : ( (b->pieces[QUEEN] & squareMask[from]) ? QUEEN : KING))))); // Test that side to move has proper value ASSERT( (toMove == WHITE) || (toMove == BLACK) ); // Check that a piece of the side to move exists at the origin ASSERT( (b->colors[toMove] & squareMask[from]) != 0); // Prepare the return value... retValue.move.from = from; retValue.move.to = to; retValue.move.promote = promote; retValue.priorCastleBits = b->castleBits; retValue.priorEnPassant = b->enPassantCol; retValue.priorHalfMoveCnt = b->halfMoves; retValue.priorZobristEnPassantCol = b->zobristEnPassantCol; retValue.captured = b->colors[oppositeColor] & squareMask[to] ? ( (b->pieces[PAWN] & squareMask[to]) ? PAWN : ( (b->pieces[KNIGHT] & squareMask[to]) ? KNIGHT : ( (b->pieces[BISHOP] & squareMask[to]) ? BISHOP : ( (b->pieces[ROOK] & squareMask[to]) ? ROOK : QUEEN)))) : PIECE_NONE; // Check for capture enPassant... if( (pieceMoved == PAWN) && // moved a pawn ( (to % 8) != (from % 8) ) && // to and from files are different ( (squareMask[to] & b->colors[oppositeColor]) == 0) // target square doesn't have enemy piece ) { offset = (toMove == WHITE ? 8 : -8); retValue.captured = PAWN; } // First remove any captured piece from the board if(retValue.captured != PIECE_NONE) { removePiece(b, to + offset, retValue.captured, oppositeColor ); } if(promote == PIECE_NONE) { // Simply move the piece back movePiece(b, from, to, pieceMoved, toMove); } else { ASSERT( ( ( (to < 8) && toMove) == WHITE) || ( (to > 55) && toMove == BLACK ) ); ASSERT( pieceMoved == PAWN); // Remove pawn removePiece(b, from, pieceMoved, toMove); // Add promoted piece addPiece(b, to, promote, toMove); } // If this was a castling move, move the rook too... if(pieceMoved == KING) { if(from == E1) { if(to == C1) { movePiece(b, A1, D1, ROOK, toMove); } else if(to == G1) { movePiece(b, H1, F1, ROOK, toMove); } } else if(from == E8) { if(to == C8) { movePiece(b, A8, D8, ROOK, toMove); } else if(to == G8) { movePiece(b, H8, F8, ROOK, toMove); } } } // TODO CHESS960 // Adjust Castling possibilities if needed if( pieceMoved == KING ) { if( toMove == WHITE) { if(b->castleBits & WHITE_CASTLE_LONG) { b->hash ^= Z_WHITE_LONG_KEY; } if(b->castleBits & WHITE_CASTLE_SHORT) { b->hash ^= Z_WHITE_SHORT_KEY; } b->castleBits &= ~(WHITE_CASTLE_LONG | WHITE_CASTLE_SHORT); } else { if(b->castleBits & BLACK_CASTLE_LONG) { b->hash ^= Z_BLACK_LONG_KEY; } if(b->castleBits & BLACK_CASTLE_SHORT) { b->hash ^= Z_BLACK_SHORT_KEY; } b->castleBits &= ~(BLACK_CASTLE_LONG | BLACK_CASTLE_SHORT); } } if( pieceMoved == ROOK ) { if(from == A1 && b->castleBits & WHITE_CASTLE_LONG) { b->hash ^= Z_WHITE_LONG_KEY; b->castleBits &= ~WHITE_CASTLE_LONG; } else if (from == H1 && b->castleBits & WHITE_CASTLE_SHORT) { b->hash ^= Z_WHITE_SHORT_KEY; b->castleBits &= ~WHITE_CASTLE_SHORT; } else if(from == A8 && b->castleBits & BLACK_CASTLE_LONG) { b->hash ^= Z_BLACK_LONG_KEY; b->castleBits &= ~BLACK_CASTLE_LONG; } else if (from == H8 && b->castleBits & BLACK_CASTLE_SHORT) { b->hash ^= Z_BLACK_SHORT_KEY; b->castleBits &= ~BLACK_CASTLE_SHORT; } } // If a rook was captured, that affects castling too... if( retValue.captured == ROOK) { if( (to == A1) && (b->castleBits & WHITE_CASTLE_LONG) ) { b->hash ^= Z_WHITE_LONG_KEY; b->castleBits &= ~WHITE_CASTLE_LONG; } else if( (to == H1) && (b->castleBits & WHITE_CASTLE_SHORT) ) { b->hash ^= Z_WHITE_SHORT_KEY; b->castleBits &= ~WHITE_CASTLE_SHORT; } else if( (to == A8) && (b->castleBits & BLACK_CASTLE_LONG) ) { b->hash ^= Z_BLACK_LONG_KEY; b->castleBits &= ~BLACK_CASTLE_LONG; } else if( (to == H8) && (b->castleBits & BLACK_CASTLE_SHORT) ) { b->hash ^= Z_BLACK_SHORT_KEY; b->castleBits &= ~BLACK_CASTLE_SHORT; } } // Adjust halfmove count if( (pieceMoved == PAWN) || (retValue.captured != PIECE_NONE) ) { b->halfMoves = 0; } else { b->halfMoves++; } // Adjust move number if black just moved if(toMove == BLACK) { b->moveNumber++; } // Adjust side to move b->toMove = oppositeColor; b->hash ^= Z_WHITE_TURN_KEY; // Either side to move will trigger this toggle. // Adjust enPassant col if we moved a pawn forward two if ( (pieceMoved == PAWN) && (abs(from - to) == 16) ) { b->enPassantCol = to & 0x07; if( (shiftE(squareMask[to]) & b->pieces[PAWN] & b->colors[oppositeColor]) || (shiftW(squareMask[to]) & b->pieces[PAWN] & b->colors[oppositeColor])) { b->zobristEnPassantCol = to & 0x07; } else { b->zobristEnPassantCol = 8; } } else { b->enPassantCol = 8; b->zobristEnPassantCol = 8; } if(retValue.priorZobristEnPassantCol != b->zobristEnPassantCol) { if(retValue.priorZobristEnPassantCol != 8) { b->hash ^= Z_ENPASSANT_COL_KEY(retValue.priorZobristEnPassantCol); } if( b->zobristEnPassantCol != 8) { b->hash ^= Z_ENPASSANT_COL_KEY(b->zobristEnPassantCol); } } ASSERT(positionIndex < POSITION_HISTORY_SIZE); ASSERT(positionIndex >= 0); positionHistory[positionIndex++] = b->hash; if(positionIndex == POSITION_HISTORY_SIZE) { positionIndex = 0; } return retValue; }
TEST_F(GameLogicTests, ShouldFinishByDraw) { Array defaultArray = createArray10x10({{o,WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); auto game = createAndStartGame(defaultArray, Table::TableVersion::Version_100, PieceColor::White); Array array2 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o,WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(0,1), {Position(1,2)}, array2, PieceColor::White, PieceColor::Black)); Array array3 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(9,5), {Position(8,4)}, array3, PieceColor::Black, PieceColor::White)); Array array4 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o,BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(1,2), {Position(0,1)}, array4, PieceColor::White, PieceColor::Black)); Array array5 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(8,4), {Position(9,5)}, array5, PieceColor::Black, PieceColor::White)); Array array6 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(0,1), {Position(1,2)}, array6, PieceColor::White, PieceColor::Black)); Array array7 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(9,5), {Position(8,4)}, array7, PieceColor::Black, PieceColor::White)); Array array8 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o,BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(1,2), {Position(0,1)}, array8, PieceColor::White, PieceColor::Black)); Array array9 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(8,4), {Position(9,5)}, array9, PieceColor::Black, PieceColor::White)); Array array10 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(0,1), {Position(1,2)}, array10, PieceColor::White, PieceColor::Black)); Array array11 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(9,5), {Position(8,4)}, array11, PieceColor::Black, PieceColor::White)); Array array12 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o,BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(1,2), {Position(0,1)}, array12, PieceColor::White, PieceColor::Black)); Array array13 = createArray10x10({{o, WQ, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(8,4), {Position(9,5)}, array13, PieceColor::Black, PieceColor::White)); Array array14 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o, WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o,BQ, o, o, o, o}}); EXPECT_NO_FATAL_FAILURE(movePiece(game, Position(0,1), {Position(1,2)}, array14, PieceColor::White, PieceColor::Black)); Array array15 = createArray10x10({{o, o, o, o, o, o, o, o, o, o} ,{o, o,WQ, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o} ,{o, o, o, o,BQ, o, o, o, o, o} ,{o, o, o, o, o, o, o, o, o, o}}); EXPECT_CALL(*uiMock, onDraw()); EXPECT_CALL(*uiMock, tableChanged(MatchArray(array15))); EXPECT_CALL(*uiMock, movePerformed(Position(9,5), std::vector<Position>{Position(8,4)})); game->movePiece(Position(9,5), {Position(8,4)}, PieceColor::Black); }
void AIBestPlayer::requestMove(PieceColor moveType) { assert(m_array); auto gameLogic = m_gameLogic.lock(); std::vector<int> scores; auto lockedGameLogic = m_gameLogic.lock(); std::vector<PieceMove> moves = lockedGameLogic->getAllPossibleMoves(*m_array, moveType); std::experimental::optional<std::pair<std::vector<Position>, int>> foundMove = bestMoves::findMove(*m_array, moveType); if(!foundMove || (foundMove && foundMove->second < m_maxDepth)) { std::cout << "computation of best move" << std::endl; std::vector<std::future<int>> futures; for(const auto& move: moves) { Array copyOfArray = *m_array; copyOfArray.move(move.source().m_row, move.source().m_col, move.destination().m_row, move.destination().m_col); for(const auto& pos: move.capturedPieces()) { copyOfArray.erase(pos.m_row, pos.m_col); } int newScore = move.numberOfCapturedPieces(); auto score = std::async(std::launch::async, &minMaxWithAlphaBetaPruning, lockedGameLogic, copyOfArray, m_maxDepth, newScore, getOppositeColor(moveType), moveType, gMinusInfinity, gPlusInfinity); futures.push_back(std::move(score)); } for(auto& future: futures) { auto result = future.get(); scores.push_back(result); } auto it = std::max_element(scores.begin(), scores.end()); PieceMove move = moves.at(std::distance(scores.begin(), it)); std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); } else { std::vector<Position>& positions = foundMove->first; for(const auto& move: moves) { if(positions == move.subMoves()) { std::cout << "used saved best move" << std::endl; std::vector<Position> subMoves{move.subMoves().begin()+1, move.subMoves().end()}; lockedGameLogic->movePiece(move.source(), subMoves, moveType); } } } }