/* * Add an available move for the player to the list of moves, the move is specifically created for peons, * as it may contain promotions. * - Move is expected to be valid in terms of piece type constraints (e.g: a peon can only move to 3 possible squares). * - Additional validation will be done in this function (moves that result in a check status for the current player are * illegal). * --> If the move is legal, it is added to the list of possibleMoves. Otherwise nothing happens. * Input: * board ~ The chess game board. * possibleMoves ~ A list of possible moves by the current player, we aggregate it as we check * possible eat / position change moves. * isMovesForBlackPlayer ~ True if current player is black. False if white. * startPos ~ Where the piece is currently located. * targetX, targetY ~ Coordinates of where the piece will move to. * kingPos ~ Current position of the current player's king (following the execution of the move). */ void addPeonMove(char board[BOARD_SIZE][BOARD_SIZE], LinkedList* possibleMoves, bool isMovesForBlackPlayer, Position* startPos, int targetX, int targetY, Position* kingPos) { bool isMoveAdded = addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, targetX, targetY, kingPos); if (g_memError) return; if (!isMoveAdded) return; // If the pawn reaches the edge, the moves become promotion moves. if (isSquareOnOppositeEdge(isMovesForBlackPlayer, targetX)) { char bishop = isMovesForBlackPlayer ? BLACK_B : WHITE_B; char rook = isMovesForBlackPlayer ? BLACK_R : BLACK_R; char knight = isMovesForBlackPlayer ? BLACK_N : WHITE_N; char queen = isMovesForBlackPlayer ? BLACK_Q : WHITE_Q; ((Move*)(possibleMoves->tail->data))->promotion = queen; // Update the most recent move to a promotion move. addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, targetX, targetY, kingPos); if (g_memError) return; ((Move*)(possibleMoves->tail->data))->promotion = rook; // Update the most recent move to a promotion move. addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, targetX, targetY, kingPos); if (g_memError) return; ((Move*)(possibleMoves->tail->data))->promotion = bishop; // Update the most recent move to a promotion move. addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, targetX, targetY, kingPos); if (g_memError) return; ((Move*)(possibleMoves->tail->data))->promotion = knight; // Update the most recent move to a promotion move. } }
/* * Checks if a piece can move / eat in the given direction. * Input: * board ~ The game board. * possibleMoves ~ A list of possible moves by the current player, we aggregate it as we check * possible eat / position change moves. * isMovesForBlackPlayer ~ True if current player is black. False if white. * startPos ~ Where the piece is currently located. * deltaX, deltaY ~ The direction the piece advances in. * kingPos ~ Current position of the current player's king. */ void queryDirection(char board[BOARD_SIZE][BOARD_SIZE], LinkedList* possibleMoves, bool isMovesForBlackPlayer, Position* startPos, int deltaX, int deltaY, Position* kingPos) { // First square on the diagonal / row / column Position currentSquare = { startPos->x + deltaX, startPos->y + deltaY }; // We advance along the direction, advancing by deltaX, Y each iteration. // We will stop once we no longer hit an empty square. while (isSquareVacant(board, currentSquare.x, currentSquare.y)) { addPossibleMove(board, possibleMoves, isMovesForBlackPlayer,startPos, currentSquare.x, currentSquare.y, kingPos); if (g_memError) return; currentSquare.x += deltaX; currentSquare.y += deltaY; } // If the reason we stopped iterating was we encountered an enemy piece, we get an additional move: an eat move. if (isSquareOccupiedByEnemy(board, isMovesForBlackPlayer, currentSquare.x, currentSquare.y)) { addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, currentSquare.x, currentSquare.y, kingPos); } }
/* * Add possible move for a single spot, if that spot is available for moving to or eating an enemy piece. * Input: * board ~ The game board. * possibleMoves ~ A list of possible moves by the current player, we aggregate it as we check * possible eat / position change moves. * isMovesForBlackPlayer ~ True if current player is black. False if white. * startPos ~ Where the piece is currently located. * deltaX, deltaY ~ How many squares away to move the piece to. * kingPos ~ Current position of the current player's king. */ void querySinglePos(char board[BOARD_SIZE][BOARD_SIZE], LinkedList* possibleMoves, bool isMovesForBlackPlayer, Position* startPos, int deltaX, int deltaY, Position* kingPos) { Position nextSquare = { startPos->x + deltaX, startPos->y + deltaY }; if (isSquareVacant(board, nextSquare.x, nextSquare.y) || isSquareOccupiedByEnemy(board, isMovesForBlackPlayer, nextSquare.x, nextSquare.y)) { Position* kingPosArg; // When the king moves, we should update the kingPos parameter accordingly if ((startPos->x == kingPos->x) && (startPos->y == kingPos->y)) kingPosArg = &nextSquare; // The king's updated position is where the king moves to else kingPosArg = kingPos; // The current move is not made by a king, the kingPos stays the same addPossibleMove(board, possibleMoves, isMovesForBlackPlayer, startPos, nextSquare.x, nextSquare.y, kingPosArg); } }
void generateMoveList() { // First, we'll figure out the horizontal moves that are possible int x, y, i, j; int start, end; move *temp; for (y = 0; y < boardHeight; y++) { end = -1; while (end < boardWidth) { start = -1; // First, find the first place where we can start a line for (x = end + 1; x < boardWidth; x++) { if ((gameBoard[xyToIndex(x, y)] & TOP_LINE) == 0) { start = x; break; } } if (start == -1) break; // No free lines on this line // Now that we know where to start, we'll find where to end end = boardWidth; // So if we don't find lines, we have a good endpoint for (x = start; x < boardWidth; x++) { if (gameBoard[xyToIndex(x, y)] & TOP_LINE) { // We found a place with a line! Stop just before it end = x; break; } } // Now that we've got that, we create the list of possible lines for (i = start; i < end; i++) { for (j = i + 1; j <= end; j++) { addPossibleMove(i, y, j, y); } } } } // We have to handle the last line specially, because we have to check for BOTTOM_LINE, not TOP end = -1; y = boardHeight - 1; while (end < boardWidth) { start = -1; // First, find the first place where we can start a line for (x = end + 1; x < boardWidth; x++) { if ((gameBoard[xyToIndex(x, y)] & BOTTOM_LINE) == 0) { start = x; break; } } if (start == -1) break; // No free lines on this line // Now that we know where to start, we'll find where to end end = boardWidth; // So if we don't find lines, we have a good endpoint for (x = start; x < boardWidth; x++) { if (gameBoard[xyToIndex(x, y)] & BOTTOM_LINE) { // We found a place with a line! Stop just before it end = x; break; } } // Now that we've got that, we create the list of possible lines for (i = start; i < end; i++) { for (j = i + 1; j <= end; j++) { addPossibleMove(i, boardHeight, j, boardHeight); } } } // Now, the same thing, only for virticle lines for (x = 0; x < boardWidth; x++) { end = -1; while (end < boardHeight) { start = -1; // First, find the first place where we can start a line for (y = end + 1; y < boardHeight; y++) { if ((gameBoard[xyToIndex(x, y)] & LEFT_LINE) == 0) { start = y; break; } } if (start == -1) break; // No free lines on this line // Now that we know where to start, we'll find where to end end = boardHeight; // So if we don't find lines, we have a good endpoint for (y = start; y < boardHeight; y++) { if (gameBoard[xyToIndex(x, y)] & LEFT_LINE) { // We found a place with a line! Stop just before it end = y; break; } } // Now that we've got that, we create the list of possible lines for (i = start; i < end; i++) { for (j = i + 1; j <= end; j++) { addPossibleMove(x, i, x, j); } } } } // We have to handle the last line specially, because we have to check for BOTTOM_LINE, not TOP end = -1; x = boardWidth - 1; while (end < boardHeight) { start = -1; // First, find the first place where we can start a line for (y = end + 1; y < boardHeight; y++) { if ((gameBoard[xyToIndex(x, y)] & RIGHT_LINE) == 0) { start = y; break; } } if (start == -1) break; // No free lines on this line // Now that we know where to start, we'll find where to end end = boardHeight; // So if we don't find lines, we have a good endpoint for (y = start; y < boardHeight; y++) { if (gameBoard[xyToIndex(x, y)] & RIGHT_LINE) { // We found a place with a line! Stop just before it end = y; break; } } // Now that we've got that, we create the list of possible lines for (i = start; i < end; i++) { for (j = i + 1; j <= end; j++) { addPossibleMove(boardWidth, i, boardWidth, j); } } } // That's it, the possible move list is full! }