Compare commits
8 Commits
9932a64c97
...
754b011d05
| Author | SHA1 | Date | |
|---|---|---|---|
| 754b011d05 | |||
| e2a3563fce | |||
| d852e0bc1d | |||
| 3de87daa5a | |||
| b5ed42746e | |||
| 0ca495576d | |||
| ed9b9cc646 | |||
| 88d2d4061f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,3 +19,4 @@ brchess
|
||||
/obj/
|
||||
/lib/
|
||||
/.deps/
|
||||
/notused/
|
||||
|
||||
@@ -28,6 +28,8 @@ k4n2/4P3/8/8/8/8/4p3/K4N2 w - - 0 1
|
||||
|
||||
# position after 1.e4
|
||||
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1
|
||||
# position after 1.Nh3
|
||||
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b KQkq - 1 1
|
||||
|
||||
# white castled, and can e.p. on c6 black can castle
|
||||
# white is a pawn down
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "move.h"
|
||||
#include "fen.h"
|
||||
#include "eval.h"
|
||||
#include "eval-simple.h"
|
||||
#include "search.h"
|
||||
|
||||
struct command {
|
||||
@@ -60,11 +61,13 @@ int do_prmoves(pos_t *, char*);
|
||||
int do_prpieces(pos_t *pos, char *arg);
|
||||
int do_memstats(pos_t *, char*);
|
||||
int do_eval(pos_t *, char*);
|
||||
int do_simple_eval(pos_t *, char*);
|
||||
int do_move(pos_t *, char*);
|
||||
int do_quit(pos_t *, char*);
|
||||
int do_debug(pos_t *, char*);
|
||||
int do_depth(pos_t *, char*);
|
||||
int do_search(pos_t *, char*);
|
||||
int do_pvs(pos_t *, char*);
|
||||
|
||||
struct command commands[] = {
|
||||
{ "help", do_help, "Display this text" },
|
||||
@@ -79,10 +82,12 @@ struct command commands[] = {
|
||||
{ "prpieces", do_prpieces, "Print Pieces (from pieces lists)" },
|
||||
{ "memstats", do_memstats, "Generate next move list" },
|
||||
{ "eval", do_eval, "Eval current position" },
|
||||
{ "simple-eval", do_simple_eval, "Simple eval current position" },
|
||||
{ "do_move", do_move, "execute nth move on current position" },
|
||||
{ "debug", do_debug, "Set log level to LEVEL" },
|
||||
{ "depth", do_depth, "Set search depth to N" },
|
||||
{ "search", do_search, "Search best move" },
|
||||
{ "search", do_search, "Search best move (negamax)" },
|
||||
{ "pvs", do_pvs, "Search best move (Principal Variation Search)" },
|
||||
{ NULL, (int(*)()) NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -277,6 +282,13 @@ int do_eval(__unused pos_t *pos, __unused char *arg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_simple_eval(__unused pos_t *pos, __unused char *arg)
|
||||
{
|
||||
eval_t eval = eval_simple(pos);
|
||||
printf("eval = %d centipawns\n", eval);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_fen(pos_t *pos, char *arg)
|
||||
{
|
||||
fen2pos(pos, arg);
|
||||
@@ -425,13 +437,46 @@ int do_depth(__unused pos_t *pos, char *arg)
|
||||
int do_search(pos_t *pos, __unused char *arg)
|
||||
{
|
||||
int debug_level = debug_level_get();
|
||||
long long timer1, timer2;
|
||||
float nodes_sec;
|
||||
|
||||
timer1 = debug_timer_elapsed();
|
||||
negamax(pos, depth, pos->turn == WHITE ? 1 : -1);
|
||||
timer2 = debug_timer_elapsed();
|
||||
nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
|
||||
debug_level_set(1);
|
||||
log(1, "best=");
|
||||
move_print(0, pos->bestmove, 0);
|
||||
log(1, " negamax=%d\n", pos->bestmove->negamax);
|
||||
debug_level_set(debug_level);
|
||||
printf("Total nodes: %lu time=%lld %.0f nodes/sec\n",
|
||||
pos->node_count, timer2 - timer1, nodes_sec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_pvs(pos_t *pos, __unused char *arg)
|
||||
{
|
||||
int debug_level = debug_level_get();
|
||||
long long timer1, timer2;
|
||||
float nodes_sec;
|
||||
eval_t _pvs;
|
||||
|
||||
timer1 = debug_timer_elapsed();
|
||||
moves_gen_eval_sort(pos);
|
||||
_pvs = pvs(pos, depth, EVAL_MIN, EVAL_MAX, pos->turn == WHITE ? 1 : -1);
|
||||
timer2 = debug_timer_elapsed();
|
||||
nodes_sec = (float) pos->node_count / ((float) (timer2 - timer1) / (float)NANOSEC);
|
||||
debug_level_set(1);
|
||||
log(1, "best=");
|
||||
if (pos->bestmove) {
|
||||
move_print(0, pos->bestmove, 0);
|
||||
log(1, " pvs=%d stored=%d\n", _pvs, pos->bestmove->negamax);
|
||||
} else {
|
||||
log(1, "<no-best-move>");
|
||||
}
|
||||
debug_level_set(debug_level);
|
||||
printf("Total nodes: %lu time=%lld %.0f nodes/sec\n",
|
||||
pos->node_count, timer2 - timer1, nodes_sec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -459,6 +504,7 @@ int main(int ac, char **av)
|
||||
pos_pool_init();
|
||||
pos = pos_get();
|
||||
debug_init(1, stderr, true);
|
||||
eval_simple_init();
|
||||
|
||||
while ((opt = getopt(ac, av, "d:f:")) != -1) {
|
||||
switch (opt) {
|
||||
|
||||
@@ -164,7 +164,7 @@ eval_t eval_simple(pos_t *pos)
|
||||
|
||||
pos->eval_simple_phase = ENDGAME;
|
||||
# ifdef DEBUG_EVAL
|
||||
log_f(1, "phase = %s.\n", eg? "endgame": "midgame");
|
||||
log_f(5, "phase = %s.\n", eg? "endgame": "midgame");
|
||||
# endif
|
||||
|
||||
for (int color = WHITE; color <= BLACK; ++color) {
|
||||
@@ -173,25 +173,26 @@ eval_t eval_simple(pos_t *pos)
|
||||
u64 _t;
|
||||
|
||||
# ifdef DEBUG_EVAL
|
||||
log_f(1, "p=%u bb=%d %s %s: count=%d val=%ld ", piece, bb, color? "black": "white",
|
||||
log_f(5, "p=%u bb=%d %s %s: count=%d val=%ld ", piece, bb, color? "black": "white",
|
||||
P_SYM(piece), popcount64(pos->bb[color][bb]),
|
||||
popcount64(pos->bb[color][bb]) * P_VALUE(piece));
|
||||
# endif
|
||||
|
||||
eval[color] += popcount64(pos->bb[color][bb]) * P_LETTER(piece);
|
||||
bit_for_each64_2(cur, _t, pos->bb[color][piece]) {
|
||||
bit_for_each64_2(cur, _t, pos->bb[color][bb]) {
|
||||
# ifdef DEBUG_EVAL
|
||||
log(1, "sq=%d:%d ", cur, gg[color][bb][cur]);
|
||||
log(5, "sq=%d:%d ", cur, gg[color][bb][cur]);
|
||||
# endif
|
||||
eval[color] += gg[color][bb][cur];
|
||||
}
|
||||
# ifdef DEBUG_EVAL
|
||||
log(1, "\n");
|
||||
log(5, "\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
# ifdef DEBUG_EVAL
|
||||
log_f(1, "white: %d black:%d\n", eval[WHITE], eval[BLACK]);
|
||||
log_f(2, "eval:%d white:%d black:%d\n", eval[WHITE] - eval[BLACK],
|
||||
eval[WHITE], eval[BLACK]);
|
||||
# endif
|
||||
|
||||
return eval[WHITE] - eval[BLACK];
|
||||
|
||||
13
src/eval.c
13
src/eval.c
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "position.h"
|
||||
#include "eval.h"
|
||||
#include "eval-simple.h"
|
||||
|
||||
inline eval_t eval_material(pos_t *pos, bool color)
|
||||
{
|
||||
@@ -51,18 +52,18 @@ inline eval_t eval_square_control(pos_t *pos, bool color)
|
||||
|
||||
eval_t eval(pos_t *pos)
|
||||
{
|
||||
eval_t material[2] = {0}, control[2] = {0};
|
||||
eval_t simple = 0, control[2] = {0};
|
||||
|
||||
if (pos->eval != EVAL_INVALID)
|
||||
return pos->eval;
|
||||
|
||||
/* 1) pieces value */
|
||||
material[WHITE] = eval_material(pos, WHITE);
|
||||
material[BLACK] = eval_material(pos, BLACK);
|
||||
//material[WHITE] = eval_material(pos, WHITE);
|
||||
//material[BLACK] = eval_material(pos, BLACK);
|
||||
simple = eval_simple(pos);
|
||||
|
||||
# ifdef DEBUG_EVAL
|
||||
log_f(2, "material: W:%d B:%d diff=%d\n",
|
||||
material[WHITE], material[BLACK], material[WHITE] - material[BLACK]);
|
||||
log_f(2, "eval_simple=%d\n", simple);
|
||||
# endif
|
||||
|
||||
/* 2) square control: 10 square controls diff = 1 pawn */
|
||||
@@ -83,7 +84,7 @@ eval_t eval(pos_t *pos)
|
||||
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10);
|
||||
# endif
|
||||
|
||||
eval_t res = material[WHITE] - material[BLACK] +
|
||||
eval_t res = simple +
|
||||
(control[WHITE] - control[BLACK]) * 10 +
|
||||
(pos->mobility[WHITE] - pos->mobility[BLACK]) * 10;
|
||||
# ifdef DEBUG_EVAL
|
||||
|
||||
11
src/eval.h
11
src/eval.h
@@ -19,13 +19,12 @@
|
||||
#include "chessdefs.h"
|
||||
#include "piece.h"
|
||||
|
||||
#define EVAL_MAX \
|
||||
KING_VALUE + \
|
||||
QUEEN_VALUE * 9 + \
|
||||
ROOK_VALUE * 2 + \
|
||||
BISHOP_VALUE * 2 + \
|
||||
KNIGHT_VALUE * 2
|
||||
/* max pieces eval is KING_VALUE + 9*QUEEN_VALUE + 2*ROOK_VALUE + 2*BISHOP_VALUE
|
||||
* + 2*KNIGHT_VALUE which around 30000.
|
||||
* We are on secure sire with -50000/+50000
|
||||
*/
|
||||
|
||||
#define EVAL_MAX (50000)
|
||||
#define EVAL_MIN (-EVAL_MAX)
|
||||
#define EVAL_INVALID INT_MIN
|
||||
|
||||
|
||||
80
src/move.c
80
src/move.c
@@ -16,12 +16,15 @@
|
||||
|
||||
#include <br.h>
|
||||
#include <list.h>
|
||||
#include <list_sort.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "chessdefs.h"
|
||||
#include "board.h"
|
||||
#include "piece.h"
|
||||
#include "move.h"
|
||||
#include "eval.h"
|
||||
#include "eval-simple.h"
|
||||
|
||||
static pool_t *moves_pool;
|
||||
|
||||
@@ -37,6 +40,7 @@ static struct vector {
|
||||
[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)
|
||||
*/
|
||||
@@ -74,6 +78,7 @@ void moves_pool_stats()
|
||||
* 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
|
||||
*/
|
||||
@@ -117,6 +122,8 @@ int move_print(int movenum, move_t *move, move_flags_t flags)
|
||||
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, " ");
|
||||
}
|
||||
@@ -193,6 +200,7 @@ static move_t *move_add(pos_t *pos, piece_t piece, square_t from,
|
||||
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",
|
||||
@@ -219,6 +227,8 @@ void move_del(struct list_head *ptr)
|
||||
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;
|
||||
@@ -659,32 +669,94 @@ int moves_gen_king_moves(pos_t *pos, bool color, bool doit)
|
||||
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_gen_all() - calculate all moves
|
||||
* 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
|
||||
*
|
||||
* Compute pseudo moves for both sides.
|
||||
* 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);
|
||||
//move_print(0, move, M_PR_NL | M_PR_LONG);
|
||||
# endif
|
||||
|
||||
pos_t *new = pos_dup(pos);
|
||||
@@ -693,8 +765,6 @@ pos_t *move_do(pos_t *pos, move_t *move)
|
||||
square_t from = move->from, to = move->to;
|
||||
u64 bb_from = SQ88_2_BB(from), bb_to = SQ88_2_BB(to);
|
||||
|
||||
//printf("Piece color=%d\n", color);
|
||||
|
||||
if (move->capture || piece == PAWN) /* 50 moves */
|
||||
new->clock_50 = 0;
|
||||
else
|
||||
|
||||
@@ -36,6 +36,7 @@ typedef unsigned char move_flags_t;
|
||||
#define M_PR_NCAPT 0x02
|
||||
#define M_PR_NUM 0x04
|
||||
#define M_PR_NL 0x08
|
||||
#define M_PR_EVAL 0x20 /* separate captures */
|
||||
#define M_PR_SEPARATE 0x40 /* separate captures */
|
||||
#define M_PR_LONG 0x80
|
||||
|
||||
@@ -46,6 +47,9 @@ typedef struct move_s {
|
||||
piece_t promotion; /* promoted piece */
|
||||
move_flags_t flags;
|
||||
eval_t negamax;
|
||||
eval_t eval;
|
||||
eval_t eval_simple;
|
||||
pos_t *pos;
|
||||
struct list_head list; /* next move */
|
||||
} move_t;
|
||||
|
||||
@@ -62,7 +66,12 @@ int pseudo_moves_gen(pos_t *pos, piece_list_t *piece, bool doit, bool do_king);
|
||||
int pseudo_moves_pawn(pos_t *pos, piece_list_t *piece, bool doit);
|
||||
int moves_gen(pos_t *pos, bool color, bool doit, bool do_king);
|
||||
int moves_gen_king_moves(pos_t *pos, bool color, bool doit);
|
||||
|
||||
void moves_sort(pos_t *pos);
|
||||
void moves_gen_eval_sort(pos_t *pos);
|
||||
|
||||
void moves_gen_all(pos_t *pos);
|
||||
void moves_gen_all_nomoves(pos_t *pos);
|
||||
|
||||
pos_t *move_do(pos_t *pos, move_t *move);
|
||||
void move_undo(pos_t *pos, move_t *move);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "move.h"
|
||||
#include "fen.h"
|
||||
#include "piece.h"
|
||||
#include "eval.h"
|
||||
|
||||
static pool_t *pos_pool;
|
||||
|
||||
@@ -199,6 +200,7 @@ pos_t *pos_clear(pos_t *pos)
|
||||
}
|
||||
|
||||
SET_WHITE(pos->turn);
|
||||
pos->node_count = 0;
|
||||
pos->castle = 0;
|
||||
pos->clock_50 = 0;
|
||||
pos->curmove = 0;
|
||||
@@ -213,6 +215,8 @@ pos_t *pos_clear(pos_t *pos)
|
||||
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);
|
||||
@@ -260,8 +264,13 @@ pos_t *pos_get()
|
||||
* pos_dup() - duplicate a position.
|
||||
* @pos: &position to duplicate.
|
||||
*
|
||||
* New position is the same as source one, with duplicated pieces list
|
||||
* and empty moves list and NULL bestmove.
|
||||
* 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
|
||||
*
|
||||
* @return: The new position.
|
||||
*
|
||||
@@ -280,7 +289,6 @@ pos_t *pos_dup(pos_t *pos)
|
||||
for (int color = 0; color < 2; ++color) {
|
||||
INIT_LIST_HEAD(&new->pieces[color]);
|
||||
INIT_LIST_HEAD(&new->moves[color]);
|
||||
new->bestmove = NULL;
|
||||
/* duplicate piece list */
|
||||
piece_list = &pos->pieces[color]; /* white/black piece list */
|
||||
|
||||
@@ -290,6 +298,11 @@ pos_t *pos_dup(pos_t *pos)
|
||||
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;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
||||
@@ -23,12 +23,17 @@
|
||||
#include "chessdefs.h"
|
||||
|
||||
typedef struct pos_s {
|
||||
u64 node_count; /* evaluated nodes */
|
||||
piece_t turn; /* we use only color bit */
|
||||
castle_t castle;
|
||||
u16 clock_50;
|
||||
u16 curmove;
|
||||
eval_t eval;
|
||||
int eval_simple_phase;
|
||||
eval_t eval_simple;
|
||||
move_t *bestmove;
|
||||
bool moves_generated;
|
||||
bool moves_counted;
|
||||
board_t board[BOARDSIZE];
|
||||
|
||||
square_t en_passant;
|
||||
|
||||
60
src/search.c
60
src/search.c
@@ -37,6 +37,7 @@ eval_t negamax(pos_t *pos, int depth, int color)
|
||||
pos_t *newpos;
|
||||
eval_t best = EVAL_MIN, score;
|
||||
|
||||
pos->node_count++;
|
||||
if (depth == 0) {
|
||||
moves_gen_all_nomoves(pos);
|
||||
score = eval(pos) * color;
|
||||
@@ -70,53 +71,74 @@ eval_t negamax(pos_t *pos, int depth, int color)
|
||||
* Calculate the PVS value of @pos.
|
||||
* See https://en.wikipedia.org/wiki/Principal_variation_search
|
||||
*
|
||||
* Moves list should be first generated and evaluated/sorted.
|
||||
*
|
||||
* @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;
|
||||
int n = 0;
|
||||
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);
|
||||
moves_gen_all(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_eval_sort(pos);
|
||||
|
||||
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) {
|
||||
log(1, "%.*s", 5 - depth, " ");
|
||||
newpos = move->pos;
|
||||
log_f(1, "depth=%d eval=%d move=", depth, move->eval);
|
||||
move_print(0, move, M_PR_EVAL);
|
||||
log(1, "\n");
|
||||
if (!n++) { /* first child */
|
||||
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);
|
||||
if (score > alpha && score < beta) {
|
||||
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 */
|
||||
score = -pvs(newpos, depth - 1, -beta, -score, -color);
|
||||
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_undo(newpos, move);
|
||||
move->pos = NULL;
|
||||
pos->node_count += newpos->node_count;
|
||||
move->negamax = score;
|
||||
// alpha = max(alpha, score);
|
||||
if (alpha > beta) { /* beta cut-off */
|
||||
break;
|
||||
}
|
||||
firstchild = false;
|
||||
}
|
||||
|
||||
return alpha;
|
||||
|
||||
Reference in New Issue
Block a user