Add castling
This commit is contained in:
309
src/chess.c
309
src/chess.c
@@ -56,7 +56,7 @@ static const double piece_value[] = {
|
||||
[KNIGHT] = 3,
|
||||
[ROOK] = 5,
|
||||
[QUEEN] = 9,
|
||||
[KING] = 0,
|
||||
[KING] = 10,
|
||||
};
|
||||
|
||||
static const double piece_position_bonus[7][BOARD_SIZE * sizeof(double)] = {
|
||||
@@ -64,10 +64,10 @@ static const double piece_position_bonus[7][BOARD_SIZE * sizeof(double)] = {
|
||||
[PAWN] = {
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.0,
|
||||
1.0, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.0,
|
||||
1.2, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.2,
|
||||
1.7, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.7,
|
||||
1.0, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.0,
|
||||
1.0, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.0,
|
||||
1.0, 1.0, 1.4, 1.4, 1.4, 1.4, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
},
|
||||
@@ -85,10 +85,10 @@ static const double piece_position_bonus[7][BOARD_SIZE * sizeof(double)] = {
|
||||
0.5, 0.7, 0.8, 0.8, 0.8, 0.8, 0.7, 0.5,
|
||||
0.6, 0.7, 0.9, 0.9, 0.9, 0.9, 0.7, 0.6,
|
||||
0.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.6,
|
||||
0.6, 1.0, 1.0, 1.1, 1.1, 1.0, 1.0, 0.6,
|
||||
0.6, 1.0, 1.0, 1.1, 1.1, 1.0, 1.0, 0.6,
|
||||
0.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.6,
|
||||
0.6, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.6,
|
||||
0.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.6,
|
||||
0.6, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.6,
|
||||
0.6, 0.7, 0.9, 0.9, 0.9, 0.9, 0.7, 0.6,
|
||||
0.5, 0.7, 0.8, 0.8, 0.8, 0.8, 0.7, 0.5,
|
||||
},
|
||||
[ROOK] = {
|
||||
@@ -112,6 +112,8 @@ static const double piece_position_bonus[7][BOARD_SIZE * sizeof(double)] = {
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
},
|
||||
[KING] = {
|
||||
/*a b c d e f g h*/
|
||||
1.4, 1.4, 1.4, 1.0, 1.0, 1.0, 99, 1.6,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
@@ -119,21 +121,13 @@ static const double piece_position_bonus[7][BOARD_SIZE * sizeof(double)] = {
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.001, 1.001, 1.0, 1.0, 1.0, 1.0, 1.001, 1.001,
|
||||
},
|
||||
};
|
||||
|
||||
#define TILE(col, row) ((col)-'A'+ROW*((row)-1))
|
||||
//static inline index_t tile(char col, int row)
|
||||
//{
|
||||
// assert(row >= 1);
|
||||
// assert(row <= 8);
|
||||
// assert(col >= 'A');
|
||||
// assert(col <= 'H');
|
||||
// return col-'A' + ROW*(row-1);
|
||||
//}
|
||||
|
||||
static bool friends(piece_t a, piece_t b)
|
||||
#define TILE(col, row) ((col)-'A'+ ROW*((row)-1))
|
||||
|
||||
static inline bool friends(piece_t a, piece_t b)
|
||||
{
|
||||
return a * b > 0;
|
||||
}
|
||||
@@ -154,26 +148,44 @@ static int signum(int t)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static index_t row(index_t i)
|
||||
static inline index_t row(index_t i)
|
||||
{
|
||||
return i / ROW;
|
||||
}
|
||||
|
||||
static index_t column(index_t i)
|
||||
static inline index_t column(index_t i)
|
||||
{
|
||||
return i % ROW;
|
||||
}
|
||||
|
||||
static bool enemies(piece_t a, piece_t b)
|
||||
static inline bool enemies(piece_t a, piece_t b)
|
||||
{
|
||||
return a * b < 0;
|
||||
}
|
||||
|
||||
static piece_t piece_color(piece_t t)
|
||||
static inline piece_t piece_color(piece_t t)
|
||||
{
|
||||
return (piece_t)signum(t);
|
||||
}
|
||||
|
||||
static const char * piece_str(piece_t p) {
|
||||
static const char * const table[] = {
|
||||
[EMPTY] = "EMPTY",
|
||||
[PAWN] = "PAWN",
|
||||
[BISHOP] = "BISHOP",
|
||||
[KNIGHT] = "KNIGHT",
|
||||
[ROOK] = "ROOK",
|
||||
[QUEEN] = "QUEEN",
|
||||
[KING] = "KING",
|
||||
};
|
||||
p = piece_abs(p);
|
||||
if (p >= 0 && (size_t)p < sizeof table / sizeof *table) {
|
||||
return table[piece_abs(p)];
|
||||
} else {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static void board_paint(struct game_state* g)
|
||||
{
|
||||
/* https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode
|
||||
@@ -184,8 +196,9 @@ static void board_paint(struct game_state* g)
|
||||
#define FG_BLACK() printf("\033[38;2;0;0;0m")
|
||||
#define FG_WHITE() printf("\033[38;2;255;255;255m")
|
||||
#define UNICODE_CHESS_SYMBOL 0x2659
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
printf("\n %zu ", 8 - i); // number coordinates
|
||||
for (ssize_t i = 7; i >= 0; i--) {
|
||||
//for (ssize_t i = 0; i < 8; i++) {
|
||||
printf("\n %zu ", i+1); // number coordinates
|
||||
for (size_t j = 0; j < 8; j++) {
|
||||
piece_t t = g->board[i * 8 + j];
|
||||
if ((i + j) % 2)
|
||||
@@ -218,13 +231,13 @@ static void move(struct game_state* g, index_t from, index_t to)
|
||||
if (piece_abs(g->board[from]) == KING) {
|
||||
g->king_pos[p] = to;
|
||||
g->king_touched[p] = true;
|
||||
} else if (from == TILE('A', 7)) {
|
||||
} else if (from == TILE('A', 8)) {
|
||||
g->a_rook_touched[0] = true;
|
||||
} else if (from == TILE('A', 0)) {
|
||||
} else if (from == TILE('A', 1)) {
|
||||
g->a_rook_touched[1] = true;
|
||||
} else if (from == TILE('H', 0)) {
|
||||
} else if (from == TILE('H', 1)) {
|
||||
g->h_rook_touched[0] = true;
|
||||
} else if (from == TILE('H', 7)) {
|
||||
} else if (from == TILE('H', 8)) {
|
||||
g->h_rook_touched[1] = true;
|
||||
}
|
||||
|
||||
@@ -234,22 +247,57 @@ static void move(struct game_state* g, index_t from, index_t to)
|
||||
g->turns_without_captures = 0;
|
||||
}
|
||||
|
||||
if (piece_abs(g->board[from]) == KING) {
|
||||
switch (to) {
|
||||
case TILE('G', 1):
|
||||
g->board[TILE('E', 1)] = EMPTY;
|
||||
g->board[TILE('F', 1)] = ROOK;
|
||||
g->board[TILE('G', 1)] = KING;
|
||||
g->board[TILE('H', 1)] = EMPTY;
|
||||
break;
|
||||
case TILE('C', 1):
|
||||
g->board[TILE('A', 1)] = EMPTY;
|
||||
g->board[TILE('B', 1)] = EMPTY;
|
||||
g->board[TILE('C', 1)] = KING;
|
||||
g->board[TILE('D', 1)] = ROOK;
|
||||
g->board[TILE('E', 1)] = EMPTY;
|
||||
break;
|
||||
case TILE('G', 8):
|
||||
g->board[TILE('E', 8)] = EMPTY;
|
||||
g->board[TILE('F', 8)] = ROOK;
|
||||
g->board[TILE('G', 8)] = KING;
|
||||
g->board[TILE('H', 8)] = EMPTY;
|
||||
break;
|
||||
case TILE('C', 8):
|
||||
g->board[TILE('A', 8)] = EMPTY;
|
||||
g->board[TILE('B', 8)] = EMPTY;
|
||||
g->board[TILE('C', 8)] = KING;
|
||||
g->board[TILE('D', 8)] = ROOK;
|
||||
g->board[TILE('E', 8)] = EMPTY;
|
||||
break;
|
||||
default:
|
||||
g->board[to] = g->board[from];
|
||||
g->board[from] = EMPTY;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
g->board[to] = g->board[from];
|
||||
g->board[from] = EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
static bitmap_t pawn_threatmap(struct game_state* g, index_t index)
|
||||
{
|
||||
index_t direction = -1 * piece_color(g->board[index]);
|
||||
index_t left = BIT(index + ROW*direction - 1);
|
||||
index_t right = BIT(index + ROW*direction + 1);
|
||||
const index_t direction = piece_color(g->board[index]);
|
||||
const index_t left = BIT(index + ROW*direction - 1);
|
||||
const index_t right = BIT(index + ROW*direction + 1);
|
||||
|
||||
if (column(index) == 7)
|
||||
return left;
|
||||
|
||||
if (column(index) == 0)
|
||||
if (column(index) == column(TILE('A', 1)))
|
||||
return right;
|
||||
|
||||
if (column(index) == column(TILE('H', 1)))
|
||||
return left;
|
||||
|
||||
return left | right;
|
||||
}
|
||||
|
||||
@@ -345,8 +393,10 @@ static bitmap_t knight_threatmap(index_t index)
|
||||
for (size_t i = 0; i < N_ELEMS(knight_wheel); i += 2) {
|
||||
index_t atks = index + knight_wheel[i] + knight_wheel[i+1] * ROW;
|
||||
|
||||
if (column(index) + knight_wheel[i] < 0 || column(index) + knight_wheel[i] > 7
|
||||
|| row(index) + knight_wheel[i+1] < 0 || row(index) + knight_wheel[i+1] > 7)
|
||||
if (column(index) + knight_wheel[i] < 0
|
||||
|| column(index) + knight_wheel[i] > 7
|
||||
|| row(index) + knight_wheel[i+1] < 0
|
||||
|| row(index) + knight_wheel[i+1] > 7)
|
||||
continue;
|
||||
|
||||
threatened |= BIT(atks);
|
||||
@@ -357,33 +407,40 @@ static bitmap_t knight_threatmap(index_t index)
|
||||
|
||||
static bitmap_t king_threatmap(index_t index)
|
||||
{
|
||||
if (row(index) == 0 && column(index) == 0) {
|
||||
// I fucking hate this function so much
|
||||
if (row(index) == 0) {
|
||||
if (column(index) == 0) {
|
||||
return BIT(index+1) | BIT(index+ROW+1) | BIT (index+ROW);
|
||||
}
|
||||
else if (row(index) == 0 && column(index) == 7) {
|
||||
else if (column(index) == 7) {
|
||||
return BIT(index-1) | BIT(index+ROW-1) | BIT (index+ROW);
|
||||
}
|
||||
else if (row(index) == 7 && column(index) == 0) {
|
||||
return BIT(index+1) | BIT(index-ROW+1) | BIT (index-ROW);
|
||||
}
|
||||
else if (row(index) == 7 && column(index) == 7) {
|
||||
return BIT(index-1) | BIT(index-ROW-1) | BIT (index-ROW);
|
||||
}
|
||||
else if (row(index) == 0) {
|
||||
else {
|
||||
return BIT(index-1) | BIT(index+1) | BIT(index+ROW-1) | BIT(index+ROW) | BIT(index+ROW+1);
|
||||
}
|
||||
else if (row(index) == 7) {
|
||||
}
|
||||
if (row(index) == 7) {
|
||||
if (column(index) == 0) {
|
||||
return BIT(index+1) | BIT(index-ROW+1) | BIT (index-ROW);
|
||||
}
|
||||
else if (column(index) == 7) {
|
||||
return BIT(index-1) | BIT(index-ROW-1) | BIT (index-ROW);
|
||||
}
|
||||
else {
|
||||
return BIT(index-1) | BIT(index+1) | BIT(index-ROW-1) | BIT(index-ROW) | BIT(index-ROW+1);
|
||||
}
|
||||
else if (column(index) == 0) {
|
||||
} else {
|
||||
if (column(index) == 0) {
|
||||
return BIT(index-ROW) | BIT(index-ROW+1) | BIT(index+1) | BIT(index+ROW+1) | BIT(index+ROW);
|
||||
}
|
||||
else if (column(index) == 7) {
|
||||
return BIT(index-ROW) | BIT(index-ROW-1) | BIT(index-1) | BIT(index+ROW-1) | BIT(index+ROW);
|
||||
}
|
||||
} else {
|
||||
return BIT(index-ROW-1) | BIT(index-ROW) | BIT(index-ROW+1)
|
||||
| BIT(index-1) | BIT(index+1)
|
||||
| BIT(index+ROW-1) | BIT(index+ROW) | BIT(index+ROW+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bitmap_t queen_threatmap(struct game_state* g, index_t index)
|
||||
@@ -393,16 +450,17 @@ static inline bitmap_t queen_threatmap(struct game_state* g, index_t index)
|
||||
|
||||
static void print_threatmap(bitmap_t threatmap)
|
||||
{
|
||||
for (size_t i = 0; i < 64; i++) {
|
||||
putc(' ', stdout);
|
||||
|
||||
if (i % 8 == 0)
|
||||
for (ssize_t i=7; i >= 0; i--) {
|
||||
fputc('\n', stdout);
|
||||
if (threatmap & BIT(i))
|
||||
for (size_t j = 0; j < 8; j++) {
|
||||
fputc(' ', stdout);
|
||||
if (threatmap & BIT(i*ROW+j))
|
||||
fputc('x', stdout);
|
||||
else
|
||||
fputc('-', stdout);
|
||||
}
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
static bitmap_t piece_threatmap(struct game_state* g, index_t index)
|
||||
@@ -430,7 +488,6 @@ static bitmap_t piece_threatmap(struct game_state* g, index_t index)
|
||||
static bitmap_t threatmap(struct game_state* g, int attacker)
|
||||
{
|
||||
bitmap_t threatened = 0;
|
||||
|
||||
for(index_t i = 0; i < BOARD_SIZE; i++) {
|
||||
if (friends(g->board[i], attacker)) {
|
||||
threatened |= piece_threatmap(g, i);
|
||||
@@ -442,33 +499,53 @@ static bitmap_t threatmap(struct game_state* g, int attacker)
|
||||
|
||||
static bool pawn_move_ok(struct game_state* g, index_t from, index_t to)
|
||||
{
|
||||
const index_t direction = -1 * piece_color(g->board[from]);
|
||||
const index_t direction = piece_color(g->board[from]);
|
||||
const index_t diff = (to - from) * direction;
|
||||
|
||||
//printf("\n");
|
||||
|
||||
switch (diff) {
|
||||
case ROW: /* single move */
|
||||
//if (!(g->board[to] == EMPTY)) {
|
||||
// printf("pawn must move to empty tile, ");
|
||||
//}
|
||||
return g->board[to] == EMPTY;
|
||||
|
||||
case ROW - COL: /* diagonal attack */
|
||||
case ROW + COL:
|
||||
//if (!(enemies(g->board[to], g->board[from]))) {
|
||||
// printf("pawn can't take its own pieces, ");
|
||||
//}
|
||||
return enemies(g->board[to], g->board[from]);
|
||||
|
||||
case 2 * ROW: /* double move */
|
||||
//if (!( g->board[to] == EMPTY)) {
|
||||
// printf("pawn must move to empty piece, ");
|
||||
//}
|
||||
//if (!( g->board[from + ROW * direction] == EMPTY)) {
|
||||
// printf("pawn can't jump over piece, ");
|
||||
//}
|
||||
//if (!( (row(from) == 1 || row(from) == 6))) {
|
||||
// printf("pawn can only move two steps from its starting row, ");
|
||||
//}
|
||||
//printf("\n");
|
||||
return g->board[to] == EMPTY
|
||||
&& g->board[from + ROW * direction] == EMPTY
|
||||
&& (row(from) == 1 || row(from) == 6);
|
||||
|
||||
default: /* any other move is illegal */
|
||||
//printf("pawn move is generally illegal, ");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool king_move_ok(struct game_state* g, index_t from, index_t to)
|
||||
{
|
||||
// castling is implemented as a separate function, invoked by O-O or O-O-O
|
||||
// castling check is implemented as a separate function
|
||||
return BIT(to) & king_threatmap(from)
|
||||
&& BIT(to) & ~threatmap(g, -piece_color(g->board[from]));
|
||||
}
|
||||
|
||||
bool is_check(struct game_state* g, int player)
|
||||
{
|
||||
return BIT(g->king_pos[player == WHITE ? 0 : 1]) & threatmap(g, -player);
|
||||
@@ -480,15 +557,21 @@ static bool castle_ok(struct game_state* g, int player, enum castle_type t)
|
||||
return false;
|
||||
}
|
||||
const int p = player == WHITE ? 0 : 1;
|
||||
const int row = ROW * (player == WHITE ? 7 : 0);
|
||||
const int row = (player == WHITE ? 1 : 8);
|
||||
|
||||
if (t == CASTLE_KINGSIDE) {
|
||||
return g->h_rook_touched[p] == false
|
||||
&& g->king_touched[p] == false
|
||||
&& threatmap(g, -player) & (BIT(TILE('F', row)) | BIT(TILE('G', row)));
|
||||
&& ~threatmap(g, -player) & (BIT(TILE('F', row)) | BIT(TILE('G', row)))
|
||||
&& g->board[TILE('G', row)] == EMPTY
|
||||
&& g->board[TILE('F', row)] == EMPTY;
|
||||
} else if (t == CASTLE_QUEENSIDE) {
|
||||
return g->a_rook_touched[p] == false
|
||||
&& g->king_touched[p] == false
|
||||
&& threatmap(g, -player) & (BIT(TILE('C', row)) | BIT(TILE('D', row)));
|
||||
&& ~threatmap(g, -player) & (BIT(TILE('C', row)) | BIT(TILE('D', row)))
|
||||
&& g->board[TILE('B', row)] == EMPTY
|
||||
&& g->board[TILE('C', row)] == EMPTY
|
||||
&& g->board[TILE('D', row)] == EMPTY;
|
||||
}
|
||||
|
||||
fprintf(stderr, "invalid castle_type passed to %s", __func__);
|
||||
@@ -500,8 +583,9 @@ bool move_ok(struct game_state* g, index_t from, index_t to, int player)
|
||||
{
|
||||
/* Player must own piece it moves
|
||||
and a player can't capture their own pieces. */
|
||||
if (enemies(player, g->board[from]) || friends(player, g->board[to]))
|
||||
if (enemies(player, g->board[from]) || friends(player, g->board[to])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool move_ok = false;;
|
||||
|
||||
@@ -530,12 +614,11 @@ bool move_ok(struct game_state* g, index_t from, index_t to, int player)
|
||||
return false;
|
||||
}
|
||||
|
||||
// pretend move was done and check if king is checked after
|
||||
unsigned char restore[sizeof *g];
|
||||
memcpy(restore, g, sizeof *g);
|
||||
typeof(*g) restore = *g;
|
||||
move(g, from, to);
|
||||
bool bad = is_check(g, player);
|
||||
memcpy(g, restore, sizeof *g);
|
||||
*g = restore;
|
||||
//memcpy(g, &restore, sizeof restore);
|
||||
|
||||
if (bad) {
|
||||
return false;
|
||||
@@ -586,51 +669,49 @@ static void game_init(struct game_state* g)
|
||||
// clang-format off
|
||||
#if 1
|
||||
static const piece_t start[BOARD_SIZE] = {
|
||||
-ROOK, -KNIGHT,-BISHOP,-QUEEN, -KING, -BISHOP,-KNIGHT,-ROOK,
|
||||
-PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
|
||||
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
|
||||
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
-PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN, -PAWN,
|
||||
-ROOK, -KNIGHT,-BISHOP,-QUEEN, -KING, -BISHOP,-KNIGHT,-ROOK,
|
||||
};
|
||||
// clang-format on
|
||||
#else
|
||||
static const piece_t start[BOARD_SIZE] = {
|
||||
-ROOK, -KNIGHT,-BISHOP,-QUEEN, -KING, -BISHOP,-KNIGHT,-ROOK,
|
||||
-PAWN, -PAWN, -PAWN, -PAWN, -PAWN, QUEEN, -PAWN, -PAWN,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, ROOK, EMPTY, EMPTY,
|
||||
ROOK, EMPTY, EMPTY, EMPTY, KING, EMPTY, EMPTY, ROOK,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
|
||||
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
|
||||
EMPTY, EMPTY, EMPTY, EMPTY, -KING, EMPTY, EMPTY, EMPTY,
|
||||
};
|
||||
#endif
|
||||
|
||||
memset(g, 0, sizeof *g);
|
||||
memcpy(g->board, start, sizeof start);
|
||||
|
||||
g->king_pos[0] = 60;
|
||||
g->king_pos[1] = 4;
|
||||
g->king_pos[0] = TILE('E', 1);
|
||||
g->king_pos[1] = TILE('E', 8);
|
||||
}
|
||||
|
||||
static index_t input_to_index(char input[2])
|
||||
{
|
||||
const char col = toupper(input[0]);
|
||||
const char row = toupper(input[1]);
|
||||
const char row = input[1];
|
||||
|
||||
if (col < 'A' || col > 'H' || row < '1' || row > '8')
|
||||
return -1;
|
||||
|
||||
const int x = col - 'A';
|
||||
const int y = row - '1';
|
||||
return 8 * (7 - y) + x;
|
||||
return TILE(col, row - '0');
|
||||
}
|
||||
|
||||
// TODO: Implement algebaric notation
|
||||
static int do_turn(int turn_no, struct game_state* g)
|
||||
static int player_move(int turn_no, struct game_state* g)
|
||||
{
|
||||
char input[3] = { 0 };
|
||||
|
||||
@@ -645,7 +726,7 @@ static int do_turn(int turn_no, struct game_state* g)
|
||||
if (from == -1)
|
||||
return 0;
|
||||
|
||||
print_threatmap(valid_moves(g, g->king_pos[turn_no % 2], turn_no % 2 ? BLACK : WHITE));
|
||||
print_threatmap(valid_moves(g, from, turn_no % 2 ? BLACK : WHITE));
|
||||
printf("\nto: ");
|
||||
scanf(" %2s", input);
|
||||
|
||||
@@ -675,7 +756,11 @@ static double heuristic(struct game_state* g, int player)
|
||||
const piece_t piece = g->board[i];
|
||||
const int player = piece_color(piece);
|
||||
const piece_t type = piece_abs(piece);
|
||||
if (player == WHITE) {
|
||||
score += player * piece_value[type] * piece_position_bonus[type][i];
|
||||
} else {
|
||||
score += player * piece_value[type] * piece_position_bonus[type][BOARD_SIZE-i-1];
|
||||
}
|
||||
}
|
||||
return score;
|
||||
}
|
||||
@@ -689,15 +774,22 @@ static void print_debug(struct game_state* g, int player)
|
||||
// bool h_rook_touched[2];
|
||||
// bool king_touched[2];
|
||||
//};
|
||||
static const char * const bool_str[2] = {"False", "True"};
|
||||
|
||||
printf("White A king touched: %s\n", bool_str[g->king_touched[0]]);
|
||||
printf("White A rook touched: %s\n", bool_str[g->a_rook_touched[0]]);
|
||||
printf("White H rook touched: %s\n", bool_str[g->h_rook_touched[0]]);
|
||||
printf("White can king side castle: %s\n", bool_str[castle_ok(g, WHITE, CASTLE_KINGSIDE)]);
|
||||
printf("White can queen side castle: %s\n", bool_str[castle_ok(g, WHITE, CASTLE_QUEENSIDE)]);
|
||||
printf("White king pos: %c%ld\n", 'A'+((char)column(g->king_pos[0])), 1+row(g->king_pos[0]));
|
||||
|
||||
//printf("Black A king touched: %s\n", bool_str[g->king_touched[1]]);
|
||||
//printf("Black A rook touched: %s\n", bool_str[g->a_rook_touched[1]]);
|
||||
//printf("Black H rook touched: %s\n", bool_str[g->h_rook_touched[1]]);
|
||||
//printf("Black can king side castle: %s\n", bool_str[castle_ok(g, BLACK, CASTLE_KINGSIDE)]);
|
||||
//printf("Black can queen side castle: %s\n", bool_str[castle_ok(g, BLACK, CASTLE_QUEENSIDE)]);
|
||||
//printf("Black king pos: %c%ld\n", 'A'+((char)column(g->king_pos[1])), 1+row(g->king_pos[1]));
|
||||
|
||||
printf("White king pos: %c%ld\n", 'A'+((char)column(g->king_pos[0])), 8-row(g->king_pos[0]));
|
||||
printf("Black king pos: %c%ld\n", 'A'+((char)column(g->king_pos[1])), 8-row(g->king_pos[1]));
|
||||
printf("White A king touched: %s\n", g->king_touched[0] ? "True" : "False");
|
||||
printf("Black A king touched: %s\n", g->king_touched[1] ? "True" : "False");
|
||||
printf("White A rook touched: %s\n", g->a_rook_touched[0] ? "True" : "False");
|
||||
printf("Black A rook touched: %s\n", g->a_rook_touched[1] ? "True" : "False");
|
||||
printf("White H rook touched: %s\n", g->h_rook_touched[0] ? "True" : "False");
|
||||
printf("Black H rook touched: %s\n", g->h_rook_touched[1] ? "True" : "False");
|
||||
printf("Turns with no capture: %d\n", g->turns_without_captures);
|
||||
printf("Estimated score: %lf\n", heuristic(g, player));
|
||||
}
|
||||
@@ -774,8 +866,19 @@ int main()
|
||||
|
||||
game_init(&state);
|
||||
|
||||
#if 0
|
||||
board_paint(&state);
|
||||
print_debug(&state, WHITE);
|
||||
printf("white threatmap:\n");
|
||||
print_threatmap(threatmap(&state, WHITE));
|
||||
printf("black threatmap:\n");
|
||||
print_threatmap(threatmap(&state, BLACK));
|
||||
}
|
||||
#else
|
||||
|
||||
int turn = 0;
|
||||
int player = WHITE;
|
||||
bool player_intervention = false;
|
||||
|
||||
while (true) {
|
||||
print_debug(&state, player);
|
||||
@@ -784,15 +887,15 @@ int main()
|
||||
|
||||
if (is_check(&state, player)) {
|
||||
printf("%s in check!\n", player == WHITE ? "White" : "Black");
|
||||
//print_threatmap(piece_threatmap(&state, state.king_pos[player == WHITE ? 0 : 1]));
|
||||
print_threatmap(piece_threatmap(&state, state.king_pos[player == WHITE ? 0 : 1]));
|
||||
}
|
||||
|
||||
bool player_intervention = false;
|
||||
|
||||
if (player_intervention) {
|
||||
intervene:
|
||||
while (do_turn(turn, &state) == 0)
|
||||
/*noop*/;
|
||||
intervene:
|
||||
while (player_move(turn, &state) == 0) {
|
||||
printf("Valid moves for %s:\n", player == WHITE ? "white" : "black");
|
||||
print_threatmap(valid_moves(&state, state.king_pos[player == WHITE ? 0 : 1], player));
|
||||
}
|
||||
} else {
|
||||
printf("thinking...\n");
|
||||
index_t from = -1, to = -1;
|
||||
@@ -801,13 +904,13 @@ intervene:
|
||||
printf("computer couldn't think, starting player intervention\n");
|
||||
printf("Valid moves for %s:\n", player == WHITE ? "white" : "black");
|
||||
print_threatmap(valid_moves(&state, state.king_pos[player == WHITE ? 0 : 1], player));
|
||||
printf("\nThreatened pieces\n");
|
||||
printf("\nThreatened pieces by %s\n", -player == WHITE ? "white" : "black");
|
||||
print_threatmap(threatmap(&state, -player));
|
||||
player_intervention = true;
|
||||
goto intervene;
|
||||
}
|
||||
move(&state, from, to);
|
||||
printf("Did %c%ld to %c%ld\n", (char)('A'+column(from)), 8-row(from), (char)('A'+column(to)), 8-row(to));
|
||||
printf("Did %c%ld to %c%ld\n", (char)('A'+column(from)), 1+row(from), (char)('A'+column(to)), 1+row(to));
|
||||
}
|
||||
|
||||
turn += 1;
|
||||
@@ -831,4 +934,4 @@ intervene:
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user