Browse Source

feat: board: get any piece positions on board

master
parent
commit
d97d9dc34b
  1. 1
      TODO
  2. 287
      src/board.c
  3. 38
      src/board.h

1
TODO

@ -1,3 +1,4 @@
1. Algebraic notation: notation_move_to_string, documentation 1. Algebraic notation: notation_move_to_string, documentation
2. Board: board_is_move_legal, add other piece's moves 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 3. Chess: output special error message for each type of illegal move so it's clear what went wrong
4. board_get_pawn_moves - add en passant

287
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) { if (!board || !piece_tile || !pos_count) {
return NULL; return NULL;
} }
@ -338,7 +338,30 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
} }
switch (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++) { for (unsigned int j = 0; j < 4; j++) {
int vx = CARDINALS[j].x; int vx = CARDINALS[j].x;
int vy = CARDINALS[j].y; int vy = CARDINALS[j].y;
@ -365,7 +388,7 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
break; break;
} }
case 1: { case MODEDIAGONALS: {
for (unsigned int j = 0; j < 4; j++) { for (unsigned int j = 0; j < 4; j++) {
int vx = DIAGONALS[j].x; int vx = DIAGONALS[j].x;
int vy = DIAGONALS[j].y; int vy = DIAGONALS[j].y;
@ -392,7 +415,7 @@ Position* board_get_moves(const Board* board, const Tile* piece_tile, int mode,
break; break;
} }
case 2: { case MODESTRAIGHTSDIAGONALS: {
for (unsigned int j = 0; j < 4; j++) { for (unsigned int j = 0; j < 4; j++) {
int vx = CARDINALS[j].x; int vx = CARDINALS[j].x;
int vy = CARDINALS[j].y; 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) { Position* board_get_rook_moves(const Board* board, const Tile* rook_tile, unsigned int* pos_count) {
if (!board || !rook_tile || !pos_count) { if (!board || !rook_tile || !pos_count) {
return NULL; 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 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. Checks if a move is legal or not (and reason) on this board.
@ -520,8 +706,28 @@ MoveLegality board_is_move_legal(const Board* board, Move move, Color color_play
} }
case QUEEN: { case QUEEN: {
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; return LEGAL;
} }
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case ROOK: { case ROOK: {
unsigned int pos_count = 0; unsigned int pos_count = 0;
@ -542,21 +748,82 @@ 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); free(legal_positions);
return LEGAL; return ILLINVALIDPIECEMOVEMENT;
} }
case KNIGHT: { case KNIGHT: {
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; return LEGAL;
} }
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case BISHOP: { case BISHOP: {
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; return LEGAL;
} }
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case PAWN: { case PAWN: {
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; return LEGAL;
} }
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
default: { default: {
// Non reachable // Non reachable

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); 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); 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); 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 // Move legality status
typedef enum MoveLegality { typedef enum MoveLegality {
LEGAL, LEGAL,

Loading…
Cancel
Save