#ifndef MYBT_H #define MYBT_H #include #include #include #define WHITE 0 #define BLACK 1 #define EMPTY 2 char* cboard = (char*)"o@."; struct bt_piece_t { int line; int col; }; struct bt_move_t { int line_i; int col_i; int line_f; int col_f; // all moves are printed without ambiguity // white in its color // black in red color 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); } else { fprintf(_fp, "\x1B[31m%d%c%d%c\x1B[0m", _nbl-line_i, 'a'+col_i, _nbl-line_f, 'a'+col_f); } } std::string tostr(int _nbl) { char ret[16]; snprintf(ret, sizeof(ret), "%d%c%d%c", _nbl-line_i, 'a'+col_i, _nbl-line_f, 'a'+col_f); 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; bt_piece_t white_pieces[2*MAX_LINES]; int nb_white_pieces; bt_piece_t black_pieces[2*MAX_LINES]; int nb_black_pieces; bt_move_t moves[3*2*MAX_LINES]; int nb_moves; // last turn of moves update int turn_of_last_moves_update; void init(int _nbl, int _nbc); void init_pieces(); void print_board(FILE* _fp); void print_turn_and_moves(FILE* _fp); void update_moves(); void update_moves(int _color); 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(); // 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) { moves[nb_moves].line_i = _li; moves[nb_moves].col_i = _ci; moves[nb_moves].line_f = _lf; moves[nb_moves].col_f = _cf; nb_moves++; } }; void bt_t::init(int _nbl, int _nbc) { if(_nbl > MAX_LINES || _nbc > MAX_COLS) { fprintf(stderr, "ERROR : MAX_LINES or MAX_COLS exceeded\n"); exit(0); } nbl = _nbl; nbc = _nbc; turn = 0; turn_of_last_moves_update = -1; for(int i = 0; i < nbl; i++) for(int j = 0; j < nbc; j++) { if(i <= 1 ) { board[i][j] = BLACK; } else if(i < _nbl-2) { 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; for(int i = 0; i < nbl; i++) for(int j = 0; j < nbc; j++) { if(board[i][j] == WHITE) { white_pieces[nb_white_pieces].line = i; white_pieces[nb_white_pieces].col = j; nb_white_pieces++; } else if(board[i][j] == BLACK) { 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) void bt_t::print_board(FILE* _fp = stderr) { fprintf(_fp, " \x1B[34m"); for(int j = 0; j < nbc; j++) { fprintf(_fp, "%c ", 'a'+j); } fprintf(_fp, "\x1B[0m\n"); 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) fprintf(_fp, "\x1B[31m%c\x1B[0m ", cboard[board[i][j]]); else fprintf(_fp, "%c ", cboard[board[i][j]]); } fprintf(_fp, "\n"); } } 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); fprintf(_fp, " "); } fprintf(_fp, "\n"); } void bt_t::update_moves() { if(turn%2 == 0) update_moves(WHITE); else update_moves(BLACK); } void bt_t::update_moves(int _color) { if(turn_of_last_moves_update == turn) return; // MAJ ever done turn_of_last_moves_update = turn; nb_moves = 0; if(_color==WHITE) { for(int i = 0; i < nb_white_pieces; i++) { int li = white_pieces[i].line; int ci = white_pieces[i].col; 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); } } else if(_color == BLACK) { for(int i = 0; i < nb_black_pieces; i++) { int li = black_pieces[i].line; int ci = black_pieces[i].col; 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); } } } bool bt_t::white_can_move_right(int _line, int _col) { if(_line == 0) return false; if(_col == nbc-1) return false; if(board[_line-1][_col+1] != WHITE) return true; return false; } bool bt_t::white_can_move_forward(int _line, int _col) { if(_line == 0) return false; if(board[_line-1][_col] == EMPTY) return true; return false; } bool bt_t::white_can_move_left(int _line, int _col) { if(_line == 0) return false; if(_col == 0) return false; if(board[_line-1][_col-1] != WHITE) return true; return false; } bool bt_t::black_can_move_right(int _line, int _col) { if(_line == nbl-1) return false; if(_col == nbc-1) return false; if(board[_line+1][_col+1] != BLACK) return true; return false; } bool bt_t::black_can_move_forward(int _line, int _col) { if(_line == nbl-1) return false; if(board[_line+1][_col] == EMPTY) return true; return false; } bool bt_t::black_can_move_left(int _line, int _col) { if(_line == nbl-1) return false; if(_col == 0) return false; if(board[_line+1][_col-1] != BLACK) return true; return false; } bt_move_t bt_t::get_rand_move() { update_moves(); int r = ((int)rand())%nb_moves; return moves[r]; } bool bt_t::can_play(bt_move_t _m) { int dx = abs(_m.col_f - _m.col_i); if(dx > 1) return false; int dy = abs(_m.line_f - _m.line_i); 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; int color_i = board[_m.line_i][_m.col_i]; int color_f = board[_m.line_f][_m.col_f]; 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; 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; 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) { white_pieces[i].line = _m.line_f; white_pieces[i].col = _m.col_f; break; } } 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]; nb_black_pieces--; break; } } } } 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) { black_pieces[i].line = _m.line_f; black_pieces[i].col = _m.col_f; break; } } 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]; nb_white_pieces--; break; } } } } turn++; } int bt_t::endgame() { for(int i = 0; i < nbc; i++) { if(board[0][i] == WHITE) return WHITE; } for(int i = 0; i < nbc; i++) { if(board[nbl-1][i] == BLACK) return BLACK; } return EMPTY; } double bt_t::score(int _color) { int state = endgame(); if(state == EMPTY) return 0.0; if(_color == state) return 1.0; return -1.0; } #endif /* MYBT_H */