#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <cii/assert.h>
#include <cii/mem.h>
#include "CBoard.h"
#include "attack.h"
#include "utils.h"
// piece representation
struct Piece_T {
ePiece piece;
eColor color;
char code;
char asci;
char *unicode;
attack_f attacks;
};
attack_f Piece_attacks(Piece_T pt) { return pt->attacks; }
char Piece_asci(Piece_T pt) { return pt->asci; }
char Piece_code(Piece_T pt) { return pt->code; }
char *Piece_unicode(Piece_T pt) { return pt->unicode; }
eColor Piece_color(Piece_T pt) { return pt->color; }
ePiece Piece_piece(Piece_T pt) { return pt->piece; }
int Piece_index(Piece_T self) { return self->color * 8 + self->piece; }
// Pieces table [color][piece]
// clang-format off
struct Piece_T Pieces[2][6] = {
{
{.color = WHITE, .code = 'P', .asci = 'P', .unicode = "♙ ", .piece = PAWN, .attacks = get_wpawn_attacks},
{.color = WHITE, .code = 'N', .asci = 'N', .unicode = "♘ ", .piece = KNIGHT, .attacks = get_knight_attacks},
{.color = WHITE, .code = 'B', .asci = 'B', .unicode = "♗ ", .piece = BISHOP, .attacks = get_bishop_attacks},
{.color = WHITE, .code = 'R', .asci = 'R', .unicode = "♖ ", .piece = ROOK, .attacks = get_rook_attacks},
{.color = WHITE, .code = 'Q', .asci = 'Q', .unicode = "♕ ", .piece = QUEEN, .attacks = get_queen_attacks},
{.color = WHITE, .code = 'K', .asci = 'K', .unicode = "♔ ", .piece = KING, .attacks = get_king_attacks},
},
{
{.color = BLACK, .code = 'p', .asci = 'p', .unicode = "♟ ", .piece = PAWN, .attacks = get_bpawn_attacks},
{.color = BLACK, .code = 'n', .asci = 'n', .unicode = "♞ ", .piece = KNIGHT, .attacks = get_knight_attacks},
{.color = BLACK, .code = 'b', .asci = 'b', .unicode = "♝ ", .piece = BISHOP, .attacks = get_bishop_attacks},
{.color = BLACK, .code = 'r', .asci = 'r', .unicode = "♜ ", .piece = ROOK, .attacks = get_rook_attacks},
{.color = BLACK, .code = 'q', .asci = 'q', .unicode = "♛ ", .piece = QUEEN, .attacks = get_queen_attacks},
{.color = BLACK, .code = 'k', .asci = 'k', .unicode = "♚ ", .piece = KING, .attacks = get_king_attacks},
},
};
// clang-format on
Piece_T Piece_fromCode(char code) {
int color = (isupper(code)) ? WHITE : BLACK;
for (int i = 0; i < 6; i++)
if (Pieces[color][i].code == code)
return &Pieces[color][i];
return NULL;
}
Piece_T Piece_fromIndex(int index) { return &Pieces[index / 8][index % 8]; }
Piece_T Piece_get(ePiece piece, eColor color) { return &Pieces[color][piece]; }
// board representation
struct CBoard_T {
U64 colorBB[2];
U64 pieceBB[6];
eColor side;
Square enpassant;
eCastle castle;
};
U64 CBoard_colorBB(CBoard_T self, eColor color) { return self->colorBB[color]; }
U64 CBoard_pieceBB(CBoard_T self, ePiece piece) { return self->pieceBB[piece]; }
eColor CBoard_side(CBoard_T self) { return self->side; }
Square CBoard_enpassant(CBoard_T self) { return self->enpassant; }
eCastle CBoard_castle(CBoard_T self) { return self->castle; }
U64 CBoard_getPieceSet(CBoard_T self, Piece_T piece) {
return self->pieceBB[Piece_piece(piece)] & self->colorBB[Piece_color(piece)];
}
CBoard_T CBoard_new(void) {
CBoard_T p;
NEW0(p);
return p;
}
void CBoard_copy(CBoard_T self, CBoard_T dest) { *dest = *self; }
void CBoard_enpassant_set(CBoard_T self, Square target) {
self->enpassant = target;
}
void CBoard_colorBB_pop(CBoard_T self, eColor color, Square target) {
bit_pop(self->colorBB[color], target);
}
void CBoard_colorBB_set(CBoard_T self, eColor color, Square target) {
bit_set(self->colorBB[color], target);
}
U64 CBoard_colorBB_get(CBoard_T self, eColor color, Square target) {
return bit_get(self->colorBB[color], target);
}
void CBoard_pieceBB_pop(CBoard_T self, ePiece piece, Square target) {
bit_pop(self->pieceBB[piece], target);
}
void CBoard_pieceBB_set(CBoard_T self, ePiece piece, Square target) {
bit_set(self->pieceBB[piece], target);
}
U64 CBoard_pieceBB_get(CBoard_T self, ePiece piece, Square target) {
return bit_get(self->pieceBB[piece], target);
}
void CBoard_piece_pop(CBoard_T self, Piece_T Piece, Square square) {
bit_pop(self->pieceBB[Piece->piece], square);
bit_pop(self->colorBB[Piece->color], square);
}
void CBoard_piece_set(CBoard_T self, Piece_T Piece, Square square) {
bit_set(self->pieceBB[Piece->piece], square);
bit_set(self->colorBB[Piece->color], square);
}
void CBoard_piece_move(CBoard_T self, Piece_T Piece, Square source,
Square target) {
CBoard_piece_pop(self, Piece, source);
CBoard_piece_set(self, Piece, target);
}
void CBoard_castle_pop(CBoard_T self, eCastle castle) {
bit_pop(self->castle, bit_lsb_index(castle));
}
void CBoard_castle_and(CBoard_T self, int exp) { self->castle &= exp; }
void CBoard_side_switch(CBoard_T self) { self->side = !self->side; }
int CBoard_isCheck(CBoard_T self) {
U64 king = self->pieceBB[KING] & self->colorBB[self->side];
return CBoard_square_isAttack(self, bit_lsb_index(king), !self->side);
}
int CBoard_square_isAttack(CBoard_T self, Square square, eColor side) {
U64 occupancy = self->colorBB[WHITE] | self->colorBB[BLACK];
for (int i = 0; i < 6; i++) {
if (Pieces[!side][i].attacks(square, occupancy) & self->pieceBB[i] &
self->colorBB[side])
return 1;
}
return 0;
}
void CBoard_print(CBoard_T self) {
for (int rank = 0; rank < 8; rank++) {
for (int file = 0; file < 8; file++) {
Square square = (7 - rank) * 8 + file;
Piece_T piece = NULL;
int color = -1;
if (bit_get(self->colorBB[WHITE], square))
color = WHITE;
else if (bit_get(self->colorBB[BLACK], square))
color = BLACK;
if (color != -1) {
for (int piece_index = 0; piece_index < 6; piece_index++) {
if (bit_get(self->pieceBB[piece_index], square)) {
piece = &Pieces[color][piece_index];
break;
}
}
}
if (!file)
printf(" %d ", 8 - rank);
printf("%s", (piece) ? Piece_unicode(piece) : ". ");
}
printf("\n");
}
printf(" A B C D E F G H\n");
printf(" Side: %s\n", (self->side == WHITE) ? "white" : "black");
printf("Enpassant: %s\n", square_to_coordinates[self->enpassant]);
printf(" Castling: %c%c%c%c\n", (self->castle & WK) ? 'K' : '-',
(self->castle & WQ) ? 'Q' : '-', (self->castle & BK) ? 'k' : '-',
(self->castle & BQ) ? 'q' : '-');
printf("\n");
}
CBoard_T CBoard_fromFEN(CBoard_T board, char *fen) {
if (!board)
NEW(board);
memset(board, C64(0), sizeof(*board));
board->side = -1;
board->enpassant = no_sq;
board->castle = 0;
int file = 0, rank = 7;
for (Piece_T piece; *fen != ' '; fen++) {
Square square = rank * 8 + file;
if (isalpha(*fen)) {
if (!(piece = Piece_fromCode(*fen)))
assert(0);
bit_set(board->colorBB[piece->color], square);
bit_set(board->pieceBB[piece->piece], square);
file++;
} else if (isdigit(*fen)) {
file += *fen - '0';
} else if (*fen == '/') {
file = 0;
rank--;
} else
assert(0);
}
fen++;
if (*fen == 'w')
board->side = WHITE;
else if (*fen == 'b')
board->side = BLACK;
else
assert(0);
for (fen += 2; *fen != ' '; fen++) {
switch (*fen) {
case 'K': board->castle |= WK; break;
case 'Q': board->castle |= WQ; break;
case 'k': board->castle |= BK; break;
case 'q': board->castle |= BQ; break;
case '-': break;
default: assert(0);
}
}
fen++;
if (*fen != '-') {
board->enpassant = (*(fen + 1) - '1') * 8 + (*fen - 'a');
}
return board;
}