Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transposition #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "attacks.h"
#include "uci.h"
#include "zobrist.h"
#include "transposition.h"

void print_bitboard(BITBOARD bb) {
printf("--------\n");
Expand All @@ -47,9 +48,12 @@ int main() {

initialize_magic();
initialize_hash();
initialize_tt();

uci();

tt_free();

return 0;
}

3 changes: 3 additions & 0 deletions src/chess.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ typedef uint8_t CASTLE;
/* max half moves in a game */
#define MAX_GAME_PLYS 2048

#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))

#endif /* ifndef _CHESS_H_ */
80 changes: 61 additions & 19 deletions src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "movelist.h"
#include "pv.h"
#include "chess.h"
#include "transposition.h"

static struct timespec start;

Expand Down Expand Up @@ -191,11 +192,14 @@ int negascout(BOARD* board,
PV ** npv,
KILLER * killer) {
PV * lpv;
const TT_RESULT * tt;
int legal_found = 0;
int score;
int score = -10001;
int beta2;
unsigned long long delta;
int count;
int alpha_orig = alpha;
int save_depth = 0;

assert(0 <= reduced_depth && reduced_depth <= depth);

Expand All @@ -217,14 +221,33 @@ int negascout(BOARD* board,
}
}

if (reduced_depth == 0) {
return quiesce(board, alpha, beta);
}

if (repetition(board)) {
return 0;
}

if (NULL != (tt = tt_probe(board->history[board->halfmovecnt].hash, reduced_depth))) {
switch (tt->type) {
case TT_TYPE_EXACT:
return tt->score;
case TT_TYPE_LOWER:
alpha = MAX(alpha, tt->score);
break;
case TT_TYPE_UPPER:
beta = MIN(beta, tt->score);
break;
}

if (alpha >= beta) {
return tt->score;
}
}

if (reduced_depth == 0) {
score = quiesce(board, alpha, beta);
/* tt_insert_or_replace(board->history[board->halfmovecnt].hash, 0, score, TT_TYPE_EXACT); */
return score;
}

lpv = pv_init();

ml_open_frame();
Expand All @@ -236,40 +259,42 @@ int negascout(BOARD* board,
count = 1;

for (MOVE * ptr = ml_sort(board, pv_getmove(opv, ply), depth, killer); ptr != NULL; ptr = ptr->next) {
int this;
int depth_for_count = lmr(reduced_depth, count);

execute_move(board, ptr);

if (in_check(board, 1 - board->next)) {
/* illegal move */
undo_move(board, ptr);
continue;
}

pv_reset(lpv);

score = -negascout(board, ply + 1, depth - 1, lmr(reduced_depth, count), -beta2, -alpha, opv, &lpv, killer);
this = -negascout(board, ply + 1, depth - 1, depth_for_count, -beta2, -alpha, opv, &lpv, killer);

if (alpha < score && score < beta && legal_found) {
score = -negascout(board, ply + 1, depth - 1, lmr(reduced_depth, count), -beta, -alpha, opv, &lpv, killer);
if (alpha < this && this < beta && legal_found) {
this = -negascout(board, ply + 1, depth - 1, depth_for_count, -beta, -alpha, opv, &lpv, killer);
}

undo_move(board, ptr);

if (alpha < score || (alpha == score && !legal_found)) {
legal_found = 1;

if (score < this) {
pv_insert(lpv, ptr, ply);
pv_swap(&lpv, npv);
alpha = score;
save_depth = depth_for_count;
score = this;
}

legal_found = 1;
alpha = MAX(alpha, this);

if (alpha >= beta) {
save_killer(killer, depth, ptr);

pv_destroy(lpv);

ml_close_frame();

return alpha;
break;
}

beta2 = alpha + 1;
Expand All @@ -283,12 +308,26 @@ int negascout(BOARD* board,

if (!legal_found) {
if (in_check(board, board->next))
return -10000;
score = -10000;
else
return 0;
score = 0;
/* insert at max depth because either checkmate or stalemate node */
/* tt_insert_or_replace(board->history[board->halfmovecnt].hash, MAX_PLYS, score, TT_TYPE_EXACT); */
} else {
TT_TYPE type;

if (score <= alpha_orig) {
type = TT_TYPE_LOWER;
} else if (score >= beta) {
type = TT_TYPE_UPPER;
} else {
type = TT_TYPE_EXACT;
}

tt_insert_or_replace(board->history[board->halfmovecnt].hash, save_depth, score, type);
}

return alpha;
return score;
}

#define MOVES_TO_GO 25
Expand All @@ -306,6 +345,8 @@ int iterative_deepening(BOARD * board, const SEARCH_LIMIT * search_limit) {
printf("info clock_gettime failed\n");
}

tt_reset();

switch (search_limit->type) {
case SL_INFINITE: max_depth = 1000; movetime = 0; break;
case SL_DEPTH: max_depth = search_limit->data.depth; movetime = 0; break;
Expand Down Expand Up @@ -362,6 +403,7 @@ int iterative_deepening(BOARD * board, const SEARCH_LIMIT * search_limit) {

delta = time_delta();

tt_info();
printf("info score cp %d depth %d time %llu pv ", score, depth, delta);

for (int i = 0; i < pv_count(npv); ++i) {
Expand Down
79 changes: 79 additions & 0 deletions src/transposition.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "transposition.h"

#include <stdlib.h>
#include <stdio.h>


unsigned long tt_hitcnt;
unsigned long tt_misscnt;

typedef struct __ENTRY__ {
#define TT_LANE1_VALID 0x00000001
#define TT_LANE2_VALID 0x00000002
unsigned int flags;
TT_RESULT lane[2];
} ENTRY;

#define TT_SIZE 262144
ENTRY * table;

void initialize_tt() {
if (NULL == (table = calloc(TT_SIZE, sizeof(ENTRY)))) {
abort();
}

tt_reset();
}

void tt_reset() {
int i;

tt_hitcnt = 0;
tt_misscnt = 0;

for (i = 0; i < TT_SIZE; ++i) {
table[i].flags = 0;
}
}

void tt_free() {
free(table);
}

const TT_RESULT * tt_probe(HASH hash, int depth) {
unsigned int index = hash % TT_SIZE;
int i;

for (i = 0; i < 2; ++i) {
if ((table[index].flags & (1 << i)) && table[index].lane[i].hash == hash && table[index].lane[i].depth >= depth) {
tt_hitcnt++;
return & table[index].lane[i];
}
}

tt_misscnt++;

return NULL;
}

void tt_info() {
printf("info tt hits %ld misses %ld\n", tt_hitcnt, tt_misscnt);
}

void tt_insert_or_replace(HASH hash, int depth, int score, TT_TYPE type) {
unsigned int index = hash % TT_SIZE;

if ((! (table[index].flags & TT_LANE1_VALID)) || table[index].lane[0].depth < depth) {
table[index].flags |= TT_LANE1_VALID;
table[index].lane[0].hash = hash;
table[index].lane[0].type = type;
table[index].lane[0].score = score;
table[index].lane[0].depth = depth;
} else {
table[index].flags |= TT_LANE2_VALID;
table[index].lane[1].hash = hash;
table[index].lane[1].type = type;
table[index].lane[1].score = score;
table[index].lane[1].depth = depth;
}
}
24 changes: 24 additions & 0 deletions src/transposition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef __TRANSPOSITION_H__
#define __TRANSPOSITION_H__

#include "zobrist.h"

typedef enum { TT_TYPE_EXACT = 1, TT_TYPE_LOWER = 2, TT_TYPE_UPPER = 3 } TT_TYPE;

typedef struct __TT_RESULT__ {
HASH hash;
TT_TYPE type;
int score;
int depth;
} TT_RESULT;

/* Implements a 2 lane transposition table, with lane 1 greater depth and lane 2 always replacement policies. */

void initialize_tt();
void tt_reset();
void tt_free();
void tt_info();
const TT_RESULT * tt_probe(HASH hash, int depth);
void tt_insert_or_replace(HASH hash, int depth, int score, TT_TYPE type);

#endif /* ifndef __TRANSPOSITION_H__ */