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
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
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) {
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,20 +478,183 @@ 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;
}
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;
}
return board_get_moves(board, rook_tile, 0, pos_count);
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,8 +706,28 @@ MoveLegality board_is_move_legal(const Board* board, Move move, Color color_play
}
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;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
case ROOK: {
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);
return LEGAL;
return ILLINVALIDPIECEMOVEMENT;
}
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;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
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;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
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;
}
}
// Couldn't find such a position in legal placements
free(legal_positions);
return ILLINVALIDPIECEMOVEMENT;
}
default: {
// 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);
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