Compare commits
3 Commits
0ff41c408b
...
f7fd2cb657
Author | SHA1 | Date | |
---|---|---|---|
f7fd2cb657 | |||
1ca4eb4443 | |||
e1debcc3ae |
80
src/perft.c
80
src/perft.c
@@ -20,59 +20,79 @@
|
|||||||
#include "move-do.h"
|
#include "move-do.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* perft() - Perform perft on position
|
* do_perft() - perft engine
|
||||||
* @pos: &position to search
|
* @pos: &position to search
|
||||||
* @depth: Wanted depth.
|
* @depth: Wanted depth.
|
||||||
* @ply: current perft depth level (root = 1)
|
|
||||||
* @divide: output total for 1st level moves.
|
|
||||||
*
|
*
|
||||||
* Run perft on a position. This function displays the available moves at @depth
|
* Run perft on a position.
|
||||||
* level for each possible first move, and the total of moves.
|
|
||||||
*
|
*
|
||||||
* This version uses the algorithm:
|
* This version uses the algorithm:
|
||||||
* if last depth
|
|
||||||
* return 1;
|
|
||||||
* gen legal moves
|
* gen legal moves
|
||||||
|
* if last depth
|
||||||
|
* return number of legal move
|
||||||
* loop for legal move
|
* loop for legal move
|
||||||
* do-move
|
* do-move
|
||||||
* perft (depth -1)
|
* if depth == 2
|
||||||
|
*
|
||||||
|
* do_perft (depth -1)
|
||||||
* undo-move
|
* undo-move
|
||||||
*
|
*
|
||||||
* @return: total moves found at @depth level.
|
* @return: total moves found at @depth level.
|
||||||
*/
|
*/
|
||||||
static u64 do_perft(pos_t *pos, int depth)
|
static u64 do_perft(pos_t *pos, int depth)
|
||||||
{
|
{
|
||||||
u64 subnodes = 0, nodes = 0;
|
u64 nodes = 0;
|
||||||
movelist_t movelist;
|
movelist_t movelist;
|
||||||
move_t *move, *last;
|
move_t *move, *last;
|
||||||
state_t state;
|
state_t state;
|
||||||
|
|
||||||
pos_set_checkers_pinners_blockers(pos);
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
|
pos_legal(pos, pos_gen_pseudo(pos, &movelist));
|
||||||
if (depth == 1)
|
|
||||||
return movelist.nmoves;
|
|
||||||
last = movelist.move + movelist.nmoves;
|
|
||||||
|
|
||||||
for (move = movelist.move; move < last; ++move) {
|
//if (depth == 1)
|
||||||
move_do(pos, *move, &state);
|
// return movelist.nmoves;
|
||||||
if (depth == 2) {
|
|
||||||
movelist_t movelist2;
|
last = movelist.move + movelist.nmoves;
|
||||||
pos_set_checkers_pinners_blockers(pos);
|
switch (depth) {
|
||||||
subnodes = pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
|
case 1:
|
||||||
} else if (pos->plyroot >= 3) {
|
/* This case could be removed if 'case 2' is handled in perft()
|
||||||
hentry_t *entry = tt_probe_perft(pos->key, depth);
|
*/
|
||||||
if (entry != TT_MISS) {
|
return movelist.nmoves;
|
||||||
subnodes = HASH_PERFT_VAL(entry->data);
|
break;
|
||||||
} else {
|
case 2:
|
||||||
subnodes = do_perft(pos, depth - 1);
|
/* For depth 2, we directly calculate the possible legal moves
|
||||||
tt_store_perft(pos->key, depth, subnodes);
|
* after each possible moves.
|
||||||
|
*/
|
||||||
|
for (move = movelist.move; move < last; ++move) {
|
||||||
|
move_do(pos, *move, &state);
|
||||||
|
movelist_t movelist2;
|
||||||
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
|
nodes += pos_legal(pos, pos_gen_pseudo(pos, &movelist2))->nmoves;
|
||||||
|
move_undo(pos, *move, &state);
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
subnodes = do_perft(pos, depth - 1);
|
default:
|
||||||
}
|
/* Default: Search in TT for same key+depth. Use it if found, create
|
||||||
move_undo(pos, *move, &state);
|
* it otherwise.
|
||||||
nodes += subnodes;
|
*/
|
||||||
|
for (move = movelist.move; move < last; ++move) {
|
||||||
|
move_do(pos, *move, &state);
|
||||||
|
hentry_t *entry = tt_probe_perft(pos->key, depth);
|
||||||
|
if (entry != TT_MISS) {
|
||||||
|
nodes += HASH_PERFT_VAL(entry->data);
|
||||||
|
} else {
|
||||||
|
u64 subnodes = do_perft(pos, depth - 1);
|
||||||
|
tt_store_perft(pos->key, depth, subnodes);
|
||||||
|
nodes += subnodes;
|
||||||
|
}
|
||||||
|
move_undo(pos, *move, &state);
|
||||||
|
}
|
||||||
|
//} else {
|
||||||
|
//subnodes = do_perft(pos, depth - 1);
|
||||||
}
|
}
|
||||||
|
//move_undo(pos, *move, &state);
|
||||||
|
//nodes += subnodes;
|
||||||
|
//}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
58
src/search.c
58
src/search.c
@@ -47,34 +47,36 @@ bool is_draw(pos_t *pos)
|
|||||||
*
|
*
|
||||||
* @return: The @pos negamax evaluation.
|
* @return: The @pos negamax evaluation.
|
||||||
*/
|
*/
|
||||||
/*
|
eval_t negamax(pos_t *pos, int depth, int color)
|
||||||
* eval_t negamax(pos_t *pos, int depth, int color)
|
{
|
||||||
* {
|
move_t *move, *last;
|
||||||
* move_t *move;
|
state_t state;
|
||||||
* pos_t *newpos;
|
eval_t best = EVAL_MIN, score;
|
||||||
* eval_t best = EVAL_MIN, score;
|
movelist_t movelist;
|
||||||
*
|
|
||||||
* pos->node_count++;
|
pos->node_count++;
|
||||||
* if (depth == 0) {
|
if (depth == 0) {
|
||||||
* moves_gen_all_nomoves(pos);
|
score = eval(pos) * color;
|
||||||
* score = eval(pos) * color;
|
return score;
|
||||||
* return score;
|
}
|
||||||
* }
|
pos_set_checkers_pinners_blockers(pos);
|
||||||
* moves_gen_all(pos);
|
pos_gen_legal(pos, &movelist);
|
||||||
* list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
last = movelist.move + movelist.nmoves;
|
||||||
* newpos = move_do(pos, move);
|
//moves_gen_all(pos);
|
||||||
* score = -negamax(newpos, depth - 1, -color);
|
for (move = movelist.move; move < last; ++move) {
|
||||||
* pos->node_count += newpos->node_count;
|
//list_for_each_entry(move, &pos->moves[pos->turn], list) {
|
||||||
* move->negamax = score;
|
move_do(pos, *move, &state);
|
||||||
* if (score > best) {
|
score = -negamax(pos, depth - 1, -color);
|
||||||
* best = score;
|
pos->node_count += pos->node_count;
|
||||||
* pos->bestmove = move;
|
//move->negamax = score;
|
||||||
* }
|
if (score > best) {
|
||||||
* move_undo(newpos, move);
|
best = score;
|
||||||
* }
|
pos->eval = best;
|
||||||
* return best;
|
}
|
||||||
* }
|
move_undo(pos, *move, &state);
|
||||||
*/
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
70
src/thread.c
Normal file
70
src/thread.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* thread.c - thread management.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <brlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
/* Still have to decide: thread or process ?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
thread_pool_t threadpool;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thrd_create - initialize thrd.
|
||||||
|
*/
|
||||||
|
int thrd_create(__unused int num)
|
||||||
|
{
|
||||||
|
int fd[2];
|
||||||
|
/* shall we make a communication channel via a pipe or socket ? */
|
||||||
|
int __unused ret = socketpair(AF_LOCAL, SOCK_SEQPACKET, PF_LOCAL, fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* thread_init - initialize thread pool.
|
||||||
|
*/
|
||||||
|
int thread_init(int nb)
|
||||||
|
{
|
||||||
|
nb = clamp(nb, MIN_THRDS, MAX_THRDS);
|
||||||
|
|
||||||
|
/* stop unwanted threads, always keep 1 */
|
||||||
|
for (int i = nb + 1; i < threadpool.nb; ++i) {
|
||||||
|
printf("stopping thread %d - status = \n", i);
|
||||||
|
threadpool.thread[i].cmd = THRD_DO_QUIT;
|
||||||
|
}
|
||||||
|
for (int i = threadpool.nb; i < nb; ++i) {
|
||||||
|
printf("creating thread %d - status = \n", i);
|
||||||
|
thrd_create(i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
communication:
|
||||||
|
main thread -> thread
|
||||||
|
commands via memory
|
||||||
|
thread -> main thread
|
||||||
|
status via memory
|
||||||
|
output via pipe/socket
|
||||||
|
thread output will be output/filtered by main thread
|
||||||
|
|
||||||
|
*/
|
55
src/thread.h
Normal file
55
src/thread.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/* thread.h - thread management.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021-2024 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 <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef THREAD_H
|
||||||
|
#define THREAD_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <brlib.h>
|
||||||
|
|
||||||
|
#include "position.h"
|
||||||
|
|
||||||
|
#define MIN_THRDS 1
|
||||||
|
#define MAX_THRDS 16
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
THRD_DEAD,
|
||||||
|
THRD_IDLE,
|
||||||
|
THRD_WORKING,
|
||||||
|
} thread_status_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* main thread to subs */
|
||||||
|
THRD_DO_SEARCH,
|
||||||
|
THRD_DO_STOP,
|
||||||
|
THRD_DO_QUIT,
|
||||||
|
} thread_cmd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int id;
|
||||||
|
thread_status_t status;
|
||||||
|
thread_cmd_t cmd;
|
||||||
|
int fd[2];
|
||||||
|
pos_t pos;
|
||||||
|
} thread_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int nb;
|
||||||
|
thread_t thread[MAX_THRDS + 1];
|
||||||
|
} thread_pool_t;
|
||||||
|
|
||||||
|
int thrd_create(__unused int num);
|
||||||
|
int thread_init(int nb);
|
||||||
|
|
||||||
|
#endif /* THREAD_H */
|
Reference in New Issue
Block a user