check captures + promotions done?
This commit is contained in:
+130
-32
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user