/** When a target square is clicked, this event is prompted * (it is attached to every enabled target square button's onClick). * We execute the given move for the selected chess piece and clicked target using the * logic layer and mark them as possible targets on board. */ void onTargetClick(GuiButton* button) { // Each target button caches a game square in its extent, so it can access the logic layer GameSquare* gameSquare = (GameSquare*)button->generalProperties.extent; if (NULL == gameSquare) return; // Avoid null extents GameControl* gameControl = gameSquare->gameControl; int guiStartX = boardRowIndexToGuiRowIndex(gameControl->selectedSquare->x); int guiTargetX = boardRowIndexToGuiRowIndex(gameSquare->x); // Build the move // Make sure to abort clicks on illegal moves Position initPos = { guiStartX, gameControl->selectedSquare->y }; Position nextPos = { guiTargetX, gameSquare->y }; Move* move = createMove(&initPos, &nextPos); if ((g_memError) || (NULL == move)) return; // If a pawn have reached the other edge, we have a promotion move. // Show the promotion dialog and wait for results. // Since this event can only be prompted by a player, we can count on the isBlackPlayerEditable property if (isSquareOnOppositeEdge(gameControl->isBlackPlayerEditable, nextPos.x) && isSquareOccupiedByPawn(gameControl->board, gameControl->isBlackPlayerEditable, initPos.x, initPos.y)) { move->promotion = showPromotionDialog(button->generalProperties.window, gameControl->isBlackPlayerEditable); } // Black king is an error value of showPromotionDialog (this is an invalid promotion). We quit on errors. if (g_guiError || g_memError || (move->promotion == BLACK_K)) { deleteMove(move); return; } // Validate the move is legal bool isValidMove = validateMove(gameControl->board, gameControl->isBlackPlayerEditable, move); if (!isValidMove) { printf("Error: Gui allowed user to interact with illegal move, but logic protected from executing this move.\n"); deleteMove(move); return; } GuiWindow* window = (GuiWindow*)button->generalProperties.window; // Execute the move and update the gui. If the game is over, return. bool isGameOver = executeGuiTurn(window, gameControl, move); if (isGameOver) return; // When playing against the AI, execute the next turn if (g_gameMode == GAME_MODE_PLAYER_VS_AI) executeGuiNextComputerMove(window); }
/* Adds a move to a move list, after verifying it's legality */ void addMove(Board *brd, int from, int to, int cap, int prom, char castling, MoveList *list) { Move move; move = createMove(brd, from, to, cap, prom, castling); if (move.from != 0) { list->moves[list->numMoves] = move; list->numMoves++; } }
Move* parseMove(char* moveString) { char initialPosition[7]; bool isDoubleDigits = moveString[4] != '>'; if (isDoubleDigits) { strncpy(initialPosition, moveString, 6); initialPosition[6] = '\0'; } else { strncpy(initialPosition, moveString, 5); initialPosition[5] = '\0'; } Position from = parsePosition(initialPosition); int lengthToSkip = isDoubleDigits ? 10 : 9;//<x,y>_to_ PositionList* to = parseDestination(moveString + lengthToSkip); return createMove(from, to, NULL, 0); }
int createMoveFromString(char moveStr[], int fromType, int capture, int moveType2){ assert(isMoveString(moveStr)); char fromSquare[3], toSquare[3]; fromSquare[0]= moveStr[0]; fromSquare[1]= moveStr[1]; fromSquare[2]= '\0'; toSquare[0]= moveStr[2]; toSquare[1]= moveStr[3]; toSquare[2]= '\0'; int fromIndex=getIndexFromSquare(fromSquare); int toIndex= getIndexFromSquare(toSquare); return createMove(fromType, fromIndex, toIndex, capture, moveType2, 0); }
/* * Add an available move for the player to the list of moves. * - 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). */ bool addPossibleMove(char board[BOARD_SIZE][BOARD_SIZE], LinkedList* possibleMoves, bool isMovesForBlackPlayer, Position* startPos, int targetX, int targetY, Position* kingPos) { // Check if the move doesn't cause the current player a check. If it does, we don't count it. if (!isValidMove(board, isMovesForBlackPlayer, startPos, targetX, targetY, kingPos)) return false; Position targetPos = { targetX, targetY }; Move* newMove = createMove(startPos, &targetPos); if (g_memError) return false; insertLast(possibleMoves, newMove); if (g_memError) { deleteMove((void*)newMove); return false; } return true; }
struct Moves* KingMoves(int x, int y, char some_board[BOARD_SIZE][BOARD_SIZE]){ struct Moves* moves = calloc(1, sizeof(struct Moves)); movesLeaks++; struct Move* move; if (isWhite(some_board[x][y])){ // white king eats piece ( or moves to an empty spot ) if (x + 1 <= 7){ if (y + 1 <= 7 && (isBlack(some_board[x + 1][y + 1]) || some_board[x + 1][y + 1] == EMPTY)){ move = createMove(x, y, x + 1, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (isBlack(some_board[x + 1][y]) || some_board[x + 1][y] == EMPTY){ move = createMove(x, y, x + 1, y, some_board, NULL); addMoveToMovesList(move, moves); } if (y - 1 >= 0 && (isBlack(some_board[x + 1][y - 1]) || some_board[x + 1][y - 1] == EMPTY)){ move = createMove(x, y, x + 1, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } } if (y - 1 >= 0 && (isBlack(some_board[x][y - 1]) || some_board[x][y - 1] == EMPTY)){ move = createMove(x, y, x, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } if (y + 1 <= 7 && (isBlack(some_board[x][y + 1]) || some_board[x][y + 1] == EMPTY)){ move = createMove(x, y, x, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (x - 1 >= 0){ if (y + 1 <= 7 && (isBlack(some_board[x - 1][y + 1]) || some_board[x - 1][y + 1] == EMPTY)){ move = createMove(x, y, x - 1, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (isBlack(some_board[x - 1][y]) || some_board[x - 1][y] == EMPTY){ move = createMove(x, y, x - 1, y, some_board, NULL); addMoveToMovesList(move, moves); } if (y - 1 >= 0 && (isBlack(some_board[x - 1][y - 1]) || some_board[x - 1][y - 1] == EMPTY)){ move = createMove(x, y, x - 1, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } } } else{ // black king eats piece ( or moves to an empty spot ) if (x + 1 <= 7){ if (y + 1 <= 7 && (isWhite(some_board[x + 1][y + 1]) || some_board[x + 1][y + 1] == EMPTY)){ move = createMove(x, y, x + 1, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (isWhite(some_board[x + 1][y]) || some_board[x + 1][y] == EMPTY){ move = createMove(x, y, x + 1, y, some_board, NULL); addMoveToMovesList(move, moves); } if (y - 1 >= 0 && (isWhite(some_board[x + 1][y - 1]) || some_board[x + 1][y - 1] == EMPTY)){ move = createMove(x, y, x + 1, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } } if (y - 1 >= 0 && (isWhite(some_board[x][y - 1]) || some_board[x][y - 1] == EMPTY)){ move = createMove(x, y, x, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } if (y + 1 <= 7 && (isWhite(some_board[x][y + 1]) || some_board[x][y + 1] == EMPTY)){ move = createMove(x, y, x, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (x - 1 >= 0){ if (y + 1 <= 7 && (isWhite(some_board[x - 1][y + 1]) || some_board[x - 1][y + 1] == EMPTY)){ move = createMove(x, y, x - 1, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } if (isWhite(some_board[x - 1][y]) || some_board[x - 1][y] == EMPTY){ move = createMove(x, y, x - 1, y, some_board, NULL); addMoveToMovesList(move, moves); } if (y - 1 >= 0 && (isWhite(some_board[x - 1][y - 1]) || some_board[x - 1][y - 1] == EMPTY)){ move = createMove(x, y, x - 1, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } } } return moves; }
struct Moves* KnightMoves(int x, int y, char some_board[BOARD_SIZE][BOARD_SIZE]){ struct Moves* moves = calloc(1, sizeof(struct Moves)); movesLeaks++; struct Move* move; if (isWhite(some_board[x][y])){ // knight piece is white if (x - 2 >= 0){ if (y - 1 >= 0 && (isBlack(some_board[x - 2][y - 1]) || some_board[x - 2][y - 1] == EMPTY)){ move = createMove(x, y, x - 2, y - 1, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } if (y + 1 <= 7 && (isBlack(some_board[x - 2][y + 1]) || some_board[x - 2][y + 1] == EMPTY)){ move = createMove(x, y, x - 2, y + 1, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } } if (x +2 <= 7){ if (y - 1 >= 0 && (isBlack(some_board[x + 2][y - 1]) || some_board[x - 2][y - 1] == EMPTY)){ move = createMove(x, y, x + 2, y - 1, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } if (y + 1 <= 7 && (isBlack(some_board[x + 2][y + 1]) || some_board[x - 2][y + 1] == EMPTY)){ move = createMove(x, y, x + 2, y + 1, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } } if (y + 2 <= 7){ if (x - 1 >= 0 && (isBlack(some_board[x - 1][y + 2]) || some_board[x - 1][y + 2] == EMPTY)){ move = createMove(x, y, x - 1, y + 2, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } if (x + 1 <= 7 && (isBlack(some_board[x + 1][y + 2]) || some_board[x + 1][y + 2] == EMPTY)){ move = createMove(x, y, x + 1, y + 2, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } } if (y - 2 >=0){ if (x - 1 >= 0 && (isBlack(some_board[x - 1][y - 2]) || some_board[x - 1][y - 2] == EMPTY)){ move = createMove(x, y, x - 1, y - 2, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } if (x + 1 <= 7 && (isBlack(some_board[x + 1][y - 2]) || some_board[x + 1][y - 2] == EMPTY)){ move = createMove(x, y, x + 1, y - 2, some_board, NULL); addMoveToMovesList(move, moves); free(move); moveLeaks--; } } } else{ // knight piece is black if (x - 2 >= 0){ if (y - 1 >= 0 && (isWhite(some_board[x - 2][y - 1]) || some_board[x - 2][y - 1] == EMPTY)){ move = createMove(x, y, x - 2, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } if (y + 1 <= 7 && (isWhite(some_board[x - 2][y + 1]) || some_board[x - 2][y + 1] == EMPTY)){ move = createMove(x, y, x - 2, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } } if (x + 2 <= 7){ if (y - 1 >= 0 && (isWhite(some_board[x + 2][y - 1]) || some_board[x - 2][y - 1] == EMPTY)){ move = createMove(x, y, x + 2, y - 1, some_board, NULL); addMoveToMovesList(move, moves); } if (y + 1 <= 7 && (isWhite(some_board[x + 2][y + 1]) || some_board[x - 2][y + 1] == EMPTY)){ move = createMove(x, y, x + 2, y + 1, some_board, NULL); addMoveToMovesList(move, moves); } } if (y + 2 <= 7){ if (x - 1 >= 0 && (isWhite(some_board[x - 1][y + 2]) || some_board[x - 1][y + 2] == EMPTY)){ move = createMove(x, y, x - 1, y + 2, some_board, NULL); addMoveToMovesList(move, moves); } if (x + 1 <= 7 && (isWhite(some_board[x + 1][y + 2]) || some_board[x + 1][y + 2] == EMPTY)){ move = createMove(x, y, x + 1, y + 2, some_board, NULL); addMoveToMovesList(move, moves); } } if (y - 2 >= 0){ if (x - 1 >= 0 && (isWhite(some_board[x - 1][y - 2]) || some_board[x - 1][y - 2] == EMPTY)){ move = createMove(x, y, x - 1, y - 2, some_board, NULL); addMoveToMovesList(move, moves); } if (x + 1 <= 7 && (isWhite(some_board[x + 1][y - 2]) || some_board[x + 1][y - 2] == EMPTY)){ move = createMove(x, y, x + 1, y - 2, some_board, NULL); addMoveToMovesList(move, moves); } } } return moves; }
struct Moves* RookMoves(int x, int y, char some_board[BOARD_SIZE][BOARD_SIZE]){ struct Moves* moves = calloc(1, sizeof(struct Moves)); movesLeaks++; struct Move* move; int i, j; // check if can eat up i = x; j = y + 1; while (j <= 7){ if (some_board[i][j] != EMPTY) break; else{ move = createMove(x, y, i, j, some_board, NULL); // add step to an empty spot on board addMoveToMovesList(move, moves); } j++; } if (isWhite(some_board[x][y]) && j <= 7 && isBlack(some_board[i][j])){ // white rook eats black piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } else{ if (isBlack(some_board[x][y]) && j <= 7 && isWhite(some_board[i][j])){ // black rook eats white piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } } // check if can eat right i = x +1; j = y; while (i<=7){ if (some_board[i][j] != EMPTY) break; else{ move = createMove(x, y, i, j, some_board, NULL); // add step to an empty spot on board addMoveToMovesList(move, moves); } i++; } if (isWhite(some_board[x][y]) && i <= 7&& isBlack(some_board[i][j])){ // white rook eats black piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } else{ if (isBlack(some_board[x][y]) && i <= 7 && isWhite(some_board[i][j])){ // black rook eats white piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } } //check if can eat down i = x; j = y - 1; while (j >= 0){ if (some_board[i][j] != EMPTY) break; else{ move = createMove(x, y, i, j, some_board, NULL); // add step to an empty spot on board addMoveToMovesList(move, moves); } j--; } if (isWhite(some_board[x][y]) && j >= 0 && isBlack(some_board[i][j])){ // white rook eats black piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } else{ if (isBlack(some_board[x][y]) && j >= 0 && isWhite(some_board[i][j])){ // black rook eats white piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } } // check if can eat left i = x - 1; j = y; while (i >=0 ){ if (some_board[i][j] != EMPTY) break; else{ move = createMove(x, y, i, j, some_board, NULL); // add step to an empty spot on board addMoveToMovesList(move, moves); } i--; } if (isWhite(some_board[x][y]) && i >= 0 && isBlack(some_board[i][j])){ // white Bishop eats black piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } else{ if (isBlack(some_board[x][y]) && i >= 0 && isWhite(some_board[i][j])){ // black bishop eats white piece move = createMove(x, y, i, j, some_board, NULL); addMoveToMovesList(move, moves); } } return moves; }
struct Moves* PawnMoves(int x, int y, char some_board[BOARD_SIZE][BOARD_SIZE]){ struct Moves* moves = calloc(1,sizeof(struct Moves)); movesLeaks++; struct Move* move; int isPromoted = 0; if (isWhite(some_board[x][y])){ if (y + 1 == 7) isPromoted = 1; // promote the pawn if (y + 1 <= 7 && some_board[x][y + 1] == EMPTY) // if you can move to an empty spot that is in the board if (isPromoted){ move = createMove(x, y, x, y + 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x, y + 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x, y + 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x, y + 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x, y + 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } if (y + 1 <= 7 && x - 1 >= 0 && isBlack(some_board[x-1][y+1])){ // can move diagonal only if can eat a black piece if (isPromoted){ move = createMove(x, y, x - 1, y + 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y + 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y + 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y + 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x - 1, y + 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } } if (y + 1 <= 7 && x + 1 <= 7 && isBlack(some_board[x+1][y+1])){ if (isPromoted){ move = createMove(x, y, x + 1, y + 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y + 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y + 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y + 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x + 1, y + 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } } } else{ // color is black if (y - 1 == 0) isPromoted = 1; // promote the pawn if (y - 1 >= 0 && some_board[x][y - 1] == EMPTY) // if you can move to an empty spot that is in the board if (isPromoted){ move = createMove(x, y, x, y - 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x, y - 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x, y - 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x, y - 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x, y - 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } if (y - 1 >=0 && x - 1 >= 0 && isWhite(some_board[x - 1][y - 1])){ // can move diagonal only if can eat a black piece if (isPromoted){ move = createMove(x, y, x - 1, y - 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y - 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y - 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x - 1, y - 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x - 1, y - 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } } if (y - 1 >= 0 && x + 1 <= 7 && isWhite(some_board[x + 1][y - 1])){ if (isPromoted){ move = createMove(x, y, x + 1, y - 1, some_board, W_ROOK); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y - 1, some_board, W_KNIGHT); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y - 1, some_board, W_QUEEN); addMoveToMovesList(move, moves); move = createMove(x, y, x + 1, y - 1, some_board, W_BISHOP); addMoveToMovesList(move, moves); } else{ move = createMove(x, y, x + 1, y - 1, some_board, NULL); // Move with no promotion addMoveToMovesList(move, moves); } } } return moves; }
Move* copyMove(Move* move) { return createMove(move->from, copyPositionList(move->to), copyPositionList(move->eatenAt), move->eatCount); }