diff --git a/Makefile b/Makefile index 1747b22..fa97e43 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile - brchess Makefile, **GNU make only** # -# Copyright (C) 2021-2023 Bruno Raoult ("br") +# Copyright (C) 2021-2024 Bruno Raoult ("br") # Licensed under the GNU General Public License v3.0 or later. # Some rights reserved. See COPYING. # diff --git a/src/move-gen.c b/src/move-gen.c index 9c53b9a..a453790 100644 --- a/src/move-gen.c +++ b/src/move-gen.c @@ -103,18 +103,19 @@ bool pseudo_is_legal(const pos_t *pos, const move_t move) /** * pos_next_legal() - get next legal move in position. * @pos: position - * @start: &int, starting position in move list + * @movelist: &pseudo-legal movelist + * @start: &int, starting position in @movelist * * Get next valid move in @pos move list, from move @start, or MOVE_NONE. * @start is set to next non-checked move in pseudo-legal list. * Position pseudo-legal moves must be already calculated before calling this function. * - * @return: move, or -1 if no move. + * @return: move, or MOVE_NONE if no move. */ -move_t pos_next_legal(const pos_t *pos, int *start) +move_t pos_next_legal(const pos_t *pos, movelist_t *movelist, int *start) { - const int nmoves = pos->moves.nmoves; - const move_t *moves = pos->moves.move; + const int nmoves = movelist->nmoves; + const move_t *moves = movelist->move; move_t move; while (*start < nmoves) { @@ -127,20 +128,20 @@ move_t pos_next_legal(const pos_t *pos, int *start) /** * pos_all_legal() - get the list of legal moves from pseudo-legal. * @pos: position - * @dest: destination &movelist_t + * @movelist: &pseudo-legal movelist_t + * @dest: &destination movelist_t * * The pseudo-legal moves must be already calculated before calling this function. * No check is done on @dest limits. * * @Return: @dest */ -movelist_t *pos_all_legal(const pos_t *pos, movelist_t *dest) +movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *dest) { int tmp = dest->nmoves = 0; move_t move; - //int tmp = 0; - while ((move = pos_next_legal(pos, &tmp)) != MOVE_NONE) + while ((move = pos_next_legal(pos, movelist, &tmp)) != MOVE_NONE) dest->move[dest->nmoves++] = move; return dest; } @@ -148,9 +149,10 @@ movelist_t *pos_all_legal(const pos_t *pos, movelist_t *dest) /** * pos_gen_pseudomoves() - generate position pseudo-legal moves * @pos: position + * @movelist: &movelist_t array to store pseudo-moves * * Generate all @pos pseudo moves for player-to-move. - * The @pos->moves table is filled with the moves. + * @movelist is filled with the moves. * * Only a few validity checks are done here (i.e. moves are not generated): * - castling, if king is in check @@ -167,7 +169,7 @@ movelist_t *pos_all_legal(const pos_t *pos, movelist_t *dest) * * @Return: The total number of moves. */ -int pos_gen_pseudomoves(pos_t *pos) +int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist) { color_t us = pos->turn; color_t them = OPPONENT(us); @@ -181,43 +183,43 @@ int pos_gen_pseudomoves(pos_t *pos) bitboard_t movebits, from_pawns; bitboard_t tmp1, tmp2; - move_t *moves = pos->moves.move; - int nmoves = pos->moves.nmoves; + move_t *moves = movelist->move; + int *nmoves = &movelist->nmoves; int from, to; - bug_on(nmoves != 0); + *nmoves = 0; /* king - MUST BE FIRST (we stop if doubler check) */ from = pos->king[us]; movebits = bb_king_moves(not_my_pieces, from); bit_for_each64(to, tmp1, movebits & empty) { - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } bit_for_each64(to, tmp1, movebits & enemy_pieces) { - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } if (popcount64(pos->checkers) > 1) /* double check, we stop here */ - return (pos->moves.nmoves = nmoves); + return *nmoves; /* sliding pieces */ bit_for_each64(from, tmp1, pos->bb[us][BISHOP] | pos->bb[us][QUEEN]) { movebits = hyperbola_bishop_moves(occ, from) & not_my_pieces; bit_for_each64(to, tmp2, movebits & empty) { - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } bit_for_each64(to, tmp2, movebits & enemy_pieces) { - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } } bit_for_each64(from, tmp1, pos->bb[us][ROOK] | pos->bb[us][QUEEN]) { // printf("rook=%d/%s\n", from, sq_to_string(from)); movebits = hyperbola_rook_moves(occ, from) & not_my_pieces; bit_for_each64(to, tmp2, movebits & empty) { - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } bit_for_each64(to, tmp2, movebits & enemy_pieces) { - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } } @@ -225,10 +227,10 @@ int pos_gen_pseudomoves(pos_t *pos) bit_for_each64(from, tmp1, pos->bb[us][KNIGHT]) { movebits = bb_knight_moves(not_my_pieces, from); bit_for_each64(to, tmp2, movebits & empty) { - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } bit_for_each64(to, tmp2, movebits & enemy_pieces) { - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } } @@ -241,13 +243,13 @@ int pos_gen_pseudomoves(pos_t *pos) bit_for_each64(to, tmp1, movebits) { from = pawn_push_up(to, them); /* reverse push */ //printf("push %d->%d %s->%s", from, to, sq_to_string(from), sq_to_string(to)); - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } /* possible second push */ movebits = pawn_shift_up(movebits & rel_rank3, us) & empty; bit_for_each64(to, tmp1, movebits) { from = pawn_push_up(pawn_push_up(to, them), them); - moves[nmoves++] = move_make_flags(from, to, M_DPUSH); + moves[(*nmoves)++] = move_make_flags(from, to, M_DPUSH); } /* pawn: ranks 2-6 captures left */ @@ -255,14 +257,14 @@ int pos_gen_pseudomoves(pos_t *pos) movebits = pawn_shift_upleft(from_pawns, us) & enemy_pieces; bit_for_each64(to, tmp1, movebits) { from = pawn_push_upleft(to, them); /* reverse capture */ - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } /* pawn: ranks 2-6 captures right */ from_pawns = pos->bb[us][PAWN] & ~rel_rank7; // & ~rel_fileh; movebits = pawn_shift_upright(from_pawns, us) & enemy_pieces; bit_for_each64(to, tmp1, movebits) { from = pawn_push_upright(to, them); - moves[nmoves++] = move_make_capture(from, to); + moves[(*nmoves)++] = move_make_capture(from, to); } /* pawn: en-passant */ @@ -271,7 +273,7 @@ int pos_gen_pseudomoves(pos_t *pos) from_pawns = pos->bb[us][PAWN] & (pawn_shift_upleft(movebits, them) | pawn_shift_upright(movebits, them)); bit_for_each64(from, tmp1, from_pawns) { - moves[nmoves++] = move_make_enpassant(from, to); + moves[(*nmoves)++] = move_make_enpassant(from, to); } } @@ -279,30 +281,30 @@ int pos_gen_pseudomoves(pos_t *pos) movebits = pawn_shift_up(pos->bb[us][PAWN] & rel_rank7, us) & empty; bit_for_each64(to, tmp1, movebits) { from = pawn_push_up(to, them); /* reverse push */ - moves[nmoves++] = move_make_promote(from, to, QUEEN); - moves[nmoves++] = move_make_promote(from, to, ROOK); - moves[nmoves++] = move_make_promote(from, to, BISHOP); - moves[nmoves++] = move_make_promote(from, to, KNIGHT); + moves[(*nmoves)++] = move_make_promote(from, to, QUEEN); + moves[(*nmoves)++] = move_make_promote(from, to, ROOK); + moves[(*nmoves)++] = move_make_promote(from, to, BISHOP); + moves[(*nmoves)++] = move_make_promote(from, to, KNIGHT); } /* pawn promotion: rank 7 captures left */ from_pawns = pos->bb[us][PAWN] & rel_rank7; // & ~rel_filea; movebits = pawn_shift_upleft(from_pawns, us) & enemy_pieces; bit_for_each64(to, tmp1, movebits) { from = pawn_push_upleft(to, them); /* reverse capture */ - moves[nmoves++] = move_make_promote_capture(from, to, QUEEN); - moves[nmoves++] = move_make_promote_capture(from, to, ROOK); - moves[nmoves++] = move_make_promote_capture(from, to, BISHOP); - moves[nmoves++] = move_make_promote_capture(from, to, KNIGHT); + moves[(*nmoves)++] = move_make_promote_capture(from, to, QUEEN); + moves[(*nmoves)++] = move_make_promote_capture(from, to, ROOK); + moves[(*nmoves)++] = move_make_promote_capture(from, to, BISHOP); + moves[(*nmoves)++] = move_make_promote_capture(from, to, KNIGHT); } /* pawn: rank 7 captures right */ from_pawns = pos->bb[us][PAWN] & rel_rank7; // & ~rel_fileh; movebits = pawn_shift_upright(from_pawns, us) & enemy_pieces; bit_for_each64(to, tmp1, movebits) { from = pawn_push_upright(to, them); /* reverse capture */ - moves[nmoves++] = move_make_promote_capture(from, to, QUEEN); - moves[nmoves++] = move_make_promote_capture(from, to, ROOK); - moves[nmoves++] = move_make_promote_capture(from, to, BISHOP); - moves[nmoves++] = move_make_promote_capture(from, to, KNIGHT); + moves[(*nmoves)++] = move_make_promote_capture(from, to, QUEEN); + moves[(*nmoves)++] = move_make_promote_capture(from, to, ROOK); + moves[(*nmoves)++] = move_make_promote_capture(from, to, BISHOP); + moves[(*nmoves)++] = move_make_promote_capture(from, to, KNIGHT); } /* castle - Attention ! Castling flags are assumed correct @@ -319,14 +321,14 @@ int pos_gen_pseudomoves(pos_t *pos) bitboard_t occmask = rel_rank1 & (FILE_Fbb | FILE_Gbb); if (!(occ & occmask) && !sq_attackers(pos, occ, from+1, them)) { /* f1/f8 */ - moves[nmoves++] = move_make_flags(from, from + 2, M_CASTLE_K); + moves[(*nmoves)++] = move_make_flags(from, from + 2, M_CASTLE_K); } } if (can_ooo(pos->castle, us)) { bitboard_t occmask = rel_rank1 & (FILE_Bbb | FILE_Cbb | FILE_Dbb); if (!(occ & occmask) && !sq_attackers(pos, occ, from-1, them)) { /* d1/d8 */ - moves[nmoves++] = move_make_flags(from, from - 2, M_CASTLE_Q); + moves[(*nmoves)++] = move_make_flags(from, from - 2, M_CASTLE_Q); } } } @@ -341,5 +343,5 @@ int pos_gen_pseudomoves(pos_t *pos) * add function per piece, and type, for easier debug * */ - return (pos->moves.nmoves = nmoves); + return *nmoves; } diff --git a/src/move-gen.h b/src/move-gen.h index a249c46..2b3d072 100644 --- a/src/move-gen.h +++ b/src/move-gen.h @@ -22,8 +22,8 @@ #include "move.h" bool pseudo_is_legal(const pos_t *pos, const move_t move); -move_t pos_next_legal(const pos_t *pos, int *start); -movelist_t *pos_all_legal(const pos_t *pos, movelist_t *dest); -int pos_gen_pseudomoves(pos_t *pos); +move_t pos_next_legal(const pos_t *pos, movelist_t *movelist, int *start); +movelist_t *pos_all_legal(const pos_t *pos, movelist_t *movelist, movelist_t *dest); +int pos_gen_pseudomoves(pos_t *pos, movelist_t *movelist); #endif /* MOVEGEN_H */ diff --git a/src/move.h b/src/move.h index 19fbb66..fb15d6a 100644 --- a/src/move.h +++ b/src/move.h @@ -35,8 +35,8 @@ typedef s32 move_t; /* special move_t values */ -#define MOVE_NONE (-1) -#define MOVE_NULL (0) /* hack: from = to = A1 */ +#define MOVE_NONE ((move_t) -1) +#define MOVE_NULL ((move_t) 0) /* hack: from = to = A1 */ enum { M_OFF_FROM = 0, diff --git a/src/position.c b/src/position.c index 2d98be4..aa9d150 100644 --- a/src/position.c +++ b/src/position.c @@ -89,7 +89,7 @@ pos_t *pos_clear(pos_t *pos) pos->castle = 0; pos->clock_50 = 0; pos->plycount = 0; - pos->captured = NO_PIECE; + //pos->captured = NO_PIECE; for (square_t sq = A1; sq <= H8; ++sq) pos->board[sq] = EMPTY; @@ -105,8 +105,7 @@ pos_t *pos_clear(pos_t *pos) pos->pinners = 0; pos->blockers = 0; - //pos->moves.curmove = 0; - pos->moves.nmoves = 0; + //pos->moves.nmoves = 0; return pos; } @@ -134,8 +133,8 @@ bool pos_cmp(const pos_t *pos1, const pos_t *pos2) goto end; if (warn_on(_cmpf(plycount))) goto end; - if (warn_on(_cmpf(captured))) - goto end; + //if (warn_on(_cmpf(captured))) + // goto end; for (square_t sq = A1; sq <= H8; ++sq) if (warn_on(_cmpf(board[sq]))) @@ -157,11 +156,13 @@ bool pos_cmp(const pos_t *pos1, const pos_t *pos2) if (warn_on(_cmpf(blockers))) goto end; - if (warn_on(_cmpf(moves.nmoves))) - goto end; - for (int i = 0; i < pos1->moves.nmoves; ++i) - if (warn_on(_cmpf(moves.move[i]))) - goto end; + /* + * if (warn_on(_cmpf(moves.nmoves))) + * goto end; + * for (int i = 0; i < pos1->moves.nmoves; ++i) + * if (warn_on(_cmpf(moves.move[i]))) + * goto end; + */ ret = true; end: diff --git a/src/position.h b/src/position.h index 0de3539..df986c9 100644 --- a/src/position.h +++ b/src/position.h @@ -41,7 +41,10 @@ typedef struct __pos_s { castle_rights_t castle; u16 clock_50; u16 plycount; /* plies so far, start from 1 */ - piece_t captured; /* only for move_undo */ + //piece_t captured; /* only for move_undo */ + bitboard_t checkers; /* opponent checkers */ + bitboard_t pinners; /* opponent pinners */ + bitboard_t blockers; /* pieces blocking pin */ ); piece_t board[BOARDSIZE]; @@ -49,10 +52,7 @@ typedef struct __pos_s { bitboard_t bb[2][PIECE_TYPE_MAX]; /* bb[0][PAWN], bb[1][ALL_PIECES] */ //bitboard_t controlled[2]; /* unsure */ square_t king[2]; /* dup with bb, faster retrieval */ - bitboard_t checkers; /* opponent checkers */ - bitboard_t pinners; /* opponent pinners */ - bitboard_t blockers; /* pieces blocking pin */ - movelist_t moves; + //movelist_t moves; } pos_t; typedef struct state_s state_t; diff --git a/src/search.c b/src/search.c index bb0dd78..983370d 100644 --- a/src/search.c +++ b/src/search.c @@ -1,6 +1,6 @@ /* search.c - search good moves. * - * Copyright (C) 2023 Bruno Raoult ("br") + * Copyright (C) 2023-2024 Bruno Raoult ("br") * Licensed under the GNU General Public License v3.0 or later. * Some rights reserved. See COPYING. * @@ -11,14 +11,62 @@ * */ +#include -#include -#include -#include "debug.h" +#include "brlib.h" -#include "move.h" -#include "eval.h" -#include "search.h" +#include "position.h" +#include "move-gen.h" +#include "move-do.h" + +//#include "move.h" +//#include "eval.h" +//#include "search.h" + +/** + * perft() - Perform perft on position + * @pos: &position to search + * @depth: Wanted depth. + * @ply: Depth level where perft is consolidated. + * + * Print perftCalculate the negamax value of @pos. This is an extensive search, with + * absolutely no cutoff. + * + * @return: The @pos negamax evaluation. + */ +u64 perft(pos_t *pos, int depth, int ply) +{ + int movetmp = 0, nodes = 0, subnodes, nmove = 0; + movelist_t pseudo = { .nmoves = 0 }, legal = { .nmoves = 0 }; + move_t move; + + if (depth == 0) + return 1; + pos->checkers = pos_checkers(pos, pos->turn); + pos->pinners = pos_king_pinners(pos, pos->turn); + pos->blockers = pos_king_blockers(pos, pos->turn, pos->pinners); + + pos_gen_pseudomoves(pos, &pseudo); + pos_all_legal(pos, &pseudo, &legal); + + //for (nmove = 0; nmove < legal.nmoves; ++nmove ) { + while ((move = pos_next_legal(pos, &pseudo, &movetmp)) != MOVE_NONE) { + + state_t state; + move = legal.move[nmove]; + move_do(pos, move, &state); + subnodes = perft(pos, depth - 1, ply + 1); + if (ply == 1) { + char movestr[8]; + printf("%s: %d\n", move_str(movestr, move, 0), subnodes); + } + nodes += subnodes; + move_undo(pos, move, &state); + } + if (ply == 1) + printf("Total: %d\n", nodes); + return nodes; +} /** * negamax() - search position negamax. @@ -31,32 +79,34 @@ * * @return: The @pos negamax evaluation. */ -eval_t negamax(pos_t *pos, int depth, int color) -{ - move_t *move; - pos_t *newpos; - eval_t best = EVAL_MIN, score; - - pos->node_count++; - if (depth == 0) { - moves_gen_all_nomoves(pos); - score = eval(pos) * color; - return score; - } - moves_gen_all(pos); - list_for_each_entry(move, &pos->moves[pos->turn], list) { - newpos = move_do(pos, move); - score = -negamax(newpos, depth - 1, -color); - pos->node_count += newpos->node_count; - move->negamax = score; - if (score > best) { - best = score; - pos->bestmove = move; - } - move_undo(newpos, move); - } - return best; -} +/* + * eval_t negamax(pos_t *pos, int depth, int color) + * { + * move_t *move; + * pos_t *newpos; + * eval_t best = EVAL_MIN, score; + * + * pos->node_count++; + * if (depth == 0) { + * moves_gen_all_nomoves(pos); + * score = eval(pos) * color; + * return score; + * } + * moves_gen_all(pos); + * list_for_each_entry(move, &pos->moves[pos->turn], list) { + * newpos = move_do(pos, move); + * score = -negamax(newpos, depth - 1, -color); + * pos->node_count += newpos->node_count; + * move->negamax = score; + * if (score > best) { + * best = score; + * pos->bestmove = move; + * } + * move_undo(newpos, move); + * } + * return best; + * } + */ /** @@ -74,74 +124,76 @@ eval_t negamax(pos_t *pos, int depth, int color) * * @return: The @pos PVS evaluation. */ -eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color) -{ - move_t *move; - pos_t *newpos; - eval_t score = EVAL_INVALID; - bool firstchild = true; - - pos->node_count++; - - if (depth == 0) { - //return quiesce(p, alpha, beta); /* leaf node */ - moves_gen_all_nomoves(pos); - score = eval(pos) * color; - log_f(2, "Terminal: depth=%d ", depth); - log_f(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta); - return score; - } - - moves_gen_all(pos); - //moves_print(pos, M_PR_EVAL); - /* do the full search for first child */ - //move = list_first_entry_or_null(&pos->moves[pos->turn], move_t, list); - - list_for_each_entry(move, &pos->moves[pos->turn], list) { - newpos = move_do(pos, move); - log(2, "%.*s", 5 - depth, " "); - if (firstchild) { /* first child */ - score = -pvs(newpos, depth - 1, -beta, -alpha, -color); - log_f(2, "First child depth=%d move=", depth); - //move_print(0, move, 0); - log(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta); - pos->bestmove = move; - } else { - /* search with a null window */ - score = -pvs(newpos, depth - 1, -alpha - 1, -alpha, -color); - log_f(2, "Other child depth=%d move=", depth); - //move_print(0, move, 0); - log_f(2, "score=%d alpha=%d beta=%d ", score, alpha, beta); - /* for fail-soft: if (score > alpha && score < beta) */ - if (score > alpha) { - /* if failed high, do a full re-search */ - log_f(2, "doing full search."); - score = -pvs(newpos, depth - 1, -beta, -alpha, -color); - } - log(2, "\n"); - } - pos->node_count += newpos->node_count; - move_undo(newpos, move); - if (score >= beta) { /* fail-hard hard beta cut-off */ - log(2, "%.*s", 5 - depth, " "); - log_f(2, "depth=%d score=%d alpha=%d beta=%d beta cut-off.\n", - depth, score, alpha, beta); - return beta; - } - if (score > alpha) { - log(2, "%.*s", 5 - depth, " "); - log_f(2, "depth=%d setting new alpha from %d to %d\n", - depth, alpha, score); - alpha = score; - pos->bestmove = move; - } - move->pos = NULL; - move->negamax = score; - firstchild = false; - } - - return alpha; -} +/* + * eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color) + * { + * move_t *move; + * pos_t *newpos; + * eval_t score = EVAL_INVALID; + * bool firstchild = true; + * + * pos->node_count++; + * + * if (depth == 0) { + * //return quiesce(p, alpha, beta); /\* leaf node *\/ + * moves_gen_all_nomoves(pos); + * score = eval(pos) * color; + * log_f(2, "Terminal: depth=%d ", depth); + * log_f(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta); + * return score; + * } + * + * moves_gen_all(pos); + * //moves_print(pos, M_PR_EVAL); + * /\* do the full search for first child *\/ + * //move = list_first_entry_or_null(&pos->moves[pos->turn], move_t, list); + * + * list_for_each_entry(move, &pos->moves[pos->turn], list) { + * newpos = move_do(pos, move); + * log(2, "%.*s", 5 - depth, " "); + * if (firstchild) { /\* first child *\/ + * score = -pvs(newpos, depth - 1, -beta, -alpha, -color); + * log_f(2, "First child depth=%d move=", depth); + * //move_print(0, move, 0); + * log(2, "score=%d alpha=%d beta=%d\n", score, alpha, beta); + * pos->bestmove = move; + * } else { + * /\* search with a null window *\/ + * score = -pvs(newpos, depth - 1, -alpha - 1, -alpha, -color); + * log_f(2, "Other child depth=%d move=", depth); + * //move_print(0, move, 0); + * log_f(2, "score=%d alpha=%d beta=%d ", score, alpha, beta); + * /\* for fail-soft: if (score > alpha && score < beta) *\/ + * if (score > alpha) { + * /\* if failed high, do a full re-search *\/ + * log_f(2, "doing full search."); + * score = -pvs(newpos, depth - 1, -beta, -alpha, -color); + * } + * log(2, "\n"); + * } + * pos->node_count += newpos->node_count; + * move_undo(newpos, move); + * if (score >= beta) { /\* fail-hard hard beta cut-off *\/ + * log(2, "%.*s", 5 - depth, " "); + * log_f(2, "depth=%d score=%d alpha=%d beta=%d beta cut-off.\n", + * depth, score, alpha, beta); + * return beta; + * } + * if (score > alpha) { + * log(2, "%.*s", 5 - depth, " "); + * log_f(2, "depth=%d setting new alpha from %d to %d\n", + * depth, alpha, score); + * alpha = score; + * pos->bestmove = move; + * } + * move->pos = NULL; + * move->negamax = score; + * firstchild = false; + * } + * + * return alpha; + * } + */ /* * int negascout (pos_t *pos, int depth, int alpha, int beta ) diff --git a/src/search.h b/src/search.h index b76e6c2..d4f8f12 100644 --- a/src/search.h +++ b/src/search.h @@ -1,6 +1,6 @@ /* search.h - search for perfect move. * - * Copyright (C) 2021 Bruno Raoult ("br") + * Copyright (C) 2021-2024 Bruno Raoult ("br") * Licensed under the GNU General Public License v3.0 or later. * Some rights reserved. See COPYING. * @@ -16,7 +16,9 @@ #include "position.h" -eval_t negamax(pos_t *pos, int depth, int color); -eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color); +//eval_t negamax(pos_t *pos, int depth, int color); +//eval_t pvs(pos_t *pos, int depth, int alpha, int beta, int color); + +u64 perft(pos_t *pos, int depth, int ply); #endif /* SEARCH_H */ diff --git a/test/common-test.h b/test/common-test.h index 9486ca5..800671e 100644 --- a/test/common-test.h +++ b/test/common-test.h @@ -22,12 +22,14 @@ #define MOVEDO 16 struct fentest { + int line; uint modules; char *comment; char *fen; } fentest[] = { /* - { ATTACK, + { __LINE__. + ATTACK, "checkers: ", "" }, @@ -36,144 +38,144 @@ struct fentest { */ //"4k3/pppppppp/8/8/8/8/PPPPPPPP/2BRK3 w - - 0 1", //"4k3/pppppppp/8/8/8/8/PPPPPPPP/1B1R1K2 w - - 0 1", - { MOVEGEN, + { __LINE__, MOVEGEN, "illegal white e.p.", "3k4/8/8/2qpPK2/8/8/8/8 w - d6 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "illegal black e.p.", "8/8/8/8/2QPpk2/8/8/3K4 b - d3 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "illegal white e.p.", "3k4/8/5K2/3pP3/8/2b5/8/8 w - d6 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "illegal black e.p.", "8/8/2B5/8/3Pp3/5k2/8/3K4 b - d3 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "legal white e.p.", "1K1k4/8/8/3pP3/8/6b1/8/8 w - d6 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "legal black e.p.", "8/8/6B1/8/3Pp3/8/8/1k1K4 b - d3 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "white mate.", "1nbqkbn1/ppp1pppp/8/r1rpP1K1/8/8/PPPP1PPP/RNBQ1BNR w - d6 0 1", }, - { MOVEGEN, + { __LINE__, MOVEGEN, "illegal e.p.", "1nbqkbn1/ppp1pppp/8/r1rpP1K1/8/8/PPPP1PPP/RNBQ1BNR w - d6 0 1", }, - { ATTACK, + { __LINE__, ATTACK, "checkers: a1 h1", "1k6/8/8/8/8/8/8/r2K3r w - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: a8 h8", "R2k3R/8/8/8/8/8/8/1K6 b - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: b3 g3", "1k6/8/8/8/8/1r1K2r1/8/8 w - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: b6 g6", "8/8/1R1k2R1/8/8/8/8/1K6 b - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: g2 g7", "8/k5r1/8/8/6K1/8/6r1/8 w - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: g2 g7", "8/6R1/8/6k1/8/8/K5R1/8 b - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: d5 e3, pinners: none (2 pieces between attacker & K)", "3k4/8/8/3r3b/b7/1N2nn2/2n1B3/rNBK1Rbr w - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: d4 e6 pinners: h4 a5 a8 h8", "Rn1k1r1R/4b3/1n2N3/B7/3R3B/8/8/3K4 b - - 1 1" }, - { ATTACK, + { __LINE__, ATTACK, "checkers: d5 e3, pinners: a1 h1 a4 h5", "3k4/8/8/3r3b/b7/1N2n3/4B3/rN1K1R1r w - - 1 0" }, - { MOVEGEN, + { __LINE__, MOVEGEN, "only pawn captures", "4k3/8/2p1p3/2PpP3/8/pp4pp/PP4PP/4K3 w - d6 0 1" }, - { FEN | ATTACK, + { __LINE__, FEN | ATTACK, "checker: h4", "4k3/8/8/8/7b/8/8/4K3 w - - 0 1" }, // First game moves - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "initial pos", "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "1.e4", "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "1.Nh3", "rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq - 1 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "1.e4 e5 2.Nf3 Nc6", "r1bqkbnr/pp1ppppp/2n5/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 0 1" }, // castling test // both can castle queen only - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r3k2r/8/3B4/8/8/3b4/8/R3K2R w KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r3k2r/8/3BB3/8/8/3bb3/8/R3K2R w KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r2bkb1r/8/8/8/8/3bb3/8/R2BKB1R w KQkq - 0 1" }, // - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "4 castle possible, only K+R", "r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1" }, // - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "only kings on A1/A8, white to play", "k7/8/8/8/8/8/8/K7 w - - 0 1" }, // - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "only one move possible (Pf2xBg3)", "k7/8/8/1p1p4/pPpPp3/P1PpPpb1/NBNP1P2/KBB1B3 w - - 0 1" }, // - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "only 2 moves possible (Ph5xg6 e.p., Ph5-h6)", "k7/8/8/1p1p2pP/pPpPp3/P1PpPp2/NBNP1P2/KBB1B3 w - g6 0 1" }, // - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "2 Kings, W/B/ pawns on 7th for promotion", "k4n2/4P3/8/8/8/8/4p3/K4N2 w - - 0 1" }, @@ -181,20 +183,20 @@ struct fentest { // white is a pawn down // white has 36 moves: P=11 + 1 e.p. N=6+3 B=5+5 R=1 Q=3 K=1 + 1 e.p. // black has 33 moves: P=11 N=2+7 B=5 R=3 Q=3 K=1 + castle - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "rnbqk2r/pp1pbpp1/7p/2pPp3/4n3/3B1N2/PPP2PPP/RNBQ1RK1 w kq c6 0 7" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "4k3/4p3/8/b7/1BR1p2p/1Q3P2/5N2/4K3 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1bq1rk1/pppp1ppp/2n2n2/4p3/2B1P3/3PPN2/PPP3PP/RN1QK2R b KQ - 1 7" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "6k1/6pp/R2p4/p1p5/8/1P1r3P/6P1/6K1 b - - 3 3" }, @@ -202,197 +204,203 @@ struct fentest { // some of tests below are from: // - Rodent IV // - https://www.chessprogramming.net/perfect-perft/ - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "8/2p5/3p4/Kp5r/1R3p1k/8/4P1P1/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "1rbqk1nr/p3ppbp/2np2p1/2p5/1p2PP2/3PB1P1/PPPQ2BP/R2NK1NR b KQk - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1bqk2r/pp1p1ppp/2n1pn2/2p5/1bPP4/2NBP3/PP2NPPP/R1BQK2R b KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "rnb1kb1r/ppp2ppp/1q2p3/4P3/2P1Q3/5N2/PP1P1PPP/R1B1KB1R b KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1b2rk1/pp2nppp/1b2p3/3p4/3N1P2/2P2NP1/PP3PBP/R3R1K1 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "n1q1r1k1/3b3n/p2p1bp1/P1pPp2p/2P1P3/2NBB2P/3Q1PK1/1R4N1 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "2r5/8/1n6/1P1p1pkp/p2P4/R1P1PKP1/8/1R6 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r2q1rk1/1b1nbppp/4p3/3pP3/p1pP4/PpP2N1P/1P3PP1/R1BQRNK1 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "6k1/5pp1/7p/p1p2n1P/P4N2/6P1/1P3P1K/8 w - - 0 35" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r4rk1/1pp1q1pp/p2p4/3Pn3/1PP1Pp2/P7/3QB1PP/2R2RK1 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "", "1k6/1b6/8/8/7R/8/8/4K2R b K - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Illegal ep move #1", "3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Illegal ep move #2", "8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "EP Capture Checks Opponent", "8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Short Castling Gives Check", "5k2/8/8/8/8/8/8/4K2R w K - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Long Castling Gives Check", "3k4/8/8/8/8/8/8/R3K3 w Q - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Castle Rights", "r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Castling Prevented", "r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Promote out of Check", "2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Discovered Check", "8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Promote to give check", "4k3/1P6/8/8/8/8/K7/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Under Promote to give check", "8/P1k5/K7/8/8/8/8/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Self Stalemate", "K1k5/8/P7/8/8/8/8/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Stalemate & Checkmate", "8/k1P5/8/1K6/8/8/8/8 w - - 0 1" }, - { FEN | MOVEGEN, + { __LINE__, FEN | MOVEGEN, "Stalemate & Checkmate", "8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1" }, - { FEN, + { __LINE__, FEN, "illegal EP and castle flags, fix-able by fen parser, SF crash", "4k3/8/8/8/7B/8/8/4K3 w KQkq e6 0 1" }, - { FEN, + { __LINE__, FEN, "illegal, SF crash", "4k3/8/8/8/7b/8/8/4K3 b - - 0 1" }, - { FEN, + { __LINE__, FEN, "illegal, SF crash", "2r1k3/3B4/8/8/8/8/8/4K3 w - - 0 1" }, - { FEN, + { __LINE__, FEN, "illegal, SF crash", "2r1k3/3P4/8/8/8/8/8/4K3 w - - 0 1" }, - { MOVEDO, + { __LINE__, MOVEDO, "simple movedo/undo: only 2 W knights", "8/1k6/8/8/8/8/6K1/1NN5 w - - 0 1" }, - { MOVEDO, + { __LINE__, MOVEDO, "simple movedo/undo: only 2 W knights", "8/1k6/8/8/8/8/6K1/1NN5 w - - 0 1" }, - { MOVEDO, + { __LINE__, MOVEDO, "simple movedo/undo: only 2 W knights", "5n2/1k6/8/8/5K2/8/P7/1N6 w - - 0 1" }, - { 0, NULL, NULL } + { __LINE__, 0, NULL, NULL } }; -static int cur = 0; +static int cur = -1; static char *next_fen(uint module) { + cur++; while (fentest[cur].fen && !(fentest[cur].modules & module)) cur++; - return fentest[cur].fen ? fentest[cur++].fen: NULL; + return fentest[cur].fen; } static __unused char* cur_comment() { return fentest[cur].comment; } + +static __unused int cur_line() +{ + return fentest[cur].line; +} diff --git a/test/movedo-test.c b/test/movedo-test.c index c498514..62a6179 100644 --- a/test/movedo-test.c +++ b/test/movedo-test.c @@ -26,9 +26,10 @@ int main(int __unused ac, __unused char**av) { - int i = 1; + int i = 0, test_line; char *fen, movebuf[8];; pos_t *pos, *savepos; + movelist_t pseudo; move_t move; setlinebuf(stdout); /* line-buffered stdout */ @@ -37,41 +38,48 @@ int main(int __unused ac, __unused char**av) hyperbola_init(); while ((fen = next_fen(MOVEGEN | MOVEDO))) { + test_line = cur_line(); if (!(pos = fen2pos(NULL, fen))) { printf("wrong fen %d: [%s]\n", i, fen); continue; } - pos_gen_pseudomoves(pos); + pos_gen_pseudomoves(pos, &pseudo); savepos = pos_dup(pos); - if (pos_cmp(pos, savepos) != true) { - printf("*** positions differ 1\n"); - exit(0); - } - int tmp = 0, j = 1; - while ((move = pos_next_legal(pos, &tmp)) != MOVE_NONE) { + int tmp = 0, j = 0; + while ((move = pos_next_legal(pos, &pseudo, &tmp)) != MOVE_NONE) { state_t state; - - pos_print(pos); - printf("i=%d j=%d turn=%d move=[%s]\n", i, j, pos->turn, - move_str(movebuf, move, 0)); + move_str(movebuf, move, 0); + //pos_print(pos); + //printf("i=%d j=%d turn=%d move=[%s]\n", i, j, pos->turn, + // move_str(movebuf, move, 0)); //move_p move_do(pos, move, &state); - pos_print(pos); - fflush(stdout); - pos_check(pos, true); - printf("%d/%d move_do check ok\n", i, j); - move_undo(pos, move, &state); - if (pos_cmp(pos, savepos) != true) { - printf("*** positions differ 2\n"); + //pos_print(pos); + //fflush(stdout); + if (pos_check(pos, false)) { + printf("*** fen %d move %d [%s] invalid position after move_do\n", + test_line, j, movebuf); exit(0); } - fflush(stdout); - pos_check(pos, true); - printf("%d/%d move_undo check ok\n", i, j); - if (j++ == 1000) + //printf("%d/%d move_do check ok\n", i, j); + move_undo(pos, move, &state); + if (pos_check(pos, false)) { + printf("*** fen %d move %d [%s] invalid position after move_undo\n", + test_line, j, movebuf); exit(0); + } + if (pos_cmp(pos, savepos) != true) { + printf("*** fen %d move %d [%s] position differ after move_{do,undo}\n", + test_line, j, movebuf); + exit(0); + } + //fflush(stdout); + //pos_check(pos, true); + //printf("%d/%d move_undo check ok\n", i, j); + j++; } + printf("fen %d line=%d [%s] %d move_{do,undo} OK\n", i, test_line, fen, j); pos_del(savepos); pos_del(pos); i++; diff --git a/test/movegen-test.c b/test/movegen-test.c index 08a0e09..4d71a0e 100644 --- a/test/movegen-test.c +++ b/test/movegen-test.c @@ -76,7 +76,7 @@ static FILE *open_stockfish() return out_desc; } -static void send_stockfish_fen(FILE *desc, pos_t *pos, char *fen) +static void send_stockfish_fen(FILE *desc, pos_t *pos, movelist_t *movelist, char *fen) { char *buf = NULL; int count, __unused mycount = 0, fishcount; @@ -85,8 +85,9 @@ static void send_stockfish_fen(FILE *desc, pos_t *pos, char *fen) pos_clear(pos); - move_t *moves = pos->moves.move; - int nmoves = pos->moves.nmoves; + move_t *moves = movelist->move; + int *nmoves = &movelist->nmoves; + *nmoves = 0; //char nodescount[] = "Nodes searched"; //printf("nmoves = %d\n", nmoves); fflush(stdout); @@ -109,7 +110,7 @@ static void send_stockfish_fen(FILE *desc, pos_t *pos, char *fen) // buf[0], buf[1], buf[2], buf[3], // sq_to_string(from), sq_to_string(to), // count); - moves[nmoves++] = move_make(from, to); + moves[(*nmoves)++] = move_make(from, to); } else if (sscanf(buf, "%*5s: %d", &count) == 1) { square_t from = sq_from_string(buf); @@ -120,10 +121,10 @@ static void send_stockfish_fen(FILE *desc, pos_t *pos, char *fen) // buf[0], buf[1], buf[2], buf[3], // sq_to_string(from), sq_to_string(to), // count); - moves[nmoves++] = move_make_promote(from, to, promoted); + moves[(*nmoves)++] = move_make_promote(from, to, promoted); } } - pos->moves.nmoves = nmoves; + //pos->moves.nmoves = nmoves; // printf("fishcount=%d mycount=%d\n", fishcount, mycount); free(buf); } @@ -215,7 +216,7 @@ int main(int __unused ac, __unused char**av) FILE *outfd; char *fen; pos_t *pos, *fishpos = pos_new(); - movelist_t legal; + movelist_t pseudo, legal, fishmoves; //bitboard_t wrong = 0x5088000040, tmp, loop; //bit_for_each64(loop, tmp, ) //printf("fishpos 1=%p\n", fishpos); @@ -235,9 +236,9 @@ int main(int __unused ac, __unused char**av) continue; } /* print movelists */ - send_stockfish_fen(outfd, fishpos, fen); - pos_gen_pseudomoves(pos); - pos_all_legal(pos, &legal); + send_stockfish_fen(outfd, fishpos, &fishmoves, fen); + pos_gen_pseudomoves(pos, &pseudo); + pos_all_legal(pos, &pseudo, &legal); //printf("Fu "); //moves_print(fishpos, 0); //fflush(stdout); @@ -246,7 +247,7 @@ int main(int __unused ac, __unused char**av) //fflush(stdout); /* sort and print movelists */ - move_sort_by_sq(&fishpos->moves); + move_sort_by_sq(&fishmoves); move_sort_by_sq(&legal); // printf("\nFs "); // moves_print(fishpos, 0); @@ -256,10 +257,10 @@ int main(int __unused ac, __unused char**av) // fflush(stdout); /* compare movelists */ - if (!movelists_equal(&fishpos->moves, &legal)) { + if (!movelists_equal(&fishmoves, &legal)) { pos_print(pos); printf("F: "); - moves_print(&fishpos->moves, 0); + moves_print(&fishmoves, 0); printf("M: "); moves_print(&legal, 0); } else {