v2 initial commit
This commit is contained in:
Executable
BIN
Binary file not shown.
-426
@@ -1,426 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include "chess.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
void init_board(board_t board) {
|
|
||||||
for (int i = 0; i < BOARD_VERTICAL; i++) {
|
|
||||||
for (int j = 0; j < BOARD_HORIZONTAL; j++) {
|
|
||||||
board[i][j] = BOARD_DEFAULT_CONFIG[i][j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void select_player(player_e *player, unsigned int round_count) {
|
|
||||||
if (round_count == 1) {
|
|
||||||
*player = WHITE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*player == WHITE) {
|
|
||||||
*player = BLACK;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*player == BLACK) {
|
|
||||||
*player = WHITE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_help() {
|
|
||||||
puts(
|
|
||||||
"movement help:\n\
|
|
||||||
there is a prompt asking for where to move a piece every turn\n\
|
|
||||||
format: e.g. you want to move a knight from b1 to a3:\n\
|
|
||||||
you'd type -> b1 a3 <- (without the arrows)\n"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns false if the numbers of letters are out of bounds
|
|
||||||
bool is_move_in_bounds(move_t move) {
|
|
||||||
if (
|
|
||||||
is_int_in_range(move.from.x, 0, 7) &&
|
|
||||||
is_int_in_range(move.from.y, 0, 7) &&
|
|
||||||
is_int_in_range(move.to.x, 0, 7) &&
|
|
||||||
is_int_in_range(move.to.y, 0, 7)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_move(board_t board, move_t *move) {
|
|
||||||
char _x_from, _x_to;
|
|
||||||
int _y_from, _y_to;
|
|
||||||
printf("move >> ");
|
|
||||||
scanf(" %c%d %c%d",
|
|
||||||
&_x_from,
|
|
||||||
&_y_from,
|
|
||||||
&_x_to,
|
|
||||||
&_y_to
|
|
||||||
);
|
|
||||||
|
|
||||||
move->from.x = _x_from-96-1; // char to int conversion
|
|
||||||
move->from.y = _y_from-1;
|
|
||||||
|
|
||||||
move->to.x = _x_to-96-1;
|
|
||||||
move->to.y = _y_to-1;
|
|
||||||
|
|
||||||
move->piece = board[move->from.y][move->from.x];
|
|
||||||
|
|
||||||
return is_move_in_bounds(*move);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool compare_pos(pos_t a, pos_t b) {
|
|
||||||
return a.x == b.x && a.y == b.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_t pos_multiply_scalar(pos_t a, int b) {
|
|
||||||
return (pos_t){a.x*b, a.y*b};
|
|
||||||
}
|
|
||||||
|
|
||||||
pos_t pos_add(pos_t a, pos_t b) {
|
|
||||||
return (pos_t){a.x + b.x, a.y + b.y};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
* of the current piece
|
|
||||||
*/
|
|
||||||
/** TODO: add roundcount check for PAWN */
|
|
||||||
bool is_move_legal(move_t move) {
|
|
||||||
pos_t new_pos = move.to;
|
|
||||||
|
|
||||||
// OOB check
|
|
||||||
if (is_pos_oob(new_pos)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
valid_move_t valid_moves[PIECE_COUNT] = DEFAULT_VALID_MOVES;
|
|
||||||
switch (move.piece) {
|
|
||||||
case NONE:
|
|
||||||
case WPAWN:
|
|
||||||
case WKNIGHT:
|
|
||||||
case WKING:
|
|
||||||
case BPAWN:
|
|
||||||
case BKNIGHT:
|
|
||||||
case BKING:
|
|
||||||
for (int j = 0; j < valid_moves[move.piece].piece_move_count; j++) {
|
|
||||||
pos_t candidate = pos_add(move.from, valid_moves[move.piece].options[j]);
|
|
||||||
printf("cadidate {%d,%d}\n", candidate.x, candidate.y);
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
new_pos,
|
|
||||||
candidate
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WROOK:
|
|
||||||
case WBISHOP:
|
|
||||||
case WQUEEN:
|
|
||||||
case BROOK:
|
|
||||||
case BBISHOP:
|
|
||||||
case BQUEEN:
|
|
||||||
for (int j = 0; j < valid_moves[move.piece].piece_move_count; j++) {
|
|
||||||
/** NOTE: BOARD_HORIZONTAL assuming HORIZONTAL & VERTICAL are the same */
|
|
||||||
for (int k = 0; k < BOARD_HORIZONTAL; k++) {
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
new_pos,
|
|
||||||
pos_multiply_scalar(
|
|
||||||
pos_add(
|
|
||||||
move.from,
|
|
||||||
valid_moves[move.piece].options[j]
|
|
||||||
), k
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_dest_none(board_t board, pos_t pos) {
|
|
||||||
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:
|
|
||||||
* 1. legal x illegal
|
|
||||||
* 2a. the 'to' pos could be occupied x non-occupied
|
|
||||||
* 2b. it could be capturable x non-capturable
|
|
||||||
* 2c. it could be out of bounds
|
|
||||||
*/
|
|
||||||
/** FIXME: does not work -> b1 a3 says 0 */
|
|
||||||
bool validate_move(board_t board, player_e player, move_t move) {
|
|
||||||
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);
|
|
||||||
printf("move.from = {%d,%d}; move.to = {%d,%d}\n", move.from.x, move.from.y, move.to.x, move.to.y);
|
|
||||||
printf("from.piece = %d; to.piece = %d\n", board[move.from.y][move.from.x], board[move.to.y][move.to.x]);
|
|
||||||
printf("dest is none? %d; dest is opp? %d; legal? %d\n", none, dest_is_opponent, move_legal);
|
|
||||||
if (none && move_legal) {
|
|
||||||
// free ability to move
|
|
||||||
return true;
|
|
||||||
} else if (!none && dest_is_opponent && move_legal) {
|
|
||||||
// capturing
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
// otherwise, invalid move
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* checks and sorts out a capture edge case of a move
|
|
||||||
* sorts out = moves the piece into the 'captured' area and puts a NONE in its' place
|
|
||||||
* (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++] = *board[move.to.y][move.to.x];
|
|
||||||
*board[move.to.y][move.to.x] = NONE;
|
|
||||||
break;
|
|
||||||
case BLACK:
|
|
||||||
captured->white[captured->white_n++] = *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->to;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// negative pos => no such piece is there
|
|
||||||
pos_t get_pos_of_piece(board_t board, piece_e piece) {
|
|
||||||
for (int i = 0; i < BOARD_VERTICAL; i++) {
|
|
||||||
for (int j = 0; j < BOARD_VERTICAL; j++) {
|
|
||||||
if (board[i][j] == piece) {
|
|
||||||
return (pos_t){j, i};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (pos_t){-1, -1};
|
|
||||||
}
|
|
||||||
|
|
||||||
// if king's pos is in another piece's valid moves, it is endangered
|
|
||||||
bool is_king_endangered(board_t board, player_e player, move_t move) {
|
|
||||||
pos_t king_pos;
|
|
||||||
valid_move_t valid_moves[PIECE_COUNT] = DEFAULT_VALID_MOVES;
|
|
||||||
|
|
||||||
switch (player) {
|
|
||||||
case WHITE:
|
|
||||||
king_pos = get_pos_of_piece(board, WKING);
|
|
||||||
switch (move.piece) {
|
|
||||||
case NONE:
|
|
||||||
case BPAWN:
|
|
||||||
case BKNIGHT:
|
|
||||||
case BKING:
|
|
||||||
for (int i = 0; i < PIECE_COUNT; i++) {
|
|
||||||
for (int j = 0;
|
|
||||||
j < valid_moves[i].piece_move_count &&
|
|
||||||
move.piece == valid_moves[i].piece;
|
|
||||||
j++
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
king_pos,
|
|
||||||
valid_moves[i].options[j]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BROOK:
|
|
||||||
case BBISHOP:
|
|
||||||
case BQUEEN:
|
|
||||||
for (int i = 0; i < PIECE_COUNT; i++) {
|
|
||||||
for (int j = 0;
|
|
||||||
j < valid_moves[i].piece_move_count &&
|
|
||||||
move.piece == valid_moves[i].piece;
|
|
||||||
j++
|
|
||||||
) {
|
|
||||||
/** NOTE: BOARD_HORIZONTAL assuming HORIZONTAL & VERTICAL are the same */
|
|
||||||
for (int k = 0; k < BOARD_HORIZONTAL; k++) {
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
king_pos,
|
|
||||||
pos_multiply_scalar(valid_moves[i].options[j], k)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BLACK:
|
|
||||||
king_pos = get_pos_of_piece(board, BKING);
|
|
||||||
switch (move.piece) {
|
|
||||||
case NONE:
|
|
||||||
case WPAWN:
|
|
||||||
case WKNIGHT:
|
|
||||||
case WKING:
|
|
||||||
for (int i = 0; i < PIECE_COUNT; i++) {
|
|
||||||
for (int j = 0;
|
|
||||||
j < valid_moves[i].piece_move_count &&
|
|
||||||
move.piece == valid_moves[i].piece;
|
|
||||||
j++
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
king_pos,
|
|
||||||
valid_moves[i].options[j]
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WROOK:
|
|
||||||
case WBISHOP:
|
|
||||||
case WQUEEN:
|
|
||||||
for (int i = 0; i < PIECE_COUNT; i++) {
|
|
||||||
for (int j = 0;
|
|
||||||
j < valid_moves[i].piece_move_count &&
|
|
||||||
move.piece == valid_moves[i].piece;
|
|
||||||
j++
|
|
||||||
) {
|
|
||||||
/** NOTE: BOARD_HORIZONTAL assuming HORIZONTAL & VERTICAL are the same */
|
|
||||||
for (int k = 0; k < BOARD_HORIZONTAL; k++) {
|
|
||||||
if (
|
|
||||||
compare_pos(
|
|
||||||
king_pos,
|
|
||||||
pos_multiply_scalar(valid_moves[i].options[j], k)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks for mates
|
|
||||||
end_condition_e check_end(board_t board, player_e player, move_t move) {
|
|
||||||
// here 'is_move_legal' is used as a determinator if a piece can move
|
|
||||||
if (is_king_endangered(board, player, move) && !is_move_legal(move)) {
|
|
||||||
return CHECKMATE;
|
|
||||||
} else if (!is_king_endangered(board, player, move) && !is_move_legal(move)) {
|
|
||||||
return STALEMATE;
|
|
||||||
} else {
|
|
||||||
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.from.y][move.from.x] = NONE; // erase the remnants
|
|
||||||
}
|
|
||||||
|
|
||||||
return check_end(*board, player, move);
|
|
||||||
}
|
|
||||||
|
|
||||||
void announce_results(end_condition_e end_condition, player_e player) {
|
|
||||||
printf("The game has ended because of a ");
|
|
||||||
|
|
||||||
switch (end_condition) {
|
|
||||||
case CHECKMATE:
|
|
||||||
printf("CHECKMATE");
|
|
||||||
break;
|
|
||||||
case STALEMATE:
|
|
||||||
printf("STALEMATE");
|
|
||||||
break;
|
|
||||||
case CONTINUE: break; // to make the linter happy
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\nand the player who has won is");
|
|
||||||
|
|
||||||
switch (player) {
|
|
||||||
case WHITE:
|
|
||||||
printf(" WHITE");
|
|
||||||
break;
|
|
||||||
case BLACK:
|
|
||||||
printf(" BLACK");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("! Congratulations.\n");
|
|
||||||
}
|
|
||||||
-190
@@ -1,190 +0,0 @@
|
|||||||
#ifndef CHESS_H
|
|
||||||
#define CHESS_H
|
|
||||||
|
|
||||||
/* the "board" is the playable area on which
|
|
||||||
* pieces move. pieces are represented by numbers:
|
|
||||||
* 0 - no piece
|
|
||||||
* 1 - pawn
|
|
||||||
* 2 - rook
|
|
||||||
* 3 - knight
|
|
||||||
* 4 - bishop
|
|
||||||
* 5 - queen
|
|
||||||
* 6 - king
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// board size constraints
|
|
||||||
#define BOARD_HORIZONTAL 8
|
|
||||||
#define BOARD_VERTICAL 8
|
|
||||||
|
|
||||||
// type abstractions
|
|
||||||
typedef enum { WHITE, BLACK } player_e;
|
|
||||||
|
|
||||||
#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
|
|
||||||
typedef enum {
|
|
||||||
NONE,
|
|
||||||
|
|
||||||
WPAWN,
|
|
||||||
WROOK,
|
|
||||||
WKNIGHT,
|
|
||||||
WBISHOP,
|
|
||||||
WQUEEN,
|
|
||||||
WKING,
|
|
||||||
|
|
||||||
BPAWN,
|
|
||||||
BROOK,
|
|
||||||
BKNIGHT,
|
|
||||||
BBISHOP,
|
|
||||||
BQUEEN,
|
|
||||||
BKING
|
|
||||||
} piece_e;
|
|
||||||
|
|
||||||
typedef piece_e board_t[BOARD_VERTICAL][BOARD_HORIZONTAL];
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
} pos_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// what
|
|
||||||
// where from
|
|
||||||
// where to
|
|
||||||
piece_e piece;
|
|
||||||
pos_t from;
|
|
||||||
pos_t to;
|
|
||||||
} move_t;
|
|
||||||
|
|
||||||
// the default arrangment of pieces on the board
|
|
||||||
// negative numbers are black, positive ones white
|
|
||||||
#define BOARD_DEFAULT_CONFIG \
|
|
||||||
(board_t){\
|
|
||||||
{ BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK },\
|
|
||||||
{ BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN },\
|
|
||||||
{ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
|
|
||||||
{ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
|
|
||||||
{ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
|
|
||||||
{ NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE },\
|
|
||||||
{ WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN },\
|
|
||||||
{ WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK }\
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
piece_e piece;
|
|
||||||
pos_t options[MAX_PIECE_MOVE_COUNT];
|
|
||||||
unsigned int piece_move_count;
|
|
||||||
} valid_move_t;
|
|
||||||
|
|
||||||
/** FIXED: ALSO DEPENDS ON THE STATE OF THE GAME -
|
|
||||||
* e.g. a pawn cannot move two places in the middle
|
|
||||||
* of the game but can in the first round
|
|
||||||
* => ASSUME NO OTHER PIECES - then ALWAYS CHECK
|
|
||||||
* FOR PIECE COLLISIONS and FOR ROUND COUNT
|
|
||||||
* (pawn 1 || 2 move)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** MAYBE: consider the POV from both sides???!!! */
|
|
||||||
/**
|
|
||||||
* the NONE, PAWN, KNIGHT and KING pieces' relative_moves are
|
|
||||||
* treated like specific coordinates relative to their
|
|
||||||
* position,
|
|
||||||
* whereas the BISHOP, ROOK and QUEEN pieces' 'moves'
|
|
||||||
* are treated as *directions* in which they can move rather than
|
|
||||||
* absolute x,y values -> e.g. the rook can move
|
|
||||||
* up, down, left, right * n -> and then bounds & edge cases are checked
|
|
||||||
*/
|
|
||||||
#define DEFAULT_VALID_MOVES {\
|
|
||||||
{NONE, {}, 0},\
|
|
||||||
\
|
|
||||||
{WPAWN, {\
|
|
||||||
{ 0, -1}, {-1, -1}, {+1, -1}, { 0, -2}\
|
|
||||||
}, 4},\
|
|
||||||
{WROOK, {\
|
|
||||||
{ 0, -1}, { 0, +1}, {-1, 0}, {+1, 0}\
|
|
||||||
}, 4},\
|
|
||||||
{WKNIGHT, {\
|
|
||||||
{-1, -2}, {+1, -2}, {-2, -1}, {-2, +1},\
|
|
||||||
{+2, -1}, {+2, +1}, {-1, -2}, {-1, +2}\
|
|
||||||
}, 8},\
|
|
||||||
{WBISHOP, {\
|
|
||||||
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
|
|
||||||
}, 4},\
|
|
||||||
{WQUEEN, {\
|
|
||||||
{0, -1}, {0, +1}, {-1, 0}, {+1, 0},\
|
|
||||||
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
|
|
||||||
}, 8},\
|
|
||||||
{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},\
|
|
||||||
{-1, -1}, {-1, +1}, {+1, -1}, {+1, +1}\
|
|
||||||
}, 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 {
|
|
||||||
CONTINUE,
|
|
||||||
CHECKMATE,
|
|
||||||
STALEMATE
|
|
||||||
} 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
|
|
||||||
void init_board(board_t board);
|
|
||||||
|
|
||||||
// selects the player to currently play
|
|
||||||
// if it is the first round, it selects white
|
|
||||||
void select_player(player_e *player, unsigned int round_count);
|
|
||||||
|
|
||||||
// listens for a command to make a move by the currently playing player
|
|
||||||
bool get_move(board_t board, move_t *move);
|
|
||||||
|
|
||||||
// performs the move if is it possible
|
|
||||||
end_condition_e perform_move(board_t *board, player_e player, captured_t *captured, move_t move);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// shows a guide to help players understand the move prompt system
|
|
||||||
void show_help();
|
|
||||||
|
|
||||||
#endif // CHESS_H
|
|
||||||
+2
-50
@@ -1,54 +1,6 @@
|
|||||||
// a chess implementation in pure C :)
|
|
||||||
|
|
||||||
#include "chess.h"
|
|
||||||
#include "render.h"
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* steps to victory:
|
|
||||||
* 1. init the board with the default config
|
|
||||||
* 2. game loop
|
|
||||||
* 2a. select the current player (if first round - white starts)
|
|
||||||
* 2b. wait for the movement of the current player
|
|
||||||
* 2c. once a move is registered, perform it IF POSSIBLE
|
|
||||||
* 2d. check for captures and/or promotions and/or mates (check, stale...)
|
|
||||||
* 2e. if there is an end condition that is met, end the game; announce
|
|
||||||
* the results
|
|
||||||
*/
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// variable defs
|
printf("Hello, World!\n");
|
||||||
board_t board;
|
return 0;
|
||||||
move_t move;
|
|
||||||
player_e player;
|
|
||||||
unsigned int round_count = 0;
|
|
||||||
end_condition_e end_condition;
|
|
||||||
captured_t captured = {.white_n = 0, .black_n = 0};
|
|
||||||
bool running = true;
|
|
||||||
|
|
||||||
// algo begin
|
|
||||||
|
|
||||||
init_board(board);
|
|
||||||
|
|
||||||
show_help();
|
|
||||||
|
|
||||||
while (running) {
|
|
||||||
round_count++;
|
|
||||||
|
|
||||||
select_player(&player, round_count);
|
|
||||||
|
|
||||||
show_board(board, player);
|
|
||||||
|
|
||||||
get_move(board, &move);
|
|
||||||
|
|
||||||
end_condition = perform_move(&board, player, &captured, move);
|
|
||||||
if (end_condition == CHECKMATE || end_condition == STALEMATE) {
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
announce_results(end_condition, player);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "render.h"
|
|
||||||
#include "chess.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void show_board(board_t board, player_e player) {
|
|
||||||
printf("\n ");
|
|
||||||
for (int i = 0; i < BOARD_HORIZONTAL; i++) {
|
|
||||||
printf("%-2c ", i+97);
|
|
||||||
}
|
|
||||||
printf("\n\n");
|
|
||||||
for (int i = 0; i < BOARD_VERTICAL; i++) {
|
|
||||||
printf("%-2d [", i+1);
|
|
||||||
for (int j = 0; j < BOARD_HORIZONTAL-1; j++) {
|
|
||||||
printf("%-2d ", board[i][j]);
|
|
||||||
}
|
|
||||||
printf("%d]\n", board[i][BOARD_HORIZONTAL-1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\ncurrently plays: ");
|
|
||||||
switch (player) {
|
|
||||||
case WHITE:
|
|
||||||
printf("WHITE\n");
|
|
||||||
break;
|
|
||||||
case BLACK:
|
|
||||||
printf("BLACK\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#ifndef RENDER_H
|
|
||||||
#define RENDER_H
|
|
||||||
|
|
||||||
#include "chess.h"
|
|
||||||
|
|
||||||
void show_board(board_t board, player_e player);
|
|
||||||
|
|
||||||
#endif // RENDER_H
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
#include "util.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void clear_stdin() {
|
|
||||||
while ((getchar()) != '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_int_in_range(int x, int start, int end) {
|
|
||||||
if (start <= x && x <= end) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
#ifndef UTIL_H
|
|
||||||
#define UTIL_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
// misc. defines and methods
|
|
||||||
|
|
||||||
// for input handling consistency
|
|
||||||
void clear_stdin();
|
|
||||||
|
|
||||||
// self-explanatory
|
|
||||||
bool is_int_in_range(int x, int start, int end);
|
|
||||||
|
|
||||||
#endif // UTIL_H
|
|
||||||
Reference in New Issue
Block a user