home / fornax / fornax-v4-0 / src / supplementary / opening_book.cpp

opening_book.cpp



//
//  opening_book.cpp
//  fornax3
//
//  Created by Anders on 28/03/2020.
//

#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <stdio.h>
#include "opening_book.hpp"
#include "../libs/require.h"
#include "../libs/iolog.hpp"
#include "parsing.hpp"
#include "../moving/movegen.hpp"
#include "../moving/makemove.hpp"

#define BOOK_SIZE_MAX 50//max positions in the book
#define MOVES_SIZE_MAX 20 //max alternative moves for each position
#define PLY_MAX 10// max depth before book is disabled
static bool enabled = false;

typedef struct {
  uint64_t ttkey;
  move m[MOVES_SIZE_MAX];
  uint8_t count;
} Opening;

static Opening* openings;

static Opening* opening_book_find(const Board* board) {
  int i = 0;
  Opening* opening;
  while ((opening = &openings[i++])->ttkey != 0) {
    
    if (opening->ttkey == board_get_hash(board)) {
      return opening;
    }
  }
  return NULL;
}

static void opening_register(const Board* board, const char* ucimove) {
  
  Board b = *board;
  move m = parsing_move_from_uci(ucimove);
  
  require(parsing_is_valid_move(&b, m), "illegal move %s\n", ucimove);
  
  Opening* opening = opening_book_find(&b);
  if (opening != NULL) {
    require(opening->count < MOVES_SIZE_MAX, "too many moves for this position, size=%d\n", MOVES_SIZE_MAX);
    opening->m[opening->count] = m;
    opening->count++;

    return;
  }
  
  int i = 0;
  while ((openings[i]).ttkey != 0) i++;
  require(i < BOOK_SIZE_MAX, "book was full, size=%d\n", BOOK_SIZE_MAX);
  Opening o;
  o.ttkey = b.plyinfo[b.ply].hash;
  o.m[0] = m;
  o.count = 1;
  openings[i] = o;
}

static void opening_moves_to_board(Board* board, ...) {
  
  const char* ucimove;
  
  va_list arglist;
  va_start(arglist, board);
  
  while ((ucimove = va_arg(arglist, const char *)) != NULL) {
    move m = parsing_move_from_uci(ucimove);
    require(parsing_is_valid_move(board, m), "illegal move %s\n", ucimove);
    makemove_makef(board, m);
  }
  va_end( arglist );
}

static void opening_register_multi(const Board* b, ...) {
  
  va_list arglist;
  va_start(arglist, b);
  const char* ucimove;
  while ((ucimove = va_arg(arglist, const char *)) != NULL) {
    opening_register(b, ucimove);
  }
  va_end( arglist );
}

#define OPENING_START()  {Board b = parsing_from_fen(STARTPOS_FEN);\

#define OPENING_MOVES(...)  {Board b = parsing_from_fen(STARTPOS_FEN);\
opening_moves_to_board(&b, __VA_ARGS__, NULL);

#define OPENING_REGISTER(expr, ...) expr; \
opening_register_multi(&b, __VA_ARGS__, NULL);\
}

#define OPENING_REGISTER_FEN(fen, ...) {Board b = parsing_from_fen(fen);\
opening_register_multi(&b, __VA_ARGS__, NULL);\
}

static move opening_pick(const Opening* opening) {
  int i = rand() % opening->count;
  return opening->m[i];
}

void opening_whitebook(void);
void opening_blackbook(void);

void opening_book_init(void) {
  if (!enabled) return;
  openings = (Opening*) calloc(BOOK_SIZE_MAX, sizeof(*openings));
  unsigned int seed = (unsigned int) time(NULL);
  srand(seed);
  opening_whitebook();
  opening_blackbook();
}


void opening_book_set_enabled(bool is_enabled) {
  bool init = !enabled && is_enabled;
  bool destroy = enabled && !is_enabled;
  enabled = is_enabled;
  if (init) opening_book_init();
  else if (destroy) opening_book_destroy();
  #ifdef DEBUGLOG
    IO_PRINT("ok OwnBook = %s\n", enabled ? "true" : "false");
  #endif
}

move opening_book_consult(const Board* board) {
  if (!enabled) return 0;
  if (board->ply > PLY_MAX) return 0;
  Opening* opening = opening_book_find(board);
  if (opening == NULL) return 0;
  
  return opening_pick(opening);
}

void opening_book_destroy(void) {
  free(openings);
}

void opening_whitebook(void) {
  OPENING_REGISTER(OPENING_START(),
                   "d2d4", "d2d4", "d2d4", "d2d4", "d2d4",
                   "e2e4", "e2e4", "e2e4",
                   "g1f3",
                   "c2c4",
                   "g2g3");
  OPENING_REGISTER(OPENING_MOVES("d2d4", "g8f6"),
                   "c2c4");
  OPENING_REGISTER(OPENING_MOVES("d2d4", "d7d5"),
                   "c2c4");
  OPENING_REGISTER(OPENING_MOVES("d2d4", "e7e6"),
                   "c2c4");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c5"),
                   "g1f3");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c5", "g1f3", "d7d6"),
                   "d2d4", "d2d4", "f1b5");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "e7e5"),
                   "g1f3");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "e7e6"),
                   "d2d4");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c6"),
                   "d2d4");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "d7d5"),
                   "e4d5", "e4d5", "e4e5");
}


void opening_blackbook(void) {
  OPENING_REGISTER(OPENING_MOVES("e2e4"),
                   "c7c5", "c7c5", "e7e5");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c5", "g1f3"),
                  "d7d6", "d7d6", "b8c6");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c5", "g1f3", "d7d6", "d2d4"),
                  "c5d4", "c5d4", "g8f6");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "c7c5", "b1c3"),
                  "d7d6", "b8c6", "b8c6");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "e7e5", "g1f3"),
                  "d7d6", "b8c6", "b8c6");
  OPENING_REGISTER(OPENING_MOVES("e2e4", "e7e5", "g1f3", "b8c6", "f1b5"),
                  "a7a6");
  
  OPENING_REGISTER(OPENING_MOVES("d2d4"),
                   "d7d5", "g8f6", "g8f6");
  OPENING_REGISTER(OPENING_MOVES("d2d4", "d7d5", "c2c4"),
                   "e7e6", "e7e6", "e7e6", "e7e5");
  OPENING_REGISTER(OPENING_MOVES("d2d4", "g8f6", "g1f3"),
                   "g7g6", "g7g6", "c7c5");
  
  OPENING_REGISTER(OPENING_MOVES("c2c4"),
                   "g8f6", "c7c5", "c7c5", "e7e6", "e7e5", "c7c6");
  OPENING_REGISTER(OPENING_MOVES("c2c4", "c7c5", "b1c3"),
                   "g7g6", "g7g6", "b8c6");
  OPENING_REGISTER(OPENING_MOVES("c2c4", "c7c5", "g1f3"),
                   "g7g6", "g7g6", "g8f6");
  
  OPENING_REGISTER(OPENING_MOVES("g2g3"),
                   "d7d5", "d7d5", "g8f6", "g7g6", "e7e5");
  
  OPENING_REGISTER(OPENING_MOVES("f2f4"),
                   "d7d5", "d7d5", "g8f6", "g7g6", "e7e5");
  OPENING_REGISTER(OPENING_MOVES("e2e3"),
                   "d7d5", "d7d5", "g8f6", "g7g6", "e7e5");
  OPENING_REGISTER(OPENING_MOVES("b1c3"),
                   "c7c5", "d7d5", "g8f6", "g7g6", "e7e5");
  OPENING_REGISTER(OPENING_MOVES("g1f3"),
                   "d7d5","d7d5", "d7d5", "g8f6", "g7g6", "c7c5", "e7e6", "c7c6");
  OPENING_REGISTER(OPENING_MOVES("b2b4"),
                   "c7c5", "d7d5", "g8f6", "g7g6", "e7e6");
}