#include #include #include #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" #define ANSI_COLOR_BLUE "\x1b[34m" #define ANSI_COLOR_MAGENTA "\x1b[35m" #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m" typedef enum { pawn = 1, knight = 2, bishop = 3, rook = 4, queen = 5, king = 6, } piece_t; typedef struct Vector { int mx; int my; } vector_t; vector_t init_vector(int mx, int my) { vector_t vector; vector.mx = mx; vector.my = my; return vector; } typedef struct VectorP { vector_t* vectors; int length; } vectorp_t; vectorp_t init_vectorp(vector_t* vectors, int length) { vectorp_t vectorP; vectorP.vectors = vectors; vectorP.length = length; return vectorP; } void draw_board(int board[8][8]) { printf(" A B C D E F G H\n"); int tileColor = 1; for(int r = 0; r < 8; r++) { tileColor = !tileColor; char* line = calloc(2 + (8 * 10), sizeof(char)); line[0] = '8' - r; line[1] = ' '; for(int c = 0; c < 8; c++) { tileColor = !tileColor; strcat(line, tileColor == 0 ? ANSI_COLOR_RED : ANSI_COLOR_RESET); if(board[c][r] <= 6) { switch(board[c][r]) { case 0: strcat(line, "# "); break; case pawn: strcat(line, "P "); break; case knight: strcat(line, "N "); break; case bishop: strcat(line, "B "); break; case rook: strcat(line, "R "); break; case queen: strcat(line, "Q "); break; case king: strcat(line, "K "); break; } } else { switch(board[c][r] - 6) { case pawn: strcat(line, "p "); break; case knight: strcat(line, "n "); break; case bishop: strcat(line, "b "); break; case rook: strcat(line, "r "); break; case queen: strcat(line, "q "); break; case king: strcat(line, "k "); break; } } } printf(line); printf("\n" ANSI_COLOR_RESET); free(line); } } int in_board(vector_t position) { return position.mx < 8 && position.mx >= 0 && position.my < 8 && position.my >= 0; } int is_empty(int board[8][8], vector_t position) { return board[position.mx][position.my] == 0; } int is_color(int board[8][8], vector_t position, int color) { if(color == 0) { return board[position.mx][position.my] >= 1 && board[position.mx][position.my] <= 6; } else { return board[position.mx][position.my] >= 7; } } vectorp_t get_pawn_moves(int board[8][8], vector_t position, int color) { vector_t* moves = malloc(6 * sizeof(vector_t)); int moveCount = 0; int forwardDir = (color == 0 ? -1 : 1); vector_t move1 = init_vector(position.mx, position.my + forwardDir); if(in_board(move1) && is_empty(board, move1)) { moves[moveCount] = move1; moveCount++; if(position.my == (color == 0 ? 6 : 1)) { vector_t move2 = init_vector(position.mx, position.my + (forwardDir * 2)); if(is_empty(board, move2)) { moves[moveCount] = move2; moveCount++; } } } vector_t captureL = init_vector(position.mx - 1, position.my + forwardDir); if(in_board(captureL) && is_color(board, captureL, !color)) { moves[moveCount] = captureL; moveCount++; } vector_t captureR = init_vector(position.mx + 1, position.my + forwardDir); if(in_board(captureR) && is_color(board, captureR, !color)) { moves[moveCount] = captureR; moveCount++; } return init_vectorp(moves, moveCount); } vectorp_t get_knight_moves(int board[8][8], vector_t position, int color) { vector_t* moves = malloc(8 * sizeof(vector_t)); int moveCount = 0; for(int i = 0; i < 8; i++) { int h = ((i == 0 || i == 1) ? 2 : (i == 2 || i == 3) ? -2 : (i == 4 || i == 5) ? 1 : -1); int v = ((i == 0 || i == 2) ? -1 : (i == 1 || i == 3) ? 1 : (i == 4 || i == 6) ? 2 : -2); vector_t move = init_vector(position.mx + h, position.my + v); if(in_board(move) && (is_empty(board, move) || is_color(board, move, !color))) { moves[moveCount] = move; moveCount++; } } return init_vectorp(moves, moveCount); } vectorp_t get_bishop_moves(int board[8][8], vector_t position, int color) { vector_t* moves = malloc(14 * sizeof(vector_t)); int moveCount = 0; for(int i = 0; i < 4; i++) { int h = i < 2 ? 1 : -1; int v = (i == 0 || i == 2) ? 1 : -1; vector_t checkPos = init_vector(position.mx, position.my); for(int d = 0; d < 7; d++) { checkPos.mx += h; checkPos.my += v; if(in_board(checkPos)) { if(is_empty(board, checkPos)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; } else if(is_color(board, checkPos, !color)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; break; } else { break; } } else { break; } } } return init_vectorp(moves, moveCount); } vectorp_t get_rook_moves(int board[8][8], vector_t position, int color) { vector_t* moves = malloc(14 * sizeof(vector_t)); int moveCount = 0; for(int i = 0; i < 4; i++) { int h = (i == 0 || i == 2) ? 0 : i == 1 ? 1 : -1; int v = (i == 1 || i == 3) ? 0 : i == 2 ? 1 : -1; vector_t checkPos = init_vector(position.mx, position.my); for(int d = 0; d < 7; d++) { checkPos.mx += h; checkPos.my += v; if(in_board(checkPos)) { if(is_empty(board, checkPos)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; } else if(is_color(board, checkPos, !color)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; break; } else { break; } } else { break; } } } return init_vectorp(moves, moveCount); } vectorp_t get_queen_moves(int board[8][8], vector_t position, int color) { vector_t* moves = malloc(28 * sizeof(vector_t)); int moveCount = 0; for(int i = 0; i < 8; i++) { int h; int v; //diagonal moves if(i < 4) { h = i < 2 ? 1 : -1; v = (i == 0 || i == 2) ? 1 : -1; } //straight moves else { h = (i == 4 || i == 6) ? 0 : i == 5 ? 1 : -1; v = (i == 5 || i == 7) ? 0 : i == 6 ? 1 : -1; } vector_t checkPos = init_vector(position.mx, position.my); for(int d = 0; d < 7; d++) { checkPos.mx += h; checkPos.my += v; if(in_board(checkPos)) { if(is_empty(board, checkPos)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; } else if(is_color(board, checkPos, !color)) { moves[moveCount] = init_vector(checkPos.mx, checkPos.my); moveCount++; break; } else { break; } } else { break; } } } return init_vectorp(moves, moveCount); } vectorp_t get_moves(int board[8][8], 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); } } vector_t user_input_pos() { char* inputString = malloc(3 * sizeof(char)); vector_t pos; printf("Enter coordinates: "); scanf("%2s", inputString); for(int i = 0; i < 2; i++) { if(inputString[i] <= '9' && inputString[i] >= '0') { pos.my = 8 - (inputString[i] - '0'); } else if(inputString[i] <= 'Z' && inputString[i] >= 'A') { pos.mx = inputString[i] - 'A'; } else if(inputString[i] <= 'z' && inputString[i] >= 'a') { pos.mx = inputString[i] - 'a'; } else { return init_vector(-1, -1); } } free(inputString); return pos; } //converts board coordinates into algebraic notation char* get_readable_coords(vector_t position) { char* output = malloc(3 * sizeof(char)); output[0] = 'a' + position.mx; output[1] = '8' - position.my; output[2] = '\0'; return output; } //gets the proper algebraic notation for the move char* get_move_name(int board[8][8], vector_t origin, vector_t end) { int piece = board[origin.mx][origin.my]; if(piece > 6) { piece -= 6; } if(piece != 1) { char cPiece = piece == pawn ? 'P' : piece == knight ? 'N' : piece == bishop ? 'B' : piece == rook ? 'R' : piece == queen ? 'Q' : 'K'; int isCapture = board[end.mx][end.my] != 0; char* output = calloc(isCapture ? 5 : 4, sizeof(char)); output[0] = cPiece; if(isCapture) { output[1] = 'x'; } char* rEnd = get_readable_coords(end); strcat(output, rEnd); free(rEnd); output[isCapture ? 4 : 3] = '\0'; return output; } else { int isCapture = board[end.mx][end.my] != 0; char* output = calloc(isCapture ? 5 : 3, sizeof(char)); if(isCapture) { output[0] = 'a' + origin.mx; output[1] = 'x'; } char* rEnd = get_readable_coords(end); strcat(output, rEnd); free(rEnd); output[isCapture ? 4 : 2] = '\0'; return output; } } void clear_screen() { system("@cls||clear"); } void warn_user(char* message) { clear_screen(); printf("\n"); printf(message); printf("\nPress any key to continue...\n"); while(getchar() != '\n'); getchar(); } int main() { int board[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 } }; int turn = 0; while(1) { //draw the board, write some info clear_screen(); draw_board(board); printf(turn == 0 ? "\nWhite's turn\n" : "\nBlack's turn\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[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(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[selection.mx][selection.my] = 0; board[target.mx][target.my] = selectedPiece; printf("\n"); turn = !turn; } return 0; }