diff options
| -rw-r--r-- | chess.c | 394 | ||||
| -rw-r--r-- | chess.h | 17 | ||||
| -rw-r--r-- | chesshelpers.c | 47 | ||||
| -rw-r--r-- | chesshelpers.h | 8 |
4 files changed, 283 insertions, 183 deletions
@@ -4,7 +4,186 @@ #include "vector.h" #include "console.h" #include "chesshelpers.h" +#include "chess.h" +int main() { + //set up the board + int boardA[8][8] = { + { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook }, + { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight }, + { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop }, + { queen + 6, pawn + 6, 0, 0, 0, 0, pawn, queen }, + { king + 6, pawn + 6, 0, 0, 0, 0, pawn, king }, + { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop }, + { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight }, + { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook } + }; + //convert the array to pointers + int** pieces = malloc(8 * sizeof(int*)); + for(int r = 0; r < 8; r++) { + pieces[r] = malloc(8 * sizeof(int)); + for(int c = 0; c < 8; c++) { + pieces[r][c] = boardA[r][c]; + } + } + board_t board = init_board(pieces); + int turn = 0; + while(1) { + //draw the board, write some info + clear_screen(); + draw_board(board.pieces); + printf(turn == 0 ? "\nWhite's turn\n" : "\nBlack's turn\n"); + if(is_in_check(board, turn)) { + printf("You're in check!\n"); + } + printf("Enter the coordinates of the piece you want to move\n"); + //get the selection for the piece to be moved + vector_t selection = user_input_pos(); + int selectedPiece = board.pieces[selection.mx][selection.my]; + //check if the piece is of the right colour, and that there is a piece there + if(selectedPiece == 0 || (selectedPiece > 6 && turn == 0) || (selectedPiece <= 6 && turn == 1)) { + warn_user("Invalid selection!"); + continue; + } + printf("Selected piece: "); + printf("%d", selectedPiece); + printf("\n"); + vectorp_t moves = get_moves_final(board, selection, selectedPiece); + if(moves.length == 0) { + warn_user("That piece has no valid moves!"); + continue; + } + printf("Valid moves: "); + //write all the valid moves + for(int i = 0; i < moves.length; i++) { + char* readable_coords = get_move_name(board, selection, moves.vectors[i]); + printf(readable_coords); + free(readable_coords); + printf("; "); + } + printf("\nEnter the coordinates you would like to move that piece to, or enter < to go back\n"); + //get the selection for the location to move the piece to + vector_t target = user_input_pos(); + if(target.mx == -1) { + continue; + } + //check if target is in list of valid moves + int match = 0; + for(int i = 0; i < moves.length; i++) { + if(moves.vectors[i].mx == target.mx && moves.vectors[i].my == target.my) { + match = 1; + break; + } + } + if(!match) { + warn_user("Invalid move"); + continue; + } + board = make_move(board, selection, target); + free(moves.vectors); + printf("\n"); + turn = !turn; + } + return 0; +} +//this function returns moves that will place the player in check! +vectorp_t get_moves(board_t board, vector_t position, piece_t piece) { + int color = 0; + if(piece > 6) { + color = 1; + piece -= 6; + } + if(piece == pawn) { + return get_pawn_moves(board, position, color); + } + else if(piece == knight) { + return get_knight_moves(board, position, color); + } + else if(piece == bishop) { + return get_bishop_moves(board, position, color); + } + else if(piece == rook) { + return get_rook_moves(board, position, color); + } + else if(piece == queen) { + return get_queen_moves(board, position, color); + } + else if(piece == king) { + return get_king_moves(board, position, color); + } + else { + return init_vectorp(0, 0); + } +} +//array of arrays representing all the moves each piece of color can make +//excludeKing flag prevents recursion with castling checks +vectorpp_t get_all_moves(board_t board, int color, int excludeKing) { + vectorp_t* allMoves = malloc(16 * sizeof(vectorp_t)); + int pieceCount = 0; + for(int r = 0; r < 8; r++) { + for(int c = 0; c < 8; c++) { + vector_t v = init_vector(c, r); + if(is_color(board, v, color) && (!excludeKing || (board.pieces[v.mx][v.my] != king && board.pieces[v.mx][v.my] != king + 6))) { + allMoves[pieceCount] = get_moves(board, v, board.pieces[c][r]); + pieceCount++; + } + } + } + allMoves = realloc(allMoves, pieceCount * sizeof(vectorp_t)); + return init_vectorpp(allMoves, pieceCount); +} +//returns the position of color's king +vector_t get_king_position(board_t board, int color) { + for(int r = 0; r < 8; r++) { + for(int c = 0; c < 8; c++) { + if(board.pieces[c][r] == (king + color * 6)) { + return init_vector(c, r); + } + } + } +} +//returns true if the player of color is currently in check +int is_in_check(board_t board, int color) { + int returnV = 0; + vector_t kingPos = get_king_position(board, color); + //get all the moves for the opponent + vectorpp_t allMoves = get_all_moves(board, !color, 1); + for(int i = 0; i < allMoves.length; i++) { + vectorp_t moves = allMoves.vectorps[i]; + for(int j = 0; j < moves.length; j++) { + if(moves.vectors[j].mx == kingPos.mx && moves.vectors[j].my == kingPos.my) { + returnV = 1; + } + } + free(moves.vectors); + } + free(allMoves.vectorps); + return returnV; +} +//this function removes moves that place you in check +vectorp_t get_moves_final(board_t board, vector_t position, piece_t piece) { + int color = 0; + if(piece > 6) { + color = 1; + } + vectorp_t moves = get_moves(board, position, piece); + //try making that move, see if it puts the player in check + int* invalidMoves = malloc(moves.length * sizeof(int)); + int invalidMovesCount = 0; + for(int i = 0; i < moves.length; i++) { + board_t tempBoard = make_move(clone_board(board), position, moves.vectors[i]); + if(is_in_check(tempBoard, color)) { + invalidMoves[invalidMovesCount] = i; + invalidMovesCount++; + } + free(tempBoard.pieces); + } + vectorp_t finalMoves = remove_vectors(moves, invalidMoves, invalidMovesCount); + free(invalidMoves); + free(moves.vectors); + return finalMoves; +} +//TODO: add en passant vectorp_t get_pawn_moves(board_t board, vector_t position, int color) { vector_t* moves = malloc(6 * sizeof(vector_t)); int moveCount = 0; @@ -150,9 +329,10 @@ vectorp_t get_queen_moves(board_t board, vector_t position, int color) { } return init_vectorp(moves, moveCount); } -//TODO: castling +//TODO: don't allow king to move next to opposing king vectorp_t get_king_moves(board_t board, vector_t position, int color) { - vector_t* moves = malloc(28 * sizeof(vector_t)); + //TODO: change size to 8 + vector_t* moves = malloc(20 * sizeof(vector_t)); int moveCount = 0; for(int i = 0; i < 8; i++) { int h; @@ -173,181 +353,47 @@ vectorp_t get_king_moves(board_t board, vector_t position, int color) { moveCount++; } } - return init_vectorp(moves, moveCount); -} -//this function returns moves that will place the player in check! -vectorp_t get_moves(board_t board, vector_t position, piece_t piece) { - int color = 0; - if(piece > 6) { - color = 1; - piece -= 6; - } - if(piece == pawn) { - return get_pawn_moves(board, position, color); - } - else if(piece == knight) { - return get_knight_moves(board, position, color); - } - else if(piece == bishop) { - return get_bishop_moves(board, position, color); - } - else if(piece == rook) { - return get_rook_moves(board, position, color); - } - else if(piece == queen) { - return get_queen_moves(board, position, color); - } - else if(piece == king) { - return get_king_moves(board, position, color); - } - else { - return init_vectorp(0, 0); - } -} -//array of arrays representing all the moves each piece of color can make -vectorpp_t get_all_moves(board_t board, int color) { - vectorp_t* allMoves = malloc(16 * sizeof(vectorp_t)); - int pieceCount = 0; - for(int r = 0; r < 8; r++) { - for(int c = 0; c < 8; c++) { - vector_t v = init_vector(c, r); - if(is_color(board, v, color)) { - allMoves[pieceCount] = get_moves(board, v, board.pieces[c][r]); - pieceCount++; - } - } - } - allMoves = realloc(allMoves, pieceCount * sizeof(vectorp_t)); - return init_vectorpp(allMoves, pieceCount); -} -//returns the position of color's king -vector_t get_king_position(board_t board, int color) { - for(int r = 0; r < 8; r++) { - for(int c = 0; c < 8; c++) { - if(board.pieces[c][r] == (king + color * 6)) { - return init_vector(c, r); + //castling + if(!is_in_check(board, color)) { + //kingside castling + if((color == 0 && board.whiteCanCastleKingside) || (color == 1 && board.blackCanCastleKingside)) { + //check that the squares are free + vector_t s1 = init_vector(5, color == 0 ? 7 : 0); + vector_t s2 = init_vector(6, color == 0 ? 7 : 0); + if(is_empty(board, s1) && is_empty(board, s2)) { + //check that the squares are not threatened + board_t tempBoard1 = make_move(clone_board(board), position, s1); + board_t tempBoard2 = make_move(clone_board(board), position, s2); + if(!is_in_check(tempBoard1, color) && !is_in_check(tempBoard2, color)) { + //add the move + moves[moveCount] = s2; + moveCount++; + } + free(tempBoard1.pieces); + free(tempBoard2.pieces); } } - } -} -//returns true if the player of color is currently in check -int is_in_check(board_t board, int color) { - int returnV = 0; - vector_t kingPos = get_king_position(board, color); - //get all the moves for the opponent - vectorpp_t allMoves = get_all_moves(board, !color); - for(int i = 0; i < allMoves.length; i++) { - vectorp_t moves = allMoves.vectorps[i]; - for(int j = 0; j < moves.length; j++) { - if(moves.vectors[j].mx == kingPos.mx && moves.vectors[j].my == kingPos.my) { - returnV = 1; + //queenside castling + if((color == 0 && board.whiteCanCastleQueenside) || (color == 1 && board.blackCanCastleQueenside)) { + //check that the squares are free + vector_t s1 = init_vector(3, color == 0 ? 7 : 0); + vector_t s2 = init_vector(2, color == 0 ? 7 : 0); + vector_t s3 = init_vector(1, color == 0 ? 7 : 0); + if(is_empty(board, s1) && is_empty(board, s2) && is_empty(board, s3)) { + //check that the squares are not threatened + board_t tempBoard1 = make_move(clone_board(board), position, s1); + board_t tempBoard2 = make_move(clone_board(board), position, s2); + board_t tempBoard3 = make_move(clone_board(board), position, s3); + if(!is_in_check(tempBoard1, color) && !is_in_check(tempBoard2, color) && !is_in_check(tempBoard3, color)) { + //add the move + moves[moveCount] = s3; + moveCount++; + } + free(tempBoard1.pieces); + free(tempBoard2.pieces); + free(tempBoard3.pieces); } } - free(moves.vectors); - } - free(allMoves.vectorps); - return returnV; -} -//this function removes moves that place you in check -vectorp_t get_moves_final(board_t board, vector_t position, piece_t piece) { - int color = 0; - if(piece > 6) { - color = 1; - } - vectorp_t moves = get_moves(board, position, piece); - //try making that move, see if it puts the player in check - int* invalidMoves = malloc(moves.length * sizeof(int)); - int invalidMovesCount = 0; - for(int i = 0; i < moves.length; i++) { - board_t tempBoard = make_move(clone_board(board), position, moves.vectors[i]); - if(is_in_check(tempBoard, color)) { - invalidMoves[invalidMovesCount] = i; - invalidMovesCount++; - } - free(tempBoard.pieces); - } - vectorp_t finalMoves = remove_vectors(moves, invalidMoves, invalidMovesCount); - free(invalidMoves); - free(moves.vectors); - return finalMoves; -} -int main() { - //set up the board - int boardA[8][8] = { - { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook }, - { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight }, - { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop }, - { queen + 6, pawn + 6, 0, 0, 0, 0, pawn, queen }, - { king + 6, pawn + 6, 0, 0, 0, 0, pawn, king }, - { bishop + 6, pawn + 6, 0, 0, 0, 0, pawn, bishop }, - { knight + 6, pawn + 6, 0, 0, 0, 0, pawn, knight }, - { rook + 6, pawn + 6, 0, 0, 0, 0, pawn, rook } - }; - //convert the array to pointers - int** pieces = malloc(8 * sizeof(int*)); - for(int r = 0; r < 8; r++) { - pieces[r] = malloc(8 * sizeof(int)); - for(int c = 0; c < 8; c++) { - pieces[r][c] = boardA[r][c]; - } } - board_t board = init_board(pieces); - int turn = 0; - while(1) { - //draw the board, write some info - clear_screen(); - draw_board(board.pieces); - printf(turn == 0 ? "\nWhite's turn\n" : "\nBlack's turn\n"); - if(is_in_check(board, turn)) { - printf("You're in check!\n"); - } - printf("Enter the coordinates of the piece you want to move\n"); - //get the selection for the piece to be moved - vector_t selection = user_input_pos(); - int selectedPiece = board.pieces[selection.mx][selection.my]; - //check if the piece is of the right colour, and that there is a piece there - if(selectedPiece == 0 || (selectedPiece > 6 && turn == 0) || (selectedPiece <= 6 && turn == 1)) { - warn_user("Invalid selection!"); - continue; - } - printf("Selected piece: "); - printf("%d", selectedPiece); - printf("\n"); - vectorp_t moves = get_moves_final(board, selection, selectedPiece); - if(moves.length == 0) { - warn_user("That piece has no valid moves!"); - continue; - } - printf("Valid moves: "); - //write all the valid moves - for(int i = 0; i < moves.length; i++) { - char* readable_coords = get_move_name(board, selection, moves.vectors[i]); - printf(readable_coords); - free(readable_coords); - printf("; "); - } - printf("\nEnter the coordinates you would like to move that piece to, or enter < to go back\n"); - //get the selection for the location to move the piece to - vector_t target = user_input_pos(); - if(target.mx == -1) { - continue; - } - //check if target is in list of valid moves - int match = 0; - for(int i = 0; i < moves.length; i++) { - if(moves.vectors[i].mx == target.mx && moves.vectors[i].my == target.my) { - match = 1; - break; - } - } - if(!match) { - warn_user("Invalid move"); - continue; - } - board = make_move(board, selection, target); - free(moves.vectors); - printf("\n"); - turn = !turn; - } - return 0; + return init_vectorp(moves, moveCount); } @@ -0,0 +1,17 @@ +#include "vector.h" +#include "console.h" +#include "chesshelpers.h" +#ifndef CHESS +#define CHESS +vectorp_t get_pawn_moves(board_t board, vector_t position, int color); +vectorp_t get_knight_moves(board_t board, vector_t position, int color); +vectorp_t get_bishop_moves(board_t board, vector_t position, int color); +vectorp_t get_rook_moves(board_t board, vector_t position, int color); +vectorp_t get_queen_moves(board_t board, vector_t position, int color); +vectorp_t get_king_moves(board_t board, vector_t position, int color); +vectorp_t get_moves(board_t board, vector_t position, piece_t piece); +vectorpp_t get_all_moves(board_t board, int color, int excludeKing); +vector_t get_king_position(board_t board, int color); +int is_in_check(board_t board, int color); +vectorp_t get_moves_final(board_t board, vector_t position, piece_t piece); +#endif diff --git a/chesshelpers.c b/chesshelpers.c index 1b28ed3..d0464fb 100644 --- a/chesshelpers.c +++ b/chesshelpers.c @@ -7,9 +7,11 @@ board_t init_board(int** pieces) { board_t board; board.pieces = pieces; - board.blackKingHasMoved = 0; - board.whiteKingHasMoved = 0; - board.lastPawnMove = 0; + board.whiteCanCastleKingside = 1; + board.whiteCanCastleQueenside = 1; + board.blackCanCastleKingside = 1; + board.blackCanCastleQueenside = 1; + board.lastPawnMove = -1; return board; } //function applies side effects to board values like king move state @@ -17,13 +19,44 @@ board_t make_move(board_t board, vector_t origin, vector_t end) { int piece = board.pieces[origin.mx][origin.my]; board.pieces[origin.mx][origin.my] = 0; board.pieces[end.mx][end.my] = piece; + //white king moved + if(piece == king) { + board.whiteCanCastleQueenside = 0; + board.whiteCanCastleKingside = 0; + } + //white kingside rook moved + else if(origin.mx == 7 && origin.my == 7) { + board.whiteCanCastleKingside = 0; + } + //white queenside rook moved + else if(origin.mx == 0 && origin.my == 7) { + board.whiteCanCastleQueenside = 0; + } + //black king moved + else if(piece == king + 6) { + board.blackCanCastleQueenside = 0; + board.blackCanCastleKingside = 0; + } + //black kingside rook moved + else if(origin.mx == 7 && origin.my == 0) { + board.blackCanCastleKingside = 0; + } + //black queenside rook moved + else if(origin.mx == 0 && origin.my == 0) { + board.blackCanCastleQueenside = 0; + } + //this is not an else if! lastPawnMove must be reset + if(piece == pawn || piece == pawn + 6) { + board.lastPawnMove = origin.mx; + } + else { + //en passant no longer possible + board.lastPawnMove = -1; + } return board; } board_t clone_board(board_t board) { - board_t newBoard; - newBoard.blackKingHasMoved = board.blackKingHasMoved; - newBoard.whiteKingHasMoved = board.whiteKingHasMoved; - newBoard.lastPawnMove = board.lastPawnMove; + board_t newBoard = board; int** pieces = malloc(8 * sizeof(int*)); for(int r = 0; r < 8; r++) { pieces[r] = malloc(8 * sizeof(int)); diff --git a/chesshelpers.h b/chesshelpers.h index be92ba5..b975740 100644 --- a/chesshelpers.h +++ b/chesshelpers.h @@ -11,8 +11,12 @@ typedef enum { } piece_t; typedef struct BoardState { int** pieces; - int blackKingHasMoved; - int whiteKingHasMoved; + //only falsified by moving the king or pawn + //does not consider check or empty squares + int whiteCanCastleKingside; + int whiteCanCastleQueenside; + int blackCanCastleKingside; + int blackCanCastleQueenside; int lastPawnMove; } board_t; board_t init_board(int** pieces); |
