diff --git a/src/move.c-move-to-temp-migration-bitboard__move.c b/src/move.c-move-to-temp-migration-bitboard__move.c new file mode 100644 index 0000000..7f1d23e --- /dev/null +++ b/src/move.c-move-to-temp-migration-bitboard__move.c @@ -0,0 +1,890 @@ +/* move.c - move 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 + +#include "chessdefs.h" +#include "board.h" +#include "bitboard.h" +#include "piece.h" +#include "move.h" +#include "eval.h" +#include "eval-simple.h" + +static pool_t *moves_pool; + +static struct vector { + unsigned char ndirs; + char slide; + char dir[8]; +} vectors[] = { + [KNIGHT] = { 8, 0, { -33, -31, -18, -14, 14, 18, 31, 33 }}, + [BISHOP] = { 4, 1, { -15, -17, 15, 17 }}, + [ROOK] = { 4, 1, { -1, -16, 1, 16 }}, + [QUEEN] = { 8, 1, { -1, -16, 1, 16, -15, -17, 15, 17 }}, + [KING] = { 8, 0, { -1, -16, 1, 16, -15, -17, 15, 17 }} +}; + + +/* squares needed to be empty & not controlled by opponent for castle. + * For black castle, same values 7 rows higher (>> 7*8) + */ +static struct can_castle { + bitboard_t controlled[2]; + bitboard_t occupied[2]; +} castle_squares[2] = { + /* Queen side King side Queen side King side */ + { { C1bb|D1bb|E1bb, E1bb|F1bb|G1bb }, { B1bb|C1bb|D1bb, F1bb|G1bb } }, + { { C8bb|D8bb|E8bb, E8bb|F8bb|G8bb }, { B8bb|C8bb|D8bb, F8bb|G8bb } } +}; + +pool_t *moves_pool_init() +{ + if (!moves_pool) + moves_pool = pool_create("moves", 128, sizeof(move_t)); + return moves_pool; +} + +void moves_pool_stats() +{ + if (moves_pool) + pool_stats(moves_pool); +} + +/** + * move_print() - print a move + * @movenum: move number + * @move: &move to display + * @flags: options to display + * + * Possible flags are: + * M_PR_CAPT: print move if capture + * M_PR_NCAPT: print move if non capture + * M_PR_NUM: print also move number + * M_PR_LONG: print long notation + * M_PR_NL: print a newline after move + * M_PR_EVAL: print move eval + * + * @return: 0 if nothing printed, 1 otherwise + */ +int move_print(int movenum, move_t *move, move_flags_t flags) +{ + if ((flags & M_PR_CAPT) && !(move->flags & M_CAPTURE)) { +# ifdef DEBUG_MOVE + log_i(9, "skipping capture & %#04x\n", move->flags); +# endif + return 0; + } + if ((flags & M_PR_NCAPT) && (move->flags & M_CAPTURE)) { +# ifdef DEBUG_MOVE + log_i(9, "skipping !capture & %#04x\n", move->flags); +# endif + return 0; + } + if (flags & M_PR_NUM) + log(1, "%d:", movenum); + if (move->flags & M_CASTLE_K) { + log(1, "O-O"); + goto end; + } else if (move->flags & M_CASTLE_Q) { + log(1, "O-O-O"); + goto end; + } else { + log(1, "%s%c%c", P_SYM(move->piece), + FILE2C(F88(move->from)), + RANK2C(R88(move->from))); + if (move->flags & M_CAPTURE) { + log(1, "x"); + if (flags & M_PR_LONG) + log(1, "%s", P_SYM(move->capture)); + } else { + log(1, "-"); + } + log(1, "%c%c", + FILE2C(F88(move->to)), + RANK2C(R88(move->to))); + if (flags & M_PR_LONG && move->flags & M_EN_PASSANT) + log(1, "e.p."); + if (move->promotion) + log(1, "=%s", P_SYM(move->promotion)); + if (flags & M_PR_EVAL) + log(1, "[ev:%d] ", move->eval); + end: + log(1, " "); + } + if (flags & M_PR_NL) + log(1, "\n"); + return 1; +} + +void moves_print(pos_t *pos, move_flags_t flags) +{ + struct list_head *p_cur, *tmp; + move_t *move; + int movenum; + + for (int color=WHITE; color <= BLACK; ++color) { + int verif = 0; + log(1, "%s pseudo-moves:\n\t", color == WHITE? "White": "Black"); + if (! (flags & M_PR_SEPARATE)) { + movenum = 1; + list_for_each_safe(p_cur, tmp, &pos->moves[color]) { + move = list_entry(p_cur, move_t, list); + verif += move_print(movenum++, move, flags); + } + } else { + log(1, "captures: "); + movenum = 1; + list_for_each_safe(p_cur, tmp, &pos->moves[color]) { + move = list_entry(p_cur, move_t, list); + verif += move_print(movenum++, move, flags | M_PR_CAPT); + } + movenum = 1; + log(1, "\n\tothers : "); + list_for_each_safe(p_cur, tmp, &pos->moves[color]) { + move = list_entry(p_cur, move_t, list); + verif += move_print(movenum++, move, flags | M_PR_NCAPT); + } + } + log(1, "\n\tTotal moves = %d mobility=%u\n", verif, pos->mobility[color]); + } +} + +static move_t *move_add(pos_t *pos, piece_t piece, square_t from, + square_t to) +{ + board_t *board = pos->board; + move_t *move; + int color = COLOR(pos->board[from].piece); + +# ifdef DEBUG_MOVE + log_i(3, "piece_color=%d turn=%d from=%c%c to=%c%c\n", + color, pos->turn, + FILE2C(F88(from)), + RANK2C(R88(from)), + FILE2C(F88(to)), + RANK2C(R88(to))); +# endif + /* invalid position if opponent king is attacked + */ + if (board[to].piece & KING) { +# ifdef DEBUG_MOVE + log_i(2, "invalid position: opponent king [%c%c] is in check.\n", + FILE2C(F88(to)), RANK2C(R88(to))); +# endif + return NULL; + } + if (!(move = pool_get(moves_pool))) + return NULL; + list_add(&move->list, &pos->moves[color]); + + move->piece = piece | color; + move->from = from; + move->to = to; + move->capture = board[to].piece; + if (PIECE(move->capture) == KING) + pos->check[color]++; + + move->flags = M_NORMAL; + if (move->capture) + move->flags |= M_CAPTURE; + move->pos = NULL; +# ifdef DEBUG_MOVE + log_i(3, "added %s %s move from %c%c to %c%c\n", + COLOR(move->piece)? "black": "white", + P_NAME(PIECE(move->piece)), + FILE2C(F88(move->from)), RANK2C(R88(move->from)), + FILE2C(F88(move->to)), RANK2C(R88(move->to))); +# endif + return move; +} + +/** + * move_del() - delete a move from list. + * @ptr: move &list_head + * + * Remove the move whose 'list' element address is @ptr. + */ +void move_del(struct list_head *ptr) +{ + move_t *move = list_entry(ptr, move_t, list); + +# ifdef DEBUG_MOVE + log_i(3, "delete move from %c%c to %c%c\n", + FILE2C(F88(move->from)), RANK2C(R88(move->from)), + FILE2C(F88(move->to)), RANK2C(R88(move->to))); +# endif + + if (move->pos) + pos_del(move->pos); + list_del(ptr); + pool_add(moves_pool, move); + return; +} + +/** + * move_del() - delete all position moves. + * @ppos: &position. + * + * Remove all generated moves from @pos structure. + */ +int moves_del(pos_t *pos) +{ + struct list_head *p_cur, *tmp, *head; + int count = 0; + + for (int color = WHITE; color <= BLACK; ++color) { + head = &pos->moves[color]; + + list_for_each_safe(p_cur, tmp, head) { + move_del(p_cur); + count++; + } + } +# ifdef DEBUG_PIECE + log_f(3, "%d moves removed\n", count); +# endif + return count; +} + +/* TODO: return nmoves */ +static move_t *move_pawn_add(pos_t *pos, piece_t piece, square_t from, + square_t to, unsigned char rank7) +{ + move_t *move; + piece_t promote; + unsigned char color = COLOR(piece); + + if (R88(from) == rank7) { /* promotion */ + for (promote = QUEEN; promote > PAWN; promote >>= 1) { + if ((move = move_add(pos, piece, from, to))) { + move->flags |= M_PROMOTION; + move->promotion = promote | color; + } + } + } else { + move = move_add(pos, piece, from, to); + } + return move; +} + +/** + * pseudo_moves_pawn() - generate moves for pawn. + * @pos: &position + * @ppiece: &piece_list pawn structure pointer + * @doit: add move to moves list + * + * Calculate all possible moves for @ppiece pawn. + * If @doit is true, add moves to @pos' moves list. + */ +int pseudo_moves_pawn(pos_t *pos, piece_list_t *ppiece, bool doit) +{ + piece_t piece = PIECE(ppiece->piece); + unsigned char color = COLOR(ppiece->piece); + square_t square = ppiece->square, new; + board_t *board = pos->board; + unsigned char rank2, rank7, rank5; + move_t *move = NULL; + char dir; + int count = 0; + + /* setup direction */ + if (IS_WHITE(color)) { + dir = 1; + rank2 = 1; + rank7 = 6; + rank5 = 4; + } else { + dir = -1; + rank2 = 6; + rank7 = 1; + rank5 = 3; + } + +# ifdef DEBUG_MOVE + log_f(2, "pos:%p turn:%s piece:%d [%s %s] dir:%d at %#04x[%c%c]\n", + pos, + IS_WHITE(pos->turn)? "white": "black", + piece, + IS_WHITE(color)? "white": "black", + P_NAME(piece), + dir, + square, + FILE2C(F88(square)), RANK2C(R88(square))); +# endif + + /* normal push. We do not test for valid destination square here, + * assuming position is valid. Is that correct ? + */ + new = square + dir * 16; + if (!board[new].piece) { +# ifdef DEBUG_MOVE + log_i(4, "pushing pawn %#04x\n", square); +# endif + pos->mobility[color]++; + count++; + if (doit) + move_pawn_add(pos, piece | color, square, new, rank7); + /* push 2 squares */ + log(4, "R88(%#x)=%d R2=%d \n", square, R88(square), rank2); + if (R88(square) == rank2) { + new += dir * 16; + if (SQ88_OK(new) && !board[new].piece) { +# ifdef DEBUG_MOVE + log_i(4, "pushing pawn %#04x 2 squares\n", square); +# endif + //log_f(2, "pawn move2 mobility\n"); + pos->mobility[color]++; + count++; + if (doit) + move_pawn_add(pos, piece | color, square, new, rank7); + } + } + } + + /* en passant - not accounted for mobility. Correct ? */ + if (pos->en_passant && R88(square) == rank5) { + unsigned char ep_file = F88(pos->en_passant); + unsigned char sq_file = F88(square); + +# ifdef DEBUG_MOVE + log_i(4, "possible en passant on rank %#x (current = %#0x)\n", ep_file, + sq_file); +# endif + if (sq_file == ep_file - 1 || sq_file == ep_file + 1) { + square_t t_square = SQ88(ep_file, rank5); /* taken pawn square */ + piece_t captured = board[t_square].piece; + move = move_pawn_add(pos, piece | color , square, pos->en_passant, rank7); + move->flags |= M_EN_PASSANT | M_CAPTURE; + move->capture = captured; + pos->mobility[color]++; + count++; + } + + } + + /* capture */ + int two=0; + for (new = square + dir * 15; two < 2; new = square + dir * 17, two++) { +# ifdef DEBUG_MOVE + log_i(4, "pawn capture %#04x %#04x\n", square, new); +# endif + if (SQ88_NOK(new)) + continue; + pos->controlled[color] |= SQ88_2_BB(new); + if (board[new].piece && COLOR(board[new].piece) != color) { + if (PIECE(board[new].piece) == KING) + pos->check[color]++; + //log_f(2, "pawn capture mobility\n"); + pos->mobility[color]++; + count++; + if (doit) + move_pawn_add(pos, piece | color, square, new, rank7); + } + } +# ifdef DEBUG_MOVE + log_f(2, "pos:%p turn:%s piece:%d [%s %s] dir:%d at %#04x[%c%c] count=%d\n", + pos, + IS_WHITE(pos->turn)? "white": "black", + piece, + IS_WHITE(color)? "white": "black", + P_NAME(piece), + dir, + square, + FILE2C(F88(square)), RANK2C(R88(square)), count); +# endif + return count; +} + +/** + * pseudo_moves_castle() - generate castle moves. + * @pos: &position + * @color: side for which to generate moves + * @doit: add move to moves list + * @do_king: count king moves in mobility + * + * Calculate the possible castle moves for @color side. + * If @doit is true, add moves to @pos' moves list. + * If @do_king is true, account king moves (incl. castle) to mobility. + * + * @return: The number of possible king moves. + */ +int pseudo_moves_castle(pos_t *pos, bool color, bool doit, bool do_king) +{ + board_t *board = pos->board; + unsigned char rank1, castle_K, castle_Q; + move_t *move = NULL; + unsigned short count=0; + struct can_castle *can_castle; + bitboard_t controlled; + bitboard_t occupied = pos->occupied[WHITE] | pos->occupied[BLACK]; + //pos_t *newpos; + +# ifdef DEBUG_MOVE + log_f(2, "pos:%p turn:%s color:%s\n", + pos, + IS_WHITE(pos->turn)? "white": "black", + IS_WHITE(color)? "white": "black"); +# endif + + if (IS_WHITE(color)) { + rank1 = 0; + castle_K = pos->castle & CASTLE_WK; + castle_Q = pos->castle & CASTLE_WQ; + can_castle = castle_squares+WHITE; + controlled = pos->controlled[BLACK]; + } else { + rank1 = 7; + castle_K = pos->castle & CASTLE_BK; + castle_Q = pos->castle & CASTLE_BQ; + can_castle = castle_squares+BLACK; + controlled = pos->controlled[WHITE]; + } + if (castle_K) { + if (occupied & can_castle->occupied[1]) { +# ifdef DEBUG_MOVE + log(5, "Cannot castle K side: occupied\n"); +# endif + goto next; + } + if (controlled & can_castle->controlled[1]) { +# ifdef DEBUG_MOVE + log(5, "Cannot castle K side: controlled\n"); +# endif + goto next; + } + if (do_king) { + pos->mobility[color]++; + count++; + } + if (doit) { + move = move_add(pos, board[SQ88(4, rank1)].piece, + SQ88(4, rank1), SQ88(6, rank1)); + if (move) + move->flags |= M_CASTLE_K; + } + } + +next: + if (castle_Q) { + if (occupied & can_castle->occupied[0]) { +# ifdef DEBUG_MOVE + log(5, "Cannot castle Q side: occupied\n"); +# endif + goto end; + } + if (controlled & can_castle->controlled[0]) { +# ifdef DEBUG_MOVE + log(5, "Cannot castle Q side: controlled\n"); +# endif + goto end; + } + if (do_king) { + pos->mobility[color]++; + count++; + } + if (doit) { + move = move_add(pos, board[SQ88(4, rank1)].piece, + SQ88(4, rank1), SQ88(2, rank1)); + if (move) + move->flags |= M_CASTLE_Q; + } + } +end: + return count; +} + +/** + * pseudo_moves_gen() - general move generation for non pawn pieces + * @pos: &position + * @ppiece: &piece_list structure pointer + * @doit: add move to moves list + * @do_king: count king moves + * + * Calculate all possible moves for @ppiece. + * If @doit is true, add moves to @pos' moves list. + * If @do_king is true, account king moves (incl. castle) to mobility. + */ +int pseudo_moves_gen(pos_t *pos, piece_list_t *ppiece, bool doit, bool do_king) +{ + piece_t piece = PIECE(ppiece->piece); + unsigned char color = COLOR(ppiece->piece); + struct vector *vector = vectors+piece; + square_t square = ppiece->square; + unsigned char ndirs = vector->ndirs; + char slide = vector->slide; + board_t *board = pos->board; + //move_t *move; + int count = 0; + u64 bb_new; + +# ifdef DEBUG_MOVE + log_f(2, "pos:%p turn:%s piece:%d [%s %s] at %#04x[%c%c]\n", + pos, + IS_WHITE(pos->turn)? "white": "black", + piece, + IS_WHITE(color)? "white": "black", + P_NAME(piece), + square, + FILE2C(F88(square)), RANK2C(R88(square))); + log_i(5, "vector=%ld ndirs=%d slide=%d\n", vector-vectors, ndirs, slide); +# endif + + for (int curdir = 0; curdir < ndirs; ++curdir) { + char dir = vector->dir[curdir]; + for (square_t new = square + dir; ; new = new + dir) { + /* outside board */ + if (SQ88_NOK(new)) { +# ifdef DEBUG_MOVE + log_i(4,"skipping %04x (invalid square)\n", new); +# endif + break; + } + bb_new = SQ88_2_BB(new); +# ifdef DEBUG_MOVE + log_i(2, "trying %#x=%c%c bb=%#lx\n", + new, FILE2C(F88(new)), RANK2C(R88(new)), + bb_new); + //bitboard_print(new_bitboard); +# endif + + pos->controlled[color] |= bb_new;; + + /* king: do not move to opponent controlled square */ + if (piece == KING && pos->controlled[OPPONENT(color)] & bb_new) { +# ifdef DEBUG_MOVE + log_i(2, "%s king cannot move to %c%c\n", + IS_WHITE(color)? "white": "black", + FILE2C(F88(new)), RANK2C(R88(new))); +# endif + break; + } + + if (bb_new & pos->occupied[color]) { + //bitboard_print(pos->occupied[color]); + //bitboard_print(pos->occupied[OPPONENT(color)]); +# ifdef DEBUG_MOVE + log_i(2, "BB: skipping %#lx [%c%c] (same color piece)\n", + bb_new, FILE2C(F88(new)), RANK2C(R88(new))); +# endif + break; + } + + /* we are sure the move is valid : we create move */ + if (piece != KING || do_king) { + pos->mobility[color]++; + count++; + } + if (doit) + move_add(pos, ppiece->piece, square, new); + if (board[new].piece) { /* stopper move */ + break; + } + if (!slide) + break; + } + } +# ifdef DEBUG_MOVE + log_f(2, "pos:%p turn:%s piece:%d [%s %s] at %#04x[%c%c] count=%d\n", + pos, + IS_WHITE(pos->turn)? "white": "black", + piece, + IS_WHITE(color)? "white": "black", + P_NAME(piece), + square, + FILE2C(F88(square)), RANK2C(R88(square)), count); +# endif + return count; +} + +/** + * moves_gen() - move generation for one color + * @pos: &position + * @color: side + * @doit: add move to moves list + * @do_king: count king moves + * + * Calculate all possible moves for @color. + * If @doit is true, add moves to @pos' moves list. + * If @do_king is true, account king moves (incl. castle) to mobility. + */ +int moves_gen(pos_t *pos, bool color, bool doit, bool do_king) +{ + struct list_head *p_cur, *tmp, *piece_list; + piece_list_t *piece; + int count = 0; + +# ifdef DEBUG_MOVE + log_f(2, "color:%s doit:%d\n", color? "Black": "White", doit); +# endif + + /* do not generate moves if already done for color */ + if (!list_empty(&pos->moves[color])) + doit = false; + + piece_list = &pos->pieces[color]; + pos->mobility[color] = 0; + pos->controlled[color] = 0; + count += pseudo_moves_castle(pos, color, doit, do_king); + list_for_each_safe(p_cur, tmp, piece_list) { + piece = list_entry(p_cur, piece_list_t, list); + if (PIECE(piece->piece) != PAWN) + count += pseudo_moves_gen(pos, piece, doit, do_king); + else + count += pseudo_moves_pawn(pos, piece, doit); + + count++; + } + return count; +} + +/** + * moves_gen_king_moves() - adjust king mobility + * @pos: &position + * @color: king color + * @doit: add move to moves list + * + * Compute the number of king moves (incl. castle), after opponent controlled + * are known. + * If @doit is true, add moves to @pos' moves list. + * + * @return: The number of possible king moves. + */ +int moves_gen_king_moves(pos_t *pos, bool color, bool doit) +{ + int count = 0; + piece_list_t *king = list_first_entry(&pos->pieces[color], piece_list_t, list); + count = pseudo_moves_castle(pos, king, doit, true); + count += pseudo_moves_gen(pos, king, doit, true); + return count; +} + +static int moves_cmp_eval(__unused void *data, const struct list_head *h1, const struct list_head *h2) +{ + move_t *m1 = list_entry(h1, move_t, list); + move_t *m2 = list_entry(h2, move_t, list); + return m2->eval_simple - m1->eval_simple; +} + +/** + * moves_sort() sort - sort moves list, best eval first. + * @pos: &position. + */ +void moves_sort(pos_t *pos) +{ + list_sort(NULL, &pos->moves[pos->turn], moves_cmp_eval); +} + +/** + * moves_gen_all_eval_sort() - calculate/generate/sort moves for side to play. + * @pos: &position + * + * Generate positions for each move for player to move. + * For each of them generate opponents moves, calculate eval, and sort the moves list. + */ +void moves_gen_eval_sort(pos_t *pos) +{ + move_t *move; + pos_t *newpos; + + moves_gen_all(pos); + + list_for_each_entry(move, &pos->moves[pos->turn], list) { + newpos = move_do(pos, move); + move->pos = newpos; + //move_print(0, move, 0); + move->eval_simple = eval_simple(newpos); + newpos->eval_simple = move->eval_simple; + } + moves_sort(pos); + //moves_print(pos, 0); +} + +/** + * moves_gen_all() - calculate all moves, and generate moves for side to play. + * @pos: &position + * + * Compute pseudo moves for both sides, and generate moves for player to move. + */ +void moves_gen_all(pos_t *pos) +{ + //log_f(1, "turn=%d opponent=%d\n", pos->turn, OPPONENT(pos->turn)); + if (!pos->moves_generated) { + if (!pos->moves_counted) {} + moves_gen(pos, OPPONENT(pos->turn), false, false); + moves_gen(pos, pos->turn, true, true); + if (!pos->moves_counted) + moves_gen_king_moves(pos, OPPONENT(pos->turn), false); + pos->moves_counted = true; + pos->moves_generated = true; + } +} + +/** + * moves_gen_all_nomoves() - calculate number of moves for each player. + * @pos: &position + */ +void moves_gen_all_nomoves(pos_t *pos) +{ + //log_f(1, "turn=%d opponent=%d\n", pos->turn, OPPONENT(pos->turn)); + if (!pos->moves_counted) { + moves_gen(pos, OPPONENT(pos->turn), false, false); + moves_gen(pos, pos->turn, false, true); + moves_gen_king_moves(pos, OPPONENT(pos->turn), false); + pos->moves_counted = true; + } +} + +/** + * move_do() - execute move in a duplicated position. + * @pos: &pos_t struct on which move will be applied + * @move: &move_t struct to apply + * + * @return: &new position + */ +pos_t *move_do(pos_t *pos, move_t *move) +{ +# ifdef DEBUG_MOVE + //log(1, "new move: "); + //move_print(0, move, M_PR_NL | M_PR_LONG); +# endif + + pos_t *new = pos_dup(pos); + piece_t piece = PIECE(move->piece), newpiece = piece, captured = move->capture; + int color = COLOR(move->piece); + square_t from = move->from, to = move->to; + u64 bb_from = SQ88_2_BB(from), bb_to = SQ88_2_BB(to); + + if (move->capture || piece == PAWN) /* 50 moves */ + new->clock_50 = 0; + else + new->clock_50++; + + if (move->flags & M_CAPTURE) { /* capture */ + if (move->flags & M_EN_PASSANT) { + uchar ep_file = F88(pos->en_passant); + square_t ep_grab = color == WHITE ? SQ88(ep_file, 4): SQ88(ep_file, 3); + u64 bb_ep_grab = SQ88_2_BB(ep_grab); + + log_f(5, "en-passant=%d,%d\n", ep_file, color == WHITE ? 4 : 3); + piece_del(&new->board[ep_grab].s_piece->list); + new->board[ep_grab].piece = 0; + new->occupied[OPPONENT(color)] &= ~bb_ep_grab; + new->bb[OPPONENT(color)][BB_PAWN] &= ~bb_ep_grab; + + } else { + piece_del(&new->board[to].s_piece->list); + new->board[to].piece = 0; + new->occupied[OPPONENT(color)] &= ~bb_to; + new->bb[OPPONENT(color)][PIECETOBB(captured)] &= ~bb_to; + } + + } else if (move->flags & M_CASTLE_Q) { + uchar row = R88(from); + square_t rook_from = SQ88(0, row); + square_t rook_to = SQ88(3, row); + u64 bb_rook_from = SQ88_2_BB(rook_from); + u64 bb_rook_to = SQ88_2_BB(rook_to); + + new->board[rook_to] = new->board[rook_from]; + new->board[rook_to].s_piece->square = rook_to; + new->occupied[color] &= ~bb_rook_from; + new->occupied[color] |= bb_rook_to; + new->bb[color][PIECETOBB(BB_ROOK)] &= ~bb_rook_from; + new->bb[color][PIECETOBB(BB_ROOK)] |= bb_rook_to; + new->board[rook_from].piece = 0; + new->board[rook_from].s_piece = NULL; + //new->castle &= color == WHITE? ~CASTLE_W: ~CASTLE_B; + + } else if (move->flags & M_CASTLE_K) { + uchar row = R88(from); + square_t rook_from = SQ88(7, row); + square_t rook_to = SQ88(5, row); + u64 bb_rook_from = SQ88_2_BB(rook_from); + u64 bb_rook_to = SQ88_2_BB(rook_to); + + new->board[rook_to] = new->board[rook_from]; + new->board[rook_to].s_piece->square = rook_to; + new->occupied[color] &= ~bb_rook_from; + new->occupied[color] |= bb_rook_to; + new->bb[color][PIECETOBB(BB_ROOK)] &= ~bb_rook_from; + new->bb[color][PIECETOBB(BB_ROOK)] |= bb_rook_to; + new->board[rook_from].piece = 0; + new->board[rook_from].s_piece = NULL; + // new->castle &= color == WHITE? ~CASTLE_W: ~CASTLE_B; + } + + new->board[to] = new->board[from]; + /* fix dest square */ + new->board[to].s_piece->square = to; + if (move->flags & M_PROMOTION) { + log_f(5, "promotion to %s\n", P_SYM(move->promotion)); + log_f(5, "newpiece=%#x p=%#x\n", move->promotion, PIECE(move->promotion)); + newpiece = PIECE(move->promotion); + new->board[to].piece = move->promotion; + new->board[to].s_piece->piece = move->promotion; + } + /* replace old occupied bitboard by new one */ + new->occupied[color] &= ~bb_from; + new->occupied[color] |= bb_to; + new->bb[color][PIECETOBB(piece)] &= ~bb_from; + new->bb[color][PIECETOBB(newpiece)] |= bb_to; + if (move->flags & M_PROMOTION) { + log_f(5, "promotion color=%d bbpiece=%d\n", color, PIECETOBB(newpiece)); + //bitboard_print(new->bb[color][PIECETOBB(newpiece)]); + } + /* set en_passant */ + new->en_passant = 0; + if (piece == PAWN) { + if (R88(from) == 1 && R88(to) == 3) + pos->en_passant = SQ88(F88(from), 2); + else if (R88(from) == 6 && R88(to) == 4) + pos->en_passant = SQ88(F88(from), 5); + } + + /* always make "from" square empty */ + new->board[from].piece = 0; + new->board[from].s_piece = NULL; + + //printf("old turn=%d ", color); + //printf("new turn=%d\n", new->turn); + //fflush(stdout); + /* adjust castling flags */ + if ((bb_from | bb_to) & E1bb) + new->castle &= ~(CASTLE_WQ | CASTLE_WK); + else if ((bb_from | bb_to) & A1bb) + new->castle &= ~CASTLE_WQ; + else if ((bb_from | bb_to) & H1bb) + new->castle &= ~CASTLE_WK; + + if ((bb_from | bb_to) & E8bb) + new->castle &= ~(CASTLE_BQ | CASTLE_BK); + else if ((bb_from | bb_to) & A8bb) + new->castle &= ~CASTLE_BQ; + else if ((bb_from | bb_to) & H8bb) + new->castle &= ~CASTLE_BK; + + SET_COLOR(new->turn, OPPONENT(color)); /* pos color */ + return new; +} + +void move_undo(pos_t *pos, __unused move_t *move) +{ + pos_del(pos); +}