|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return board_get_moves(board, rook_tile, 0, pos_count); |
|
|
|
|
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: { |
|
|
|
|