check captures + promotions done?

This commit is contained in:
Odweta
2026-02-18 16:51:14 +01:00
parent 44c38667a4
commit de55c98be3
3 changed files with 209 additions and 62 deletions
+130 -32
View File
@@ -1,4 +1,5 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "chess.h" #include "chess.h"
#include "util.h" #include "util.h"
@@ -79,33 +80,59 @@ pos_t pos_multiply_scalar(pos_t a, int b) {
return (pos_t){a.x*b, a.y*b}; return (pos_t){a.x*b, a.y*b};
} }
// check whether a position is out of bounds of the board
bool is_pos_oob(pos_t pos) {
return pos.x < 0 || pos.x > BOARD_HORIZONTAL ||
pos.y < 0 || pos.y > BOARD_VERTICAL;
}
/** /**
* check the wanted pos_t against all valid move options * check the wanted pos_t against all valid move options
* of the current piece * of the current piece
*/ */
bool is_move_legal(move_t move) { bool is_move_legal(move_t move) {
pos_t new_pos = {
move.from.x+move.to.x,
move.from.y+move.to.y
};
// OOB check
if (is_pos_oob(new_pos)) {
return false;
}
valid_move_t valid_moves[PIECE_COUNT] = DEFAULT_VALID_MOVES; valid_move_t valid_moves[PIECE_COUNT] = DEFAULT_VALID_MOVES;
switch (move.piece) { switch (move.piece) {
case NONE: case NONE:
case PAWN: case WPAWN:
case KNIGHT: case WKNIGHT:
case KING: case WKING:
case BPAWN:
case BKNIGHT:
case BKING:
for (int i = 0; i < PIECE_COUNT; i++) { for (int i = 0; i < PIECE_COUNT; i++) {
for (int j = 0; for (int j = 0;
j < valid_moves[i].piece_move_count && j < valid_moves[i].piece_move_count &&
move.piece == valid_moves[i].piece; move.piece == valid_moves[i].piece;
j++ j++
) { ) {
pos_t new_pos = {move.from.x+move.to.x, move.from.y+move.to.y}; if (
if (compare_pos(new_pos, valid_moves[i].options[j]) == true) { compare_pos(
new_pos,
valid_moves[i].options[j]
)
) {
return true; return true;
} }
} }
} }
break; break;
case ROOK: case WROOK:
case BISHOP: case WBISHOP:
case QUEEN: case WQUEEN:
case BROOK:
case BBISHOP:
case BQUEEN:
for (int i = 0; i < PIECE_COUNT; i++) { for (int i = 0; i < PIECE_COUNT; i++) {
for (int j = 0; for (int j = 0;
j < valid_moves[i].piece_move_count && j < valid_moves[i].piece_move_count &&
@@ -114,15 +141,13 @@ bool is_move_legal(move_t move) {
) { ) {
/** NOTE: BOARD_HORIZONTAL assuming HORIZONTAL & VERTICAL are the same */ /** NOTE: BOARD_HORIZONTAL assuming HORIZONTAL & VERTICAL are the same */
for (int k = 0; k < BOARD_HORIZONTAL; k++) { for (int k = 0; k < BOARD_HORIZONTAL; k++) {
pos_t new_pos = { if (
move.from.x+move.to.x, compare_pos(
move.from.y+move.to.y new_pos,
}; pos_multiply_scalar(valid_moves[i].options[j], k)
if (compare_pos( )
new_pos, ) {
pos_multiply_scalar(valid_moves[i].options[j], k) return true;
) == true) {
return true;
} }
} }
} }
@@ -133,22 +158,36 @@ bool is_move_legal(move_t move) {
return false; return false;
} }
bool is_none(board_t board, pos_t pos) { bool is_dest_none(board_t board, pos_t pos) {
return board[pos.y][pos.x] == NONE; return board[pos.y][pos.x] == NONE;
} }
bool is_dest_opponent(board_t board, player_e player, move_t move) {
switch (player) {
case WHITE:
return board[move.to.y][move.to.x] < 0;
break;
case BLACK:
return board[move.to.y][move.to.x] > 0;
break;
}
}
/** the move can be: /** the move can be:
* 1. legal x illegal * 1. legal x illegal
* 2. the 'to' pos could be occupied x non-occupied * 2a. the 'to' pos could be occupied x non-occupied
* 2a. it could be capturable x non-capturable * 2b. it could be capturable x non-capturable
* 2c. it could be out of bounds
*/ */
bool validate_move(board_t board, move_t move) { bool validate_move(board_t board, player_e player, move_t move) {
bool none = is_none(board, move.to); bool none = is_dest_none(board, move.to);
bool dest_is_opponent = is_dest_opponent(board, player, move);
bool move_legal = is_move_legal(move); bool move_legal = is_move_legal(move);
if (none == true && move_legal == true) { if (none && move_legal) {
// free ability to move // free ability to move
return true; return true;
} else if (none == false && move_legal == true) { } else if (!none && dest_is_opponent && move_legal) {
// capturing // capturing
return true; return true;
} else { } else {
@@ -157,18 +196,76 @@ bool validate_move(board_t board, move_t move) {
} }
} }
/** TODO: capturing and promotions */ /**
bool perform_move(board_t *board, player_e player, move_t move) { * checks and sorts out a capture edge case of a move
bool move_valid = validate_move(*board, move); * sorts out = moves the piece into the 'captured' area and puts a NONE in its' place
if (move_valid == true) { * (if the 'captured' piece is not a king, because you cannot capture a king)
*/
bool check_captures(board_t *board, player_e player, captured_t *captured, move_t move) {
if (is_dest_opponent(*board, player, move)) {
switch (player) {
case WHITE:
captured->white[captured->white_n++] = abs(*board[move.to.y][move.to.x]);
*board[move.to.y][move.to.x] = NONE;
break;
case BLACK:
captured->white[captured->white_n++] = abs(*board[move.to.y][move.to.x]);
*board[move.to.y][move.to.x] = NONE;
break;
}
return true;
} else {
return false;
}
}
// checks and sorts out a promotion edge case of a move
bool check_promotions(board_t *board, player_e player, move_t *move) {
pos_t new_pos = {
move->from.x+move->to.x,
move->from.y+move->to.y
};
// white player achieved a promotion
if (new_pos.y < 0 && player == WHITE && move->piece == WPAWN) {
*board[move->from.y][move->from.x] = WQUEEN;
move->piece = WQUEEN;
return true;
}
// black player achieved a promotion
if (new_pos.y > BOARD_VERTICAL && player == BLACK && move->piece == BPAWN) {
*board[move->from.y][move->from.x] = BQUEEN;
move->piece = BQUEEN;
return true;
}
return false;
}
// checks for mates
/** FIXME: unimplemented */
end_condition_e check_end() {
return CONTINUE;
}
end_condition_e perform_move(board_t *board, player_e player, captured_t *captured, move_t move) {
if (validate_move(*board, player, move)) {
if (
*board[move.to.y][move.to.x] != WKING || // accounting for both players
*board[move.to.y][move.to.x] != BKING // you cannot capture a king
) {
check_captures(board, player, captured, move);
}
check_promotions(board, player, &move);
*board[move.to.y][move.to.x] = move.piece; // move piece to wanted place *board[move.to.y][move.to.x] = move.piece; // move piece to wanted place
*board[move.from.y][move.from.x] = NONE; // erase the remnants *board[move.from.y][move.from.x] = NONE; // erase the remnants
} }
return move_valid;
}
end_condition_e check_edge_cases(board_t board) { return check_end();
return CHECKMATE;
} }
void announce_results(end_condition_e end_condition, player_e player) { void announce_results(end_condition_e end_condition, player_e player) {
@@ -181,6 +278,7 @@ void announce_results(end_condition_e end_condition, player_e player) {
case STALEMATE: case STALEMATE:
printf("STALEMATE"); printf("STALEMATE");
break; break;
case CONTINUE: break; // to make the linter happy
} }
printf("\nand the player who has won is"); printf("\nand the player who has won is");
+77 -27
View File
@@ -19,18 +19,28 @@
#define BOARD_VERTICAL 8 #define BOARD_VERTICAL 8
// type abstractions // type abstractions
typedef int board_t[BOARD_HORIZONTAL][BOARD_VERTICAL]; typedef enum { WHITE, BLACK } player_e;
#define PIECE_COUNT 7 // how many unique pieces are there typedef int board_t[BOARD_VERTICAL][BOARD_HORIZONTAL];
#define PIECE_COUNT 13 // how many unique pieces are there
#define MAX_PIECE_MOVE_COUNT 27 // the max possible num of options where to move in one moment #define MAX_PIECE_MOVE_COUNT 27 // the max possible num of options where to move in one moment
typedef enum { typedef enum {
NONE, NONE,
PAWN,
ROOK, WPAWN,
KNIGHT, WROOK,
BISHOP, WKNIGHT,
QUEEN, WBISHOP,
KING WQUEEN,
WKING,
BPAWN,
BROOK,
BKNIGHT,
BBISHOP,
BQUEEN,
BKING
} piece_e; } piece_e;
typedef struct { typedef struct {
@@ -38,8 +48,6 @@ typedef struct {
int y; int y;
} pos_t; } pos_t;
typedef enum { WHITE, BLACK } player_e;
typedef struct { typedef struct {
// what // what
// where from // where from
@@ -50,15 +58,17 @@ typedef struct {
} move_t; } move_t;
// the default arrangment of pieces on the board // the default arrangment of pieces on the board
// negative numbers are black, positive ones white
#define BOARD_DEFAULT_CONFIG \ #define BOARD_DEFAULT_CONFIG \
(board_t){\ (board_t){\
{2,3,4,5,6,4,3,2},\ { BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK },\
{1,1,1,1,1,1,1,1},\ { BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN },\
{0,0,0,0,0,0,0,0},\ { NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
{0,0,0,0,0,0,0,0},\ { NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
{0,0,0,0,0,0,0,0},\ { NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
{1,1,1,1,1,1,1,1},\ { NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
{2,3,4,5,6,4,3,2}\ { WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN },\
{ WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK }\
} }
typedef struct { typedef struct {
@@ -87,34 +97,77 @@ typedef struct {
*/ */
#define DEFAULT_VALID_MOVES (valid_move_t[PIECE_COUNT]){\ #define DEFAULT_VALID_MOVES (valid_move_t[PIECE_COUNT]){\
{NONE, {}, 0},\ {NONE, {}, 0},\
{PAWN, {\ \
{WPAWN, {\
{ 0, -1}, {-1, -1}, {+1, -1}, { 0, -2}\ { 0, -1}, {-1, -1}, {+1, -1}, { 0, -2}\
}, 4},\ }, 4},\
{ROOK, {\ {WROOK, {\
{ 0, -1}, { 0, +1}, {-1, 0}, {+1, 0}\ { 0, -1}, { 0, +1}, {-1, 0}, {+1, 0}\
}, 4},\ }, 4},\
{KNIGHT, {\ {WKNIGHT, {\
{-1, -2}, {+1, -2}, {-2, -1}, {-2, +1},\ {-1, -2}, {+1, -2}, {-2, -1}, {-2, +1},\
{+2, -1}, {+2, +1}, {-1, -2}, {-1, +2}\ {+2, -1}, {+2, +1}, {-1, -2}, {-1, +2}\
}, 8},\ }, 8},\
{BISHOP, {\ {WBISHOP, {\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\ {-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 4},\ }, 4},\
{QUEEN, {\ {WQUEEN, {\
{0, -1}, {0, +1}, {-1, 0}, {+1, 0},\ {0, -1}, {0, +1}, {-1, 0}, {+1, 0},\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\ {-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 8},\ }, 8},\
{KING, {\ {WKING, {\
{ 0, -1}, { 0, +1}, {-1, 0}, {+1, 0},\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 8},\
\
{BPAWN, {\
{ 0, -1}, {-1, -1}, {+1, -1}, { 0, -2}\
}, 4},\
{BROOK, {\
{ 0, -1}, { 0, +1}, {-1, 0}, {+1, 0}\
}, 4},\
{BKNIGHT, {\
{-1, -2}, {+1, -2}, {-2, -1}, {-2, +1},\
{+2, -1}, {+2, +1}, {-1, -2}, {-1, +2}\
}, 8},\
{BBISHOP, {\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 4},\
{BQUEEN, {\
{0, -1}, {0, +1}, {-1, 0}, {+1, 0},\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 8},\
{BKING, {\
{ 0, -1}, { 0, +1}, {-1, 0}, {+1, 0},\ { 0, -1}, { 0, +1}, {-1, 0}, {+1, 0},\
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\ {-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
}, 8}\ }, 8}\
} }
/**
* states in which the game can end
* CONTINUE => the game does not end, it continues
* CHECKMATE => one side wins
* STALEMATE => it's a draw
*/
typedef enum { typedef enum {
CONTINUE,
CHECKMATE, CHECKMATE,
STALEMATE STALEMATE
} end_condition_e; } end_condition_e;
/**
* a tracker for which pieces have been captured by who
* white contains opponent pieces WHITE have been captured by them
* black contains opponent pieces BLACK have been captured by them
*/
#define PIECE_COUNT_CAPTURABLE_PER_PLAYER 15 // 2*8 - 1
typedef struct {
piece_e white[PIECE_COUNT_CAPTURABLE_PER_PLAYER];
unsigned int white_n;
piece_e black[PIECE_COUNT_CAPTURABLE_PER_PLAYER];
unsigned int black_n;
} captured_t;
// initializes the board with the default configuration of pieces // initializes the board with the default configuration of pieces
void init_board(board_t *board); void init_board(board_t *board);
@@ -126,10 +179,7 @@ void select_player(player_e *player, unsigned int round_count);
bool get_move(move_t *move); bool get_move(move_t *move);
// performs the move if is it possible // performs the move if is it possible
bool perform_move(board_t *board, player_e player, move_t move); end_condition_e perform_move(board_t *board, player_e player, captured_t *captured, move_t move);
// checks for captures, prommotions and mates
end_condition_e check_edge_cases(board_t board);
// if there is one of the mates, end the game and show who has won // if there is one of the mates, end the game and show who has won
void announce_results(end_condition_e end_condition, player_e player); void announce_results(end_condition_e end_condition, player_e player);
+2 -3
View File
@@ -22,6 +22,7 @@ int main() {
player_e player; player_e player;
unsigned int round_count = 0; unsigned int round_count = 0;
end_condition_e end_condition; end_condition_e end_condition;
captured_t captured = {.white_n = 0, .black_n = 0};
bool running = true; bool running = true;
// algo begin // algo begin
@@ -37,9 +38,7 @@ int main() {
get_move(&move); get_move(&move);
perform_move(&board, player, move); end_condition = perform_move(&board, player, &captured, move);
end_condition = check_edge_cases(board);
if (end_condition == CHECKMATE || end_condition == STALEMATE) { if (end_condition == CHECKMATE || end_condition == STALEMATE) {
running = false; running = false;
} }