2023-02-16 20:35:32 +01:00
|
|
|
#ifndef MYBT_H
|
|
|
|
#define MYBT_H
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <random>
|
|
|
|
#define WHITE 0
|
|
|
|
#define BLACK 1
|
|
|
|
#define EMPTY 2
|
2023-02-16 20:46:54 +01:00
|
|
|
char *cboard = (char *)"o@.";
|
2023-02-16 20:35:32 +01:00
|
|
|
|
|
|
|
struct bt_piece_t {
|
2023-02-16 20:46:54 +01:00
|
|
|
int line;
|
|
|
|
int col;
|
2023-02-16 20:35:32 +01:00
|
|
|
};
|
|
|
|
struct bt_move_t {
|
2023-02-16 20:46:54 +01:00
|
|
|
int line_i;
|
|
|
|
int col_i;
|
|
|
|
int line_f;
|
|
|
|
int col_f;
|
2023-02-16 20:35:32 +01:00
|
|
|
|
|
|
|
// all moves are printed without ambiguity
|
|
|
|
// white in its color
|
|
|
|
// black in red color
|
2023-02-16 20:46:54 +01:00
|
|
|
void print(FILE *_fp, bool _white, int _nbl) {
|
|
|
|
if (_white) {
|
|
|
|
fprintf(_fp, "%d%c%d%c", _nbl - line_i, 'a' + col_i, _nbl - line_f,
|
|
|
|
'a' + col_f);
|
2023-02-16 20:35:32 +01:00
|
|
|
} else {
|
2023-02-16 20:46:54 +01:00
|
|
|
fprintf(_fp, "\x1B[31m%d%c%d%c\x1B[0m", _nbl - line_i, 'a' + col_i,
|
|
|
|
_nbl - line_f, 'a' + col_f);
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
std::string tostr(int _nbl) {
|
|
|
|
char ret[16];
|
2023-02-16 20:46:54 +01:00
|
|
|
snprintf(ret, sizeof(ret), "%d%c%d%c", _nbl - line_i, 'a' + col_i,
|
|
|
|
_nbl - line_f, 'a' + col_f);
|
2023-02-16 20:35:32 +01:00
|
|
|
return std::string(ret);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// alloc default 10x10
|
|
|
|
// standard game in 8x8
|
|
|
|
#define MAX_LINES 10
|
|
|
|
#define MAX_COLS 10
|
|
|
|
|
|
|
|
// rules reminder :
|
|
|
|
// pieces moves from 1 square in diag and in front
|
|
|
|
// pieces captures only in diag
|
|
|
|
// i.e. to go forward, square must be empty
|
|
|
|
|
|
|
|
struct bt_t {
|
|
|
|
int nbl;
|
|
|
|
int nbc;
|
|
|
|
int board[MAX_LINES][MAX_COLS];
|
|
|
|
int turn;
|
|
|
|
|
2023-02-16 20:46:54 +01:00
|
|
|
bt_piece_t white_pieces[2 * MAX_LINES];
|
2023-02-16 20:35:32 +01:00
|
|
|
int nb_white_pieces;
|
2023-02-16 20:46:54 +01:00
|
|
|
bt_piece_t black_pieces[2 * MAX_LINES];
|
2023-02-16 20:35:32 +01:00
|
|
|
int nb_black_pieces;
|
2023-02-16 20:46:54 +01:00
|
|
|
bt_move_t moves[3 * 2 * MAX_LINES];
|
2023-02-16 20:35:32 +01:00
|
|
|
int nb_moves;
|
|
|
|
// last turn of moves update
|
|
|
|
int turn_of_last_moves_update;
|
|
|
|
|
|
|
|
void init(int _nbl, int _nbc);
|
|
|
|
void init_pieces();
|
2023-02-16 20:46:54 +01:00
|
|
|
void print_board(FILE *_fp);
|
|
|
|
void print_turn_and_moves(FILE *_fp);
|
2023-02-16 20:35:32 +01:00
|
|
|
void update_moves();
|
|
|
|
void update_moves(int _color);
|
2023-02-16 20:46:54 +01:00
|
|
|
|
2023-02-16 20:35:32 +01:00
|
|
|
bool white_can_move_right(int _line, int _col);
|
|
|
|
bool white_can_move_forward(int _line, int _col);
|
|
|
|
bool white_can_move_left(int _line, int _col);
|
|
|
|
bool black_can_move_right(int _line, int _col);
|
|
|
|
bool black_can_move_forward(int _line, int _col);
|
|
|
|
bool black_can_move_left(int _line, int _col);
|
|
|
|
|
|
|
|
bt_move_t get_rand_move();
|
|
|
|
bool can_play(bt_move_t _m);
|
|
|
|
void play(bt_move_t _m);
|
|
|
|
int endgame();
|
|
|
|
double score(int _color);
|
|
|
|
void playout(bool _log);
|
|
|
|
std::string mkH1();
|
|
|
|
std::string mkH2();
|
|
|
|
long long int mkH3();
|
2023-02-16 20:46:54 +01:00
|
|
|
|
2023-02-16 20:35:32 +01:00
|
|
|
// déclarées mais non définies
|
|
|
|
double eval();
|
|
|
|
bt_move_t minimax(double _sec);
|
|
|
|
bt_move_t alphabeta(double _sec);
|
|
|
|
bt_move_t mcts(double _sec);
|
|
|
|
bt_move_t mcts_ppa(double _sec);
|
|
|
|
bt_move_t nmcs(double _sec);
|
|
|
|
bt_move_t nrpa(double _sec);
|
|
|
|
|
|
|
|
void add_move(int _li, int _ci, int _lf, int _cf) {
|
2023-02-16 20:46:54 +01:00
|
|
|
moves[nb_moves].line_i = _li;
|
|
|
|
moves[nb_moves].col_i = _ci;
|
|
|
|
moves[nb_moves].line_f = _lf;
|
|
|
|
moves[nb_moves].col_f = _cf;
|
2023-02-16 20:35:32 +01:00
|
|
|
nb_moves++;
|
|
|
|
}
|
|
|
|
};
|
2023-02-16 20:46:54 +01:00
|
|
|
|
2023-02-16 20:35:32 +01:00
|
|
|
void bt_t::init(int _nbl, int _nbc) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_nbl > MAX_LINES || _nbc > MAX_COLS) {
|
2023-02-16 20:35:32 +01:00
|
|
|
fprintf(stderr, "ERROR : MAX_LINES or MAX_COLS exceeded\n");
|
|
|
|
exit(0);
|
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
nbl = _nbl;
|
|
|
|
nbc = _nbc;
|
2023-02-16 20:35:32 +01:00
|
|
|
turn = 0;
|
|
|
|
turn_of_last_moves_update = -1;
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int i = 0; i < nbl; i++)
|
|
|
|
for (int j = 0; j < nbc; j++) {
|
|
|
|
if (i <= 1) {
|
2023-02-16 20:35:32 +01:00
|
|
|
board[i][j] = BLACK;
|
2023-02-16 20:46:54 +01:00
|
|
|
} else if (i < _nbl - 2) {
|
2023-02-16 20:35:32 +01:00
|
|
|
board[i][j] = EMPTY;
|
|
|
|
} else {
|
|
|
|
board[i][j] = WHITE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
init_pieces();
|
|
|
|
update_moves();
|
|
|
|
}
|
|
|
|
void bt_t::init_pieces() {
|
|
|
|
nb_white_pieces = 0;
|
|
|
|
nb_black_pieces = 0;
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int i = 0; i < nbl; i++)
|
|
|
|
for (int j = 0; j < nbc; j++) {
|
|
|
|
if (board[i][j] == WHITE) {
|
2023-02-16 20:35:32 +01:00
|
|
|
white_pieces[nb_white_pieces].line = i;
|
|
|
|
white_pieces[nb_white_pieces].col = j;
|
|
|
|
nb_white_pieces++;
|
2023-02-16 20:46:54 +01:00
|
|
|
} else if (board[i][j] == BLACK) {
|
2023-02-16 20:35:32 +01:00
|
|
|
black_pieces[nb_black_pieces].line = i;
|
|
|
|
black_pieces[nb_black_pieces].col = j;
|
|
|
|
nb_black_pieces++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// again print black in red (as bg is black... black is printed in red)
|
2023-02-16 20:46:54 +01:00
|
|
|
void bt_t::print_board(FILE *_fp = stderr) {
|
2023-02-16 20:35:32 +01:00
|
|
|
fprintf(_fp, " \x1B[34m");
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int j = 0; j < nbc; j++) {
|
|
|
|
fprintf(_fp, "%c ", 'a' + j);
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
|
|
|
fprintf(_fp, "\x1B[0m\n");
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int i = 0; i < nbl; i++) {
|
|
|
|
fprintf(_fp, "\x1B[34m%2d\x1B[0m ", (nbl - i));
|
|
|
|
for (int j = 0; j < nbc; j++) {
|
|
|
|
if (board[i][j] == BLACK)
|
2023-02-16 20:35:32 +01:00
|
|
|
fprintf(_fp, "\x1B[31m%c\x1B[0m ", cboard[board[i][j]]);
|
|
|
|
else
|
|
|
|
fprintf(_fp, "%c ", cboard[board[i][j]]);
|
|
|
|
}
|
|
|
|
fprintf(_fp, "\n");
|
|
|
|
}
|
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
void bt_t::print_turn_and_moves(FILE *_fp = stderr) {
|
|
|
|
fprintf(_fp, "turn:%d\nmoves:", turn);
|
|
|
|
for (int i = 0; i < nb_moves; i++) {
|
|
|
|
moves[i].print(_fp, turn % 2 == 1, nbl);
|
2023-02-16 20:35:32 +01:00
|
|
|
fprintf(_fp, " ");
|
|
|
|
}
|
|
|
|
fprintf(_fp, "\n");
|
|
|
|
}
|
|
|
|
void bt_t::update_moves() {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (turn % 2 == 0)
|
|
|
|
update_moves(WHITE);
|
|
|
|
else
|
|
|
|
update_moves(BLACK);
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
|
|
|
void bt_t::update_moves(int _color) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (turn_of_last_moves_update == turn)
|
|
|
|
return; // MAJ ever done
|
2023-02-16 20:35:32 +01:00
|
|
|
turn_of_last_moves_update = turn;
|
|
|
|
nb_moves = 0;
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_color == WHITE) {
|
|
|
|
for (int i = 0; i < nb_white_pieces; i++) {
|
2023-02-16 20:35:32 +01:00
|
|
|
int li = white_pieces[i].line;
|
|
|
|
int ci = white_pieces[i].col;
|
2023-02-16 20:46:54 +01:00
|
|
|
if (white_can_move_right(li, ci))
|
|
|
|
add_move(li, ci, li - 1, ci + 1);
|
|
|
|
if (white_can_move_forward(li, ci))
|
|
|
|
add_move(li, ci, li - 1, ci);
|
|
|
|
if (white_can_move_left(li, ci))
|
|
|
|
add_move(li, ci, li - 1, ci - 1);
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
} else if (_color == BLACK) {
|
|
|
|
for (int i = 0; i < nb_black_pieces; i++) {
|
2023-02-16 20:35:32 +01:00
|
|
|
int li = black_pieces[i].line;
|
|
|
|
int ci = black_pieces[i].col;
|
2023-02-16 20:46:54 +01:00
|
|
|
if (black_can_move_right(li, ci))
|
|
|
|
add_move(li, ci, li + 1, ci + 1);
|
|
|
|
if (black_can_move_forward(li, ci))
|
|
|
|
add_move(li, ci, li + 1, ci);
|
|
|
|
if (black_can_move_left(li, ci))
|
|
|
|
add_move(li, ci, li + 1, ci - 1);
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool bt_t::white_can_move_right(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == 0)
|
|
|
|
return false;
|
|
|
|
if (_col == nbc - 1)
|
|
|
|
return false;
|
|
|
|
if (board[_line - 1][_col + 1] != WHITE)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool bt_t::white_can_move_forward(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == 0)
|
|
|
|
return false;
|
|
|
|
if (board[_line - 1][_col] == EMPTY)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool bt_t::white_can_move_left(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == 0)
|
|
|
|
return false;
|
|
|
|
if (_col == 0)
|
|
|
|
return false;
|
|
|
|
if (board[_line - 1][_col - 1] != WHITE)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool bt_t::black_can_move_right(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == nbl - 1)
|
|
|
|
return false;
|
|
|
|
if (_col == nbc - 1)
|
|
|
|
return false;
|
|
|
|
if (board[_line + 1][_col + 1] != BLACK)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool bt_t::black_can_move_forward(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == nbl - 1)
|
|
|
|
return false;
|
|
|
|
if (board[_line + 1][_col] == EMPTY)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool bt_t::black_can_move_left(int _line, int _col) {
|
2023-02-16 20:46:54 +01:00
|
|
|
if (_line == nbl - 1)
|
|
|
|
return false;
|
|
|
|
if (_col == 0)
|
|
|
|
return false;
|
|
|
|
if (board[_line + 1][_col - 1] != BLACK)
|
|
|
|
return true;
|
2023-02-16 20:35:32 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bt_move_t bt_t::get_rand_move() {
|
|
|
|
update_moves();
|
2023-02-16 20:46:54 +01:00
|
|
|
int r = ((int)rand()) % nb_moves;
|
2023-02-16 20:35:32 +01:00
|
|
|
return moves[r];
|
|
|
|
}
|
|
|
|
bool bt_t::can_play(bt_move_t _m) {
|
|
|
|
int dx = abs(_m.col_f - _m.col_i);
|
2023-02-16 20:46:54 +01:00
|
|
|
if (dx > 1)
|
|
|
|
return false;
|
2023-02-16 20:35:32 +01:00
|
|
|
int dy = abs(_m.line_f - _m.line_i);
|
2023-02-16 20:46:54 +01:00
|
|
|
if (dy > 1)
|
|
|
|
return false;
|
|
|
|
if (_m.line_i < 0 || _m.line_i >= nbl)
|
|
|
|
return false;
|
|
|
|
if (_m.line_f < 0 || _m.line_f >= nbl)
|
|
|
|
return false;
|
|
|
|
if (_m.col_i < 0 || _m.col_i >= nbc)
|
|
|
|
return false;
|
|
|
|
if (_m.col_f < 0 || _m.col_f >= nbc)
|
|
|
|
return false;
|
2023-02-16 20:35:32 +01:00
|
|
|
int color_i = board[_m.line_i][_m.col_i];
|
|
|
|
int color_f = board[_m.line_f][_m.col_f];
|
2023-02-16 20:46:54 +01:00
|
|
|
if (color_i == EMPTY)
|
|
|
|
return false;
|
|
|
|
if (color_i == color_f)
|
|
|
|
return false;
|
|
|
|
if (turn % 2 == 0 && color_i == BLACK)
|
|
|
|
return false;
|
|
|
|
if (turn % 2 == 1 && color_i == WHITE)
|
|
|
|
return false;
|
|
|
|
if (_m.col_i == _m.col_f && color_f != EMPTY)
|
|
|
|
return false;
|
2023-02-16 20:35:32 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_t::play(bt_move_t _m) {
|
|
|
|
int color_i = board[_m.line_i][_m.col_i];
|
|
|
|
int color_f = board[_m.line_f][_m.col_f];
|
|
|
|
board[_m.line_f][_m.col_f] = color_i;
|
|
|
|
board[_m.line_i][_m.col_i] = EMPTY;
|
2023-02-16 20:46:54 +01:00
|
|
|
if (color_i == WHITE) {
|
|
|
|
for (int i = 0; i < nb_white_pieces; i++) {
|
|
|
|
if (white_pieces[i].line == _m.line_i &&
|
|
|
|
white_pieces[i].col == _m.col_i) {
|
2023-02-16 20:35:32 +01:00
|
|
|
white_pieces[i].line = _m.line_f;
|
|
|
|
white_pieces[i].col = _m.col_f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
if (color_f == BLACK) {
|
|
|
|
for (int i = 0; i < nb_black_pieces; i++) {
|
|
|
|
if (black_pieces[i].line == _m.line_f &&
|
|
|
|
black_pieces[i].col == _m.col_f) {
|
|
|
|
black_pieces[i] = black_pieces[nb_black_pieces - 1];
|
2023-02-16 20:35:32 +01:00
|
|
|
nb_black_pieces--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
} else if (color_i == BLACK) {
|
|
|
|
for (int i = 0; i < nb_black_pieces; i++) {
|
|
|
|
if (black_pieces[i].line == _m.line_i &&
|
|
|
|
black_pieces[i].col == _m.col_i) {
|
2023-02-16 20:35:32 +01:00
|
|
|
black_pieces[i].line = _m.line_f;
|
|
|
|
black_pieces[i].col = _m.col_f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
if (color_f == WHITE) {
|
|
|
|
for (int i = 0; i < nb_white_pieces; i++) {
|
|
|
|
if (white_pieces[i].line == _m.line_f &&
|
|
|
|
white_pieces[i].col == _m.col_f) {
|
|
|
|
white_pieces[i] = white_pieces[nb_white_pieces - 1];
|
2023-02-16 20:35:32 +01:00
|
|
|
nb_white_pieces--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
turn++;
|
|
|
|
}
|
|
|
|
int bt_t::endgame() {
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int i = 0; i < nbc; i++) {
|
|
|
|
if (board[0][i] == WHITE)
|
|
|
|
return WHITE;
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
2023-02-16 20:46:54 +01:00
|
|
|
for (int i = 0; i < nbc; i++) {
|
|
|
|
if (board[nbl - 1][i] == BLACK)
|
|
|
|
return BLACK;
|
2023-02-16 20:35:32 +01:00
|
|
|
}
|
|
|
|
return EMPTY;
|
|
|
|
}
|
|
|
|
double bt_t::score(int _color) {
|
|
|
|
int state = endgame();
|
2023-02-16 20:46:54 +01:00
|
|
|
if (state == EMPTY)
|
|
|
|
return 0.0;
|
|
|
|
if (_color == state)
|
|
|
|
return 1.0;
|
2023-02-16 20:35:32 +01:00
|
|
|
return -1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* MYBT_H */
|