summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chess.c394
-rw-r--r--chess.h17
-rw-r--r--chesshelpers.c47
-rw-r--r--chesshelpers.h8
4 files changed, 283 insertions, 183 deletions
diff --git a/chess.c b/chess.c
index 1abc0a6..1e2fe5f 100644
--- a/chess.c
+++ b/chess.c
@@ -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);
}
diff --git a/chess.h b/chess.h
new file mode 100644
index 0000000..1d88a6e
--- /dev/null
+++ b/chess.h
@@ -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);