/* position.c - position management. * * Copyright (C) 2021 Bruno Raoult ("br") * Licensed under the GNU General Public License v3.0 or later. * Some rights reserved. See COPYING. * * You should have received a copy of the GNU General Public License along with this * program. If not, see . * * SPDX-License-Identifier: GPL-3.0-or-later * */ #include #include #include #include #include #include "chessdefs.h" #include "position.h" #include "move.h" #include "fen.h" #include "piece.h" #include "eval.h" static pool_t *pos_pool; #define BYTE_PRINT "%c%c%c%c%c%c%c%c" #define BYTE2BIN(b) ((b) & 0x01 ? '1' : '0'), \ ((b) & 0x02 ? '1' : '0'), \ ((b) & 0x04 ? '1' : '0'), \ ((b) & 0x08 ? '1' : '0'), \ ((b) & 0x10 ? '1' : '0'), \ ((b) & 0x20 ? '1' : '0'), \ ((b) & 0x40 ? '1' : '0'), \ ((b) & 0x80 ? '1' : '0') inline void bitboard_print(bitboard_t bb) { int i; printf("%#018lx\n", bb); for (i=56; i>=0; i-=8) printf("\t"BYTE_PRINT"\n", BYTE2BIN(bb>>i)); } inline void bitboard_print2(bitboard_t bb1, bitboard_t bb2) { int i; printf("\tW: %#018lx\tB: %#018lx\n", bb1, bb2); for (i=56; i>=0; i-=8) printf("\t"BYTE_PRINT"\t\t"BYTE_PRINT"\n", BYTE2BIN(bb1>>i), BYTE2BIN(bb2>>i)); } /** * pos_pieces_print() - Print position pieces * @pos: &position */ void pos_pieces_print(pos_t *pos) { printf("White pieces (%d): \t", popcount64(pos->occupied[WHITE])); piece_list_print(&pos->pieces[WHITE]); printf("Black pieces (%d): \t", popcount64(pos->occupied[BLACK])); piece_list_print(&pos->pieces[BLACK]); } /** * pos_bitboards_print() - Print position bitboards * @pos: &position */ void pos_bitboards_print(pos_t *pos) { printf("Bitboards occupied :\n"); bitboard_print2(pos->occupied[WHITE], pos->occupied[BLACK]); printf("Bitboards controlled :\n"); bitboard_print2(pos->controlled[WHITE], pos->controlled[BLACK]); } /** * pos_print() - Print position on stdout. * @pos: &position */ void pos_print(pos_t *pos) { int rank, file; piece_t piece; board_t *board = pos->board; piece_list_t *wk = list_first_entry(&pos->pieces[WHITE], piece_list_t, list), *bk = list_first_entry(&pos->pieces[BLACK], piece_list_t, list); printf(" +---+---+---+---+---+---+---+---+\n"); for (rank = 7; rank >= 0; --rank) { printf("%c |", rank + '1'); for (file = 0; file < 8; ++file) { piece = board[SQ88(file, rank)].piece; printf(" %s |", P_CSYM(piece)); } printf("\n +---+---+---+---+---+---+---+---+\n"); } printf(" A B C D E F G H\n\n"); printf("Turn: %s.\n", IS_WHITE(pos->turn) ? "white" : "black"); printf("Kings: W:%c%c B:%c%c\n", FILE2C(F88(wk->square)), RANK2C(R88(wk->square)), FILE2C(F88(bk->square)), RANK2C(R88(bk->square))); printf("Possible en-passant: [%#x] ", pos->en_passant); if (pos->en_passant == 0) printf("None.\n"); else printf("%d %d = %c%c\n", F88(pos->en_passant), R88(pos->en_passant), FILE2C(F88(pos->en_passant)), RANK2C(R88(pos->en_passant))); printf("castle [%#x] : ", pos->castle); if (pos->castle & CASTLE_WK) printf("K"); if (pos->castle & CASTLE_WQ) printf("Q"); if (pos->castle & CASTLE_BK) printf("k"); if (pos->castle & CASTLE_BQ) printf("q"); printf("\n50 half-moves-rule = %d\n", pos->clock_50); printf("Current move = %d\n", pos->curmove); printf("Squares controlled: W:%d B:%d\n", popcount64(pos->controlled[WHITE]), popcount64(pos->controlled[BLACK])); printf("Mobility: W:%u B:%u\n", pos->mobility[WHITE], pos->mobility[BLACK]); } /** * pos_check() - extensive position consistenci check. * @pos: &position */ void pos_check(pos_t *pos) { int rank, file; piece_t piece; board_t *board = pos->board; /* check that board and bitboard reflect same information */ for (rank = 7; rank >= 0; --rank) { for (file = 0; file < 8; ++file) { piece_list_t *ppiece; printf("checking %c%c ", file+'a', rank+'1'); piece = board[SQ88(file, rank)].piece; ppiece= board[SQ88(file, rank)].s_piece; printf("piece=%s ", P_CSYM(piece)); if (ppiece) printf("ppiece=%s/sq=%#x ", P_CSYM(ppiece->piece), ppiece->square); switch(PIECE(piece)) { case PAWN: printf("pawn" ); break; case KNIGHT: printf("knight "); break; case BISHOP: printf("bishop "); break; case ROOK: printf("rook "); break; case QUEEN: printf("queen "); break; case KING: printf("king "); break; } printf("\n"); } } } pos_t *pos_clear(pos_t *pos) { int file, rank; board_t *board = pos->board; for (file = 0; file < 8; ++file) { for (rank = 0; rank < 8; ++rank) { /*printf("file = %d rank = %d SQ88 = %#2x = %d addr=%p\n", file, rank, SQ88(file, rank), SQ88(file, rank), &board[SQ88(file, rank)].piece); */ board[SQ88(file, rank)].piece = EMPTY; } } SET_WHITE(pos->turn); pos->node_count = 0; pos->castle = 0; pos->clock_50 = 0; pos->curmove = 0; pos->eval = 0; pos->en_passant = 0; pos->occupied[WHITE] = 0; pos->occupied[BLACK] = 0; for (int color=0; color<2; ++color) for (int piece = BB_ALL; piece < BB_END; ++piece) pos->bb[color][piece] = 0; pos->controlled[WHITE] = 0; pos->controlled[BLACK] = 0; pos->mobility[WHITE] = 0; pos->mobility[BLACK] = 0; pos->moves_generated = false; pos->moves_counted = false; /* remove pieces / moves */ pieces_del(pos, WHITE); pieces_del(pos, BLACK); moves_del(pos); return pos; } /** * pos_del() - delete a position. * @pos: &position. */ void pos_del(pos_t *pos) { pieces_del(pos, WHITE); pieces_del(pos, BLACK); moves_del(pos); pool_add(pos_pool, pos); } pos_t *pos_startpos(pos_t *pos) { static char *startfen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; return fen2pos(pos, startfen); } pos_t *pos_get() { pos_t *pos = pool_get(pos_pool); if (pos) { INIT_LIST_HEAD(&pos->pieces[WHITE]); INIT_LIST_HEAD(&pos->pieces[BLACK]); INIT_LIST_HEAD(&pos->moves[WHITE]); INIT_LIST_HEAD(&pos->moves[BLACK]); pos_clear(pos); } else { fprintf(stderr, "zobaaa\n"); } return pos; } /** * pos_dup() - duplicate a position. * @pos: &position to duplicate. * * New position is the same as source one (with duplicated pieces list), * except: * - moves list is empty * - bestmove is NULL * - nodecount is set to zero * - eval is set to EVAL_INVALID * - moves_generated ans moves_counted are unset * - check is set to zero * * @return: The new position. * * TODO: merge with pos_get - NULL for init, non null for duplicate */ pos_t *pos_dup(pos_t *pos) { struct list_head *p_cur, *piece_list; piece_list_t *oldpiece; board_t *board; pos_t *new = pool_get(pos_pool); if (new) { board = new->board; *new = *pos; for (int color = 0; color < 2; ++color) { INIT_LIST_HEAD(&new->pieces[color]); INIT_LIST_HEAD(&new->moves[color]); /* duplicate piece list */ piece_list = &pos->pieces[color]; /* white/black piece list */ list_for_each(p_cur, piece_list) { oldpiece = list_entry(p_cur, piece_list_t, list); board[oldpiece->square].s_piece = piece_add(new, oldpiece->piece, oldpiece->square); } } new->bestmove = NULL; new->node_count = 0; new->eval = EVAL_INVALID; new->moves_generated = false; new->moves_counted = false; new->check[WHITE] = new->check[BLACK] = 0; } return new; } pool_t *pos_pool_init() { if (!pos_pool) pos_pool = pool_create("positions", 128, sizeof(pos_t)); return pos_pool; } void pos_pool_stats() { if (pos_pool) pool_stats(pos_pool); }