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;