Compare commits

...

2 Commits

  1. 5
      TODO
  2. 19
      src/algebraic_notation.c
  3. 12
      src/algebraic_notation.h
  4. 295
      src/board.c
  5. 38
      src/board.h

5
TODO

@ -1,3 +1,4 @@
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
2. Chess: output special error message for each type of illegal move so it's clear what went wrong
3. board_get_pawn_moves - add en passant
4. board_get_king_moves - add castling

19
src/algebraic_notation.c

@ -71,6 +71,7 @@ Position notation_tile_to_position(TileNotation notation) {
}
// Converts notated tile into its string representation
char* notation_tile_to_string(TileNotation tile) {
char* notation = (char*) malloc(sizeof(char) * 2);
if (!notation) {
@ -83,6 +84,8 @@ char* notation_tile_to_string(TileNotation tile) {
return notation;
}
// Converts notated tile into its string representation on dest
void notation_tile_to_string_cpy(TileNotation tile, char* dest) {
if (!dest) {
return;
@ -96,6 +99,7 @@ void notation_tile_to_string_cpy(TileNotation tile, char* dest) {
}
// Converts notated tile string into its corresponding structure
TileNotation notation_tile_from_string(const char* tile_string) {
if (!tile_string) {
return notation_tile_new('a', 1);
@ -109,6 +113,7 @@ TileNotation notation_tile_from_string(const char* tile_string) {
}
// Creates a new notation tile from given file and rank.
TileNotation notation_tile_new(char file, unsigned int rank) {
TileNotation tile;
tile.file = file;
@ -118,7 +123,7 @@ TileNotation notation_tile_new(char file, unsigned int rank) {
}
// Converts
// Converts position to a notated position
TileNotation notation_tile_from_pos(Position pos) {
TileNotation tile;
switch (pos.row) {
@ -263,6 +268,7 @@ Piece notation_piece_from_char(char character) {
}
// Converts notated move into its string representation
char* notation_move_to_string(MoveNotation move) {
char* move_notation = (char*) malloc(sizeof(char) * 10);
if (!move_notation) {
@ -371,7 +377,16 @@ MoveNotation* notation_move_from_string(const char* move_string) {
}
MoveNotation notation_move_new(Piece piece, TileNotation origin, TileNotation target, int move_type);
// Creates a new move notation from provided arguments
MoveNotation notation_move_new(Piece piece, TileNotation origin, TileNotation target, int move_type) {
MoveNotation move_new;
move_new.piece = piece;
move_new.origin = origin;
move_new.target = target;
move_new.move_type = move_type;
return move_new;
}
// Converts move notation to a move

12
src/algebraic_notation.h

@ -26,6 +26,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "move.h"
// A notated tile representation
typedef struct TileNotation {
char file;
unsigned int rank;
@ -36,19 +37,23 @@ typedef struct TileNotation {
Position notation_tile_to_position(TileNotation notation);
// Converts notated tile into its string representation
char* notation_tile_to_string(TileNotation tile);
// Converts notated tile into its string representation on dest
void notation_tile_to_string_cpy(TileNotation tile, char* dest);
// Converts notated tile string into its corresponding structure
TileNotation notation_tile_from_string(const char* tile_string);
// Creates a new notation tile from given file and rank.
TileNotation notation_tile_new(char file, unsigned int rank);
// Converts
// Converts position to a notated position
TileNotation notation_tile_from_pos(Position pos);
@ -66,6 +71,7 @@ Big characters are for WHITE pieces, small for BLACK pieces.
Piece notation_piece_from_char(char character);
// A notated move representation
typedef struct MoveNotation {
Piece piece;
TileNotation origin;
@ -74,6 +80,7 @@ typedef struct MoveNotation {
} MoveNotation;
// Converts notated move into its string representation
char* notation_move_to_string(MoveNotation move);
@ -90,6 +97,9 @@ Returns NULL if technical errors were encountered, move_string does not contain
MoveNotation* notation_move_from_string(const char* move_string);
/*
Creates a new move notation from provided arguments
*/
MoveNotation notation_move_new(Piece piece, TileNotation origin, TileNotation target, int move_type);

295
src/board.c

@ -322,11 +322,11 @@ int board_is_tile_occupied(const Board* board, Position pos) {
/*
Returns all possible legal positions either in diagonal or in straight lines
Returns all possible legal positions in diagonal, in straight lines, in both as well as knight-type for specified tile.
If mode is 0 - returns positions in straight lines, 1 - in diagonals, 2 - in both
Returns NULL in case of an error
*/
Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode, unsigned int* pos_count) {
Position* board_get_positions(const Board* board, const Tile* piece_tile, MoveMode mode, unsigned int* pos_count) {
if (!board || !piece_tile || !pos_count) {
return NULL;
}
@ -338,7 +338,30 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
}
switch (mode) {
case 0: {
case MODEKNIGHT: {
for (unsigned int j = 0; j < 8; j++) {
int vx = KNIGHTDELTAS[j].x;
int vy = KNIGHTDELTAS[j].y;
int xtmp = piece_tile->position.row + vx;
int ytmp = piece_tile->position.column + vy;
if (board_is_tile_in_bounds(board, position_new(xtmp, ytmp))) {
Tile* tile = board_get_tile(board, position_new(xtmp, ytmp));
if (tile->piece.type == NONE) {
legal_moves[i] = tile->position;
i++;
} else if (tile->piece.color != piece_tile->piece.color) {
legal_moves[i] = tile->position;
i++;
} else {
break;
}
}
}
break;
}
case MODESTRAIGHTS: {
for (unsigned int j = 0; j < 4; j++) {
int vx = CARDINALS[j].x;
int vy = CARDINALS[j].y;
@ -365,7 +388,7 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
break;
}
case 1: {
case MODEDIAGONALS: {
for (unsigned int j = 0; j < 4; j++) {
int vx = DIAGONALS[j].x;
int vy = DIAGONALS[j].y;
@ -392,7 +415,7 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
break;
}
case 2: {
case MODESTRAIGHTSDIAGONALS: {
for (unsigned int j = 0; j < 4; j++) {
int vx = CARDINALS[j].x;
int vy = CARDINALS[j].y;
@ -455,21 +478,184 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
}
// Returns all possible legal rook moves. Returns NULL if given tile does not contain a rook piece
// Returns all possible legal knight positions.
Position* board_get_knight_moves(const Board* board, const Tile* knight_tile, unsigned int* pos_count) {
if (!board || !knight_tile || !pos_count) {
return NULL;
}
return board_get_positions(board, knight_tile, MODEKNIGHT, pos_count);
}
// Returns all possible legal rook moves.
Position* board_get_rook_moves(const Board* board, const Tile* rook_tile, unsigned int* pos_count) {
if (!board || !rook_tile || !pos_count) {
return NULL;
}
if (rook_tile->piece.type != ROOK) {
return board_get_positions(board, rook_tile, MODESTRAIGHTS, pos_count);
}
// Returns all possible legal bishop positions.
Position* board_get_bishop_moves(const Board* board, const Tile* bishop_tile, unsigned int* pos_count) {
if (!board || !bishop_tile || !pos_count) {
return NULL;
}
return board_get_positions(board, bishop_tile, MODEDIAGONALS, pos_count);
}
// Returns all possible legal queen positions.
Position* board_get_queen_moves(const Board* board, const Tile* queen_tile, unsigned int* pos_count) {
if (!board || !queen_tile || !pos_count) {
return NULL;
}
return board_get_positions(board, queen_tile, MODESTRAIGHTSDIAGONALS, pos_count);
}
// Returns all possible legal king positions.
Position* board_get_king_moves(const Board* board, const Tile* king_tile, unsigned int* pos_count) {
if (!board || !king_tile || !pos_count) {
return NULL;
}
Position* queen_positions = board_get_queen_moves(board, king_tile, pos_count);
Position* king_positions = malloc(sizeof(Position) * (*pos_count));
if (!king_positions) {
free(queen_positions);
return NULL;
}
unsigned int king_pos_count = 0;
for (unsigned int i = 0; i < *pos_count; i++) {
if (position_distance(king_tile->position, queen_positions[i]) > 1) {
continue;
}
king_positions[king_pos_count] = queen_positions[i];
king_pos_count++;
}
free(queen_positions);
*pos_count = king_pos_count;
king_positions = realloc(king_positions, sizeof(Position) * king_pos_count);
return NULL;
}
// Returns all possible legal pawn positions.
Position* board_get_pawn_moves(const Board* board, const Tile* pawn_tile, unsigned int* pos_count) {
if (!board || !pawn_tile || !pos_count) {
return NULL;
}
return board_get_moves(board, rook_tile, 0, pos_count);
Position* positions = malloc(sizeof(Position) * board->rows * board->columns);
if (!positions) {
return NULL;
}
// 1 and 2 tile advancements and takes
Position pos = pawn_tile->position;
for (int i = 1; i <= 2; i++) {
pos = pawn_tile->position;
// Advances
if (pawn_tile->piece.color == WHITE) {
pos.row = pos.row + i;
} else {
pos.row = pos.row - i;
}
if (board_is_tile_in_bounds(board, pos)) {
Tile* tile = board_get_tile(board, pos);
if (tile->piece.type == NONE) {
// Add this position
positions[*pos_count] = pos;
(*pos_count)++;
}
}
// Takes
if (i % 2 == 0) {
pos.column = pos.column + 1;
} else {
pos.column = pos.column - 1;
}
if (board_is_tile_in_bounds(board, pos)) {
Tile* tile = board_get_tile(board, pos);
if (tile->piece.type != NONE && tile->piece.color != pawn_tile->piece.color) {
// Add this position
positions[*pos_count] = pos;
(*pos_count)++;
}
}
}
positions = realloc(positions, sizeof(Position) * (*pos_count));
return positions;
}
// Returns all possible legal positions for a piece standing on piece_tile. Returns NULL in case of an error
Position* board_get_positions_for(const Board* board, const Tile* piece_tile, unsigned int* pos_count) {
if (!board || !piece_tile || !pos_count) {
return NULL;
}
// Check if there is a piece or not
if (piece_tile->piece.type == NONE) {
return NULL;
}
switch (piece_tile->piece.type) {
PAWN: {
return board_get_pawn_moves(board, piece_tile, pos_count);
}
KNIGHT: {
return board_get_knight_moves(board, piece_tile, pos_count);
}
ROOK: {
return board_get_rook_moves(board, piece_tile, pos_count);
}
BISHOP: {
return board_get_bishop_moves(board, piece_tile, pos_count);
}
QUEEN: {
return board_get_queen_moves(board, piece_tile, pos_count);
}
KING: {
return board_get_king_moves(board, piece_tile, pos_count);
}
default: {
return NULL;
}
}
return NULL;
}
/*
Checks if a move is legal or not (and reason) on this board.
@ -520,7 +706,27 @@ MoveLegality board_is_move_legal(const Board* board, Move move, Color color_play
}
case QUEEN: {
return LEGAL;
unsigned int pos_count = 0;
Position* legal_positions = board_get_queen_moves(
board,
board_get_tile(board, move.origin),
&pos_count
);
for (unsigned int i = 0; i < pos_count; i++) {
if (legal_positions[i].row == move.target.row &&
legal_positions[i].column == move.target.column
)
{
// This position is allowed to be moved to
free(legal_positions);
return LEGAL;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case ROOK: {
@ -542,20 +748,81 @@ MoveLegality board_is_move_legal(const Board* board, Move move, Color color_play
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return LEGAL;
return ILLINVALIDPIECEMOVEMENT;
}
case KNIGHT: {
return LEGAL;
unsigned int pos_count = 0;
Position* legal_positions = board_get_knight_moves(
board,
board_get_tile(board, move.origin),
&pos_count
);
for (unsigned int i = 0; i < pos_count; i++) {
if (legal_positions[i].row == move.target.row &&
legal_positions[i].column == move.target.column
)
{
// This position is allowed to be moved to
free(legal_positions);
return LEGAL;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case BISHOP: {
return LEGAL;
unsigned int pos_count = 0;
Position* legal_positions = board_get_bishop_moves(
board,
board_get_tile(board, move.origin),
&pos_count
);
for (unsigned int i = 0; i < pos_count; i++) {
if (legal_positions[i].row == move.target.row &&
legal_positions[i].column == move.target.column
)
{
// This position is allowed to be moved to
free(legal_positions);
return LEGAL;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case PAWN: {
return LEGAL;
unsigned int pos_count = 0;
Position* legal_positions = board_get_pawn_moves(
board,
board_get_tile(board, move.origin),
&pos_count
);
for (unsigned int i = 0; i < pos_count; i++) {
if (legal_positions[i].row == move.target.row &&
legal_positions[i].column == move.target.column
)
{
// This position is allowed to be moved to
free(legal_positions);
return LEGAL;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
default: {

38
src/board.h

@ -107,22 +107,50 @@ int board_is_tile_occupied(const Board* board, Position pos);
void board_print(const Board* board, FILE* out);
typedef enum MoveMode {
MODESTRAIGHTS,
MODEDIAGONALS,
MODESTRAIGHTSDIAGONALS,
MODEKNIGHT
} MoveMode;
/*
Returns all possible legal positions either in diagonal or in straight lines
Returns all possible legal positions in diagonal, in straight lines, in both as well as knight-type for specified tile.
If mode is 0 - returns positions in straight lines, 1 - in diagonals, 2 - in both
Returns NULL in case of an error
*/
Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode, unsigned int* pos_count);
Position* board_get_positions(const Board* board, const Tile* piece_tile, MoveMode mode, unsigned int* pos_count);
// Returns all possible legal king positions. Returns NULL if given tile does not contain a king piece
// Returns all possible legal king positions.
Position* board_get_king_moves(const Board* board, const Tile* king_tile, unsigned int* pos_count);
// Returns all possible legal king positions. Returns NULL if given tile does not contain a rook piece
// Returns all possible legal rook positions.
Position* board_get_rook_moves(const Board* board, const Tile* rook_tile, unsigned int* pos_count);
// Returns all possible legal queen positions.
Position* board_get_queen_moves(const Board* board, const Tile* queen_tile, unsigned int* pos_count);
// Returns all possible legal bishop positions.
Position* board_get_bishop_moves(const Board* board, const Tile* bishop_tile, unsigned int* pos_count);
// Returns all possible legal knight positions.
Position* board_get_knight_moves(const Board* board, const Tile* knight_tile, unsigned int* pos_count);
// Returns all possible legal pawn positions.
Position* board_get_pawn_moves(const Board* board, const Tile* pawn_tile, unsigned int* pos_count);
// Returns all possible legal positions for a piece standing on piece_tile. Returns NULL in case of an error
Position* board_get_positions_for(const Board* board, const Tile* piece_tile, unsigned int* pos_count);
// Move legality status
typedef enum MoveLegality {
LEGAL,

Loading…
Cancel
Save