From 238c66d7a68c23caed14884797f488aca9315a76 Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Sun, 3 Dec 2023 18:10:07 +0300 Subject: [PATCH] feat: notation_move_from_string; feat: actually keep track of who makes the move; bugfix: convert char to int the right way --- TODO | 5 +-- src/algebraic_notation.c | 76 +++++++++++++++++++++++++++++++++------- src/algebraic_notation.h | 16 +++++++++ src/board.c | 71 +++++++++++++++++++++---------------- src/board.h | 26 +++++++++----- src/chess.c | 29 ++++++++++++--- src/chess.h | 2 ++ 7 files changed, 167 insertions(+), 58 deletions(-) diff --git a/TODO b/TODO index d15e498..d1838c6 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,3 @@ -1. Algebraic notation: notation_move_from_string, notation_move_to_string, documentation -2. Board: board_is_move_legal, add other piece's moves \ No newline at end of file +1. Algebraic notation: notation_move_to_string, documentation +2. Board: board_is_move_legal, add other piece's moves +3. Chess: output special error message for each type of illegal move so it's clear what went wrong \ No newline at end of file diff --git a/src/algebraic_notation.c b/src/algebraic_notation.c index cb563ca..8f8eca3 100644 --- a/src/algebraic_notation.c +++ b/src/algebraic_notation.c @@ -17,6 +17,7 @@ along with this program. If not, see . */ +#include #include #include #include @@ -28,42 +29,43 @@ Position notation_tile_to_position(TileNotation notation) { Position pos; switch (notation.file) { case 'a': { - pos.column = 1; + pos.column = 0; break; } case 'b': { - pos.column = 2; + pos.column = 1; break; } case 'c': { - pos.column = 3; + pos.column = 2; break; } case 'd': { - pos.column = 4; + pos.column = 3; break; } case 'e': { - pos.column = 5; + pos.column = 4; break; } case 'f': { - pos.column = 6; + pos.column = 5; break; } case 'g': { - pos.column = 7; + pos.column = 6; break; } case 'h': { - pos.column = 8; + pos.column = 7; break; } default: { break; } } - pos.row = notation.rank; + // pos.row = notation.rank - 1; + pos.row = (8 - (notation.rank)); return pos; } @@ -101,7 +103,7 @@ TileNotation notation_tile_from_string(const char* tile_string) { TileNotation tile; tile.file = tile_string[0]; - tile.rank = (unsigned int) tile_string[1]; + tile.rank = (unsigned int) (tile_string[1] - '0'); // Convert to proper int return tile; } @@ -239,6 +241,28 @@ int notation_is_piece_char(char character) { } +/* +Returns a piece deduced from character, returns NONE piece if couldn't deduce a piece type. +Big characters are for WHITE pieces, small for BLACK pieces. +*/ +Piece notation_piece_from_char(char character) { + if (character == 'K') return piece_new(WHITE, KING); + else if (character == 'k') return piece_new(BLACK, KING); + else if (character == 'R') return piece_new(WHITE, ROOK); + else if (character == 'r') return piece_new(BLACK, ROOK); + else if (character == 'B') return piece_new(WHITE, BISHOP); + else if (character == 'b') return piece_new(BLACK, BISHOP); + else if (character == 'N') return piece_new(WHITE, KNIGHT); + else if (character == 'n') return piece_new(BLACK, KNIGHT); + else if (character == 'P') return piece_new(WHITE, PAWN); + else if (character == 'p') return piece_new(BLACK, PAWN); + else if (character == 'Q') return piece_new(WHITE, QUEEN); + else if (character == 'q') return piece_new(BLACK, QUEEN); + + return piece_new(WHITE, NONE); +} + + char* notation_move_to_string(MoveNotation move) { char* move_notation = (char*) malloc(sizeof(char) * 10); if (!move_notation) { @@ -302,8 +326,20 @@ char* notation_move_to_string(MoveNotation move) { } +/* +Accepts a move string which consists of an origin square, piece name +(upper case for WHITE, lower case for BLACK) and a square to move to +in algebraic notation. + +Returns a notated move with origin, target and piece values set. Move type is to be +determined by the engine. + +Returns NULL if technical errors were encountered, move_string does not contain enough information +*/ MoveNotation* notation_move_from_string(const char* move_string) { - if (!move_string) { + unsigned int len = strlen(move_string); + + if (!move_string || len < 5) { return NULL; } @@ -312,11 +348,25 @@ MoveNotation* notation_move_from_string(const char* move_string) { return NULL; } - // printf(); - if (notation_is_piece_char(move_string[0])) { + // Origin tile + TileNotation origin = notation_tile_from_string(move_string); + + // Piece + Piece piece = notation_piece_from_char(move_string[2]); + if (piece.type == NONE) { + // No piece information given + return NULL; } + // Target tile + TileNotation target = notation_tile_from_string(move_string + 3); + + move->origin = origin; + move->piece = piece; + move->target = target; + move->move_type = 0; + return move; } diff --git a/src/algebraic_notation.h b/src/algebraic_notation.h index 165c0ba..bb7ae58 100644 --- a/src/algebraic_notation.h +++ b/src/algebraic_notation.h @@ -59,6 +59,12 @@ char notation_piece_to_char(Piece piece); // Returns 1 if character is one of the piece characters, 0 otherwise int notation_is_piece_char(char character); +/* +Returns a piece deduced from character, returns NONE piece if couldn't deduce a piece type. +Big characters are for WHITE pieces, small for BLACK pieces. +*/ +Piece notation_piece_from_char(char character); + typedef struct MoveNotation { Piece piece; @@ -71,6 +77,16 @@ typedef struct MoveNotation { char* notation_move_to_string(MoveNotation move); +/* +Accepts a move string which consists of an origin square, piece name +(upper case for WHITE, lower case for BLACK) and a square to move to +in algebraic notation. + +Returns a notated move with origin, target and piece values set. Move type is to be +determined by the engine. + +Returns NULL if technical errors were encountered, move_string does not contain enough information +*/ MoveNotation* notation_move_from_string(const char* move_string); diff --git a/src/board.c b/src/board.c index a7146ba..04c6f18 100644 --- a/src/board.c +++ b/src/board.c @@ -471,26 +471,41 @@ Position* board_get_rook_moves(const Board* board, const Tile* rook_tile, unsign /* -Checks if a move is legal on this board. +Checks if a move is legal or not (and reason) on this board. -Returns 1 - if the move is legal, 0 - otherwise +Returns MoveLegality */ -int board_is_move_legal(const Board* board, Move move) { +MoveLegality board_is_move_legal(const Board* board, Move move, Color color_plays) { // Check if the tiles are not out of bounds if (!board_is_tile_in_bounds(board, move.origin) || !board_is_tile_in_bounds(board, move.target) ) { - return 0; + return ILLOUTOFBOUNDS; } // Check if there is a piece at all if (board_get_tile(board, move.origin)->piece.type == NONE) { - return 0; + return ILLNOPIECE; } Tile* origin_tile = board_get_tile(board, move.origin); Tile* target_tile = board_get_tile(board, move.target); + + // Check if the piece is of the player's color + if (origin_tile->piece.color != color_plays) { + return ILLNOTYOURPIECE; + } + + // See if the target tile is of the allied color + if (tile_is_occupied(*target_tile)) { + // The tile is occupied + if (target_tile->piece.color == color_plays) { + // The pieces are allied, can't go there! + return ILLSAMECOLOR; + } + } + // Check based on the piece type Piece origin_piece = origin_tile->piece; @@ -498,23 +513,14 @@ int board_is_move_legal(const Board* board, Move move) { case KING: { if (position_distance(move.origin, move.target) > 1) { // Too far away - return 0; + return ILLINVALIDPIECEMOVEMENT; } - // See if the target tile is occupied or not - if (tile_is_occupied(*target_tile)) { - // The tile is occupied - if (target_tile->piece.color == origin_piece.color) { - // The pieces are allied, can't go there - return 0; - } - } - - return 1; + return LEGAL; } case QUEEN: { - return 1; + return LEGAL; } case ROOK: { @@ -532,49 +538,54 @@ int board_is_move_legal(const Board* board, Move move) { { // This position is allowed to be moved to free(legal_positions); - return 1; + return LEGAL; } } free(legal_positions); - return 0; + return LEGAL; } case KNIGHT: { - return 1; + return LEGAL; } case BISHOP: { - return 1; + return LEGAL; } case PAWN: { - return 1; + return LEGAL; } default: { // Non reachable - return 0; + return LEGAL; } } } /* -Moves piece from one place to other, -checking whether it is a legal move or not. +Moves piece from one place to other, does not +check if move is legal or not. -Returns 1 if a move has been successfully done, -0 - if it is an illegal move +Returns 1 if move has been successfully done, 0 - otherwise */ -int board_process_move(Board* board, Move move) { - if (!board_is_move_legal(board, move)) { +int board_make_move(Board* board, Move move) { + if (!board) { return 0; } - // The tiles are legal, no need to re-check Tile* tile_origin = board_get_tile(board, move.origin); + if (!tile_origin) { + return 0; + } + Tile* tile_target = board_get_tile(board, move.target); + if (!tile_target) { + return 0; + } // Move the piece from one tile to another tile_target->piece = tile_origin->piece; diff --git a/src/board.h b/src/board.h index f173262..f9ba6f8 100644 --- a/src/board.h +++ b/src/board.h @@ -123,21 +123,31 @@ Position* board_get_king_moves(const Board* board, const Tile* king_tile, unsign Position* board_get_rook_moves(const Board* board, const Tile* rook_tile, unsigned int* pos_count); +// Move legality status +typedef enum MoveLegality { + LEGAL, + ILLSAMECOLOR, + ILLINVALIDPIECEMOVEMENT, + ILLOUTOFBOUNDS, + ILLNOPIECE, + ILLNOTYOURPIECE +} MoveLegality; + + /* -Checks if a move is legal on this board. +Checks if a move is legal or not (and reason) on this board. -Returns 1 - if the move is legal, 0 - otherwise +Returns MoveLegality */ -int board_is_move_legal(const Board* board, Move move); +MoveLegality board_is_move_legal(const Board* board, Move move, Color color_plays); /* -Moves piece from one place to other, -checking whether it is a legal move or not. +Moves piece from one place to other, does not +check if move is legal or not. -Returns 1 if a move has been successfully done, -0 - if it is an illegal move +Returns 1 if move has been successfully done, 0 - otherwise */ -int board_process_move(Board* board, Move move); +int board_make_move(Board* board, Move move); #endif \ No newline at end of file diff --git a/src/chess.c b/src/chess.c index 594309d..32b5c5d 100644 --- a/src/chess.c +++ b/src/chess.c @@ -37,6 +37,11 @@ Chess* chess_new(Options options) { game->turn = WHITE; game->state = READY; game->options = options; + if (options.play_as_white == 1) { + game->plays_as = WHITE; + } else { + game->plays_as = BLACK; + } return game; } @@ -129,23 +134,37 @@ void chess_next_turn(Chess* chess) { // Keep asking for a legitimate move Move* move = NULL; - int result = 0; + MoveLegality result = 0; while (1) { // Get a move move = chess_take_move_input(chess); if (!move) { - printf("Invalid move input!\n"); + printf("Invalid move input! (opt, where o - origin tile, p - piece, t - target tile: a2Pa4 moves white pawn at a2 to a4)\n"); continue; } - // Make a move - result = board_process_move(chess->board, *move); - if (!result) { + printf("(%d %d) --- (%d %d)\n", move->origin.row, move->origin.column, move->target.row, move->target.column); + + + // Check if it's a valid move + result = board_is_move_legal(chess->board, *move, chess->turn); + if (result != LEGAL) { + // TODO: output special message for each illegal move + printf("Illegal move!\n"); free(move); continue; } + + // Make a move! + int move_made = board_make_move(chess->board, *move); + if (!move_made) { + printf("Failed to make a move!\n"); // Should not be reacheable + free(move); + continue; + } + break; } free(move); diff --git a/src/chess.h b/src/chess.h index 2d406c9..9703ceb 100644 --- a/src/chess.h +++ b/src/chess.h @@ -37,12 +37,14 @@ typedef struct Options { FILE* input; FILE* output; int use_ansi; + int play_as_white; } Options; typedef struct Chess { Board* board; Color turn; + Color plays_as; unsigned int moves_made; unsigned int timer_white_ms; unsigned int timer_black_ms;