This commit is contained in:
Mylloon 2023-02-16 20:35:32 +01:00
parent 887b7098bc
commit 89dce59af6
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
13 changed files with 1289 additions and 0 deletions

3
.gitignore vendored
View file

@ -10,6 +10,9 @@
# Ignore les executables
r0
rand_player
player_A
player_B
# Ajoute les gitignores
!**/.gitignore

6
TP2/Makefile Normal file
View file

@ -0,0 +1,6 @@
CC=g++
CFLAGS=-std=c++11 -Wall -O2
##### BREAKTHROUGH
rand_player: mybt.h rand_player.cpp
$(CC) $(CFLAGS) rand_player.cpp -o $@

48
TP2/README.txt Normal file
View file

@ -0,0 +1,48 @@
/////////////////////////////////
/// TP recherche arborescente ///
/////////////////////////////////
objectif : ecrire le meilleur programme qui joue à breakthrough
(quel algorithme utilisé, comment implémenter une version rapide, comment améliorer le programme)
(tous les précalculs sont autorisés mais un seul cpu est autorisé pendant le tournoi)
(l'allocation mémoire est limitée à 1Go par programme)
Nous jouerons probablement à breakthrough 6x4 mais cela peut évoluer...
Nous jouerons tous ensemble en mode tournoi à double élimination.
Quand nous auront 2 ou 3 groupes restant, nous les ferons jouer tous contre tous et le moins bon sera éliminé à chaque round.
En cas d'égalité, nous regarderons les scores, puis les temps de calcul utilisé.
Chaque groupe de TP pourra inscrire un programme au tournoi.
Le seeding round sera un premier tour sans élimination.
(exemple pour 12 équipes)
SEEDING ROUND ROUND-1 ROUND-2 ROUND-3
============= ===================== ========== ==========
G1 vs G2 Victoire1 vs Victoire2 ... ...
G3 vs G4 Victoire3 vs Victoire4 ... ... (dès qu'une équipe à 2 défaite, elle est éliminée)
G5 vs G6 Victoire5 vs Victoire6 ...
G7 vs G8 Defaite1 vs Defaite2 (3 élmininations)
G9 vs G10 Defaite3 vs Defaite4
G11 vs G12 Defaite5 vs Defaite6
A breakthrough, toutes les pièces sont des pions
Fichiers fournis pour ce TP :
* mybt.h définit les structures bt_piece_t, bt_move_t et bt_t
* bt_piece_t qui modélise une piece
* bt_move_t qui modélise un coup
* bt_t qui modélise le plateau et ses contraintes
* rand_player.cpp est un joueur aléaoire qui supporte le breakthrough text protocol btp
* le protocol btp permet de controler un programme pour jouer a breakthrough
* game1.txt est un exemple de fichier de commandes btp
* run_many_games.pike est un programme pike permettant de faire jouer ensemble des programmes supportant le btp
* Makefile permet de compiler le rand_player
* mk_stats.sh permet de lancer plusieurs parties, stocker les logs et les stats
Pour le moment, on posera pour contrainte de répondre le coup à jouer en 1 sec
Au delà de 1 sec, l'absence de réponse sera considérée comme un abandon
Au dela de la competition, chaque groupe doit rendre :
+ les sources de son programme
+ un rapport en 1 page (ou +) présentant les particularités/optimisations de son programme

50
TP2/data/scores.txt Normal file
View file

@ -0,0 +1,50 @@
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player 12 24.00) (./rand_player -12 24.00) => ./rand_player win
(./rand_player -10 24.00) (./rand_player 10 24.00) => ./rand_player win
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player -10 24.00) (./rand_player 10 24.00) => ./rand_player win
(./rand_player 8 24.00) (./rand_player -8 24.00) => ./rand_player win
(./rand_player -8 24.00) (./rand_player 8 24.00) => ./rand_player win
(./rand_player 12 24.00) (./rand_player -12 24.00) => ./rand_player win
(./rand_player 12 24.00) (./rand_player -12 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player -13 24.00) (./rand_player 13 24.00) => ./rand_player win
(./rand_player 14 24.00) (./rand_player -14 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player -10 24.00) (./rand_player 10 24.00) => ./rand_player win
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player 10 24.00) (./rand_player -10 24.00) => ./rand_player win
(./rand_player 15 24.00) (./rand_player -15 24.00) => ./rand_player win
(./rand_player 12 24.00) (./rand_player -12 24.00) => ./rand_player win
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player -13 24.00) (./rand_player 13 24.00) => ./rand_player win
(./rand_player 15 24.00) (./rand_player -15 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player -12 24.00) (./rand_player 12 24.00) => ./rand_player win
(./rand_player 9 24.00) (./rand_player -9 24.00) => ./rand_player win
(./rand_player 9 24.00) (./rand_player -9 24.00) => ./rand_player win
(./rand_player -14 24.00) (./rand_player 14 24.00) => ./rand_player win
(./rand_player 10 24.00) (./rand_player -10 24.00) => ./rand_player win
(./rand_player 12 24.00) (./rand_player -12 24.00) => ./rand_player win
(./rand_player 10 24.00) (./rand_player -10 24.00) => ./rand_player win
(./rand_player -13 24.00) (./rand_player 13 24.00) => ./rand_player win
(./rand_player 11 24.00) (./rand_player -11 24.00) => ./rand_player win
(./rand_player 9 24.00) (./rand_player -9 24.00) => ./rand_player win
(./rand_player -12 24.00) (./rand_player 12 24.00) => ./rand_player win
(./rand_player 10 24.00) (./rand_player -10 24.00) => ./rand_player win
(./rand_player -13 24.00) (./rand_player 13 24.00) => ./rand_player win
(./rand_player -12 24.00) (./rand_player 12 24.00) => ./rand_player win
(./rand_player -13 24.00) (./rand_player 13 24.00) => ./rand_player win
(./rand_player 9 24.00) (./rand_player -9 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player 11 24.00) (./rand_player -11 24.00) => ./rand_player win
(./rand_player -10 24.00) (./rand_player 10 24.00) => ./rand_player win
(./rand_player -12 24.00) (./rand_player 12 24.00) => ./rand_player win
(./rand_player -8 24.00) (./rand_player 8 24.00) => ./rand_player win
(./rand_player -11 24.00) (./rand_player 11 24.00) => ./rand_player win
(./rand_player 10 24.00) (./rand_player -10 24.00) => ./rand_player win
(./rand_player 13 24.00) (./rand_player -13 24.00) => ./rand_player win
(./rand_player 15 24.00) (./rand_player -15 24.00) => ./rand_player win

26
TP2/game1.txt Normal file
View file

@ -0,0 +1,26 @@
// simple game on 6x4 board
// a3a-5a4a 2b3b-4a3b 2c3b-6a5a 3a4a-5b4a 3b4a-6b5b 4a5b-6c5b 1a2a-5a4a 2a3a-5b4b 3a4b-5c4b 1b2b-????
echo OFF
newgame 6 4
play 2a3a
play 5a4a
play 2b3b
play 4a3b
play 2c3b
play 6a5a
play 3a4a
showboard
play 5b4a
play 3b4a
play 6b5b
play 4a5b
play 6c5b
play 1a2a
play 5a4a
play 2a3a
play 5b4b
play 3a4b
play 5c4b
play 1b2b
showboard
quit

47
TP2/mk_stats.sh Normal file
View file

@ -0,0 +1,47 @@
#!/bin/sh
PRG_1=./player_A
PRG_2=./player_B
GAME_DIR=new_stats
NB_GAMES_PER_SIDE=10
NBL=6
NBC=4
if [ -d ${GAME_DIR} ]
then
echo "GAME_DIR ever here"
exit 0
else
mkdir ${GAME_DIR}
fi
if [ ! -e ${PRG_1} ]
then
echo "PRG_1 is missing"
exit 0
fi
if [ ! -e ${PRG_2} ]
then
echo "PRG_2 is missing"
exit 0
fi
pike run_many_games.pike -f ${PRG_1} -s ${PRG_2} -o ${GAME_DIR} -n ${NB_GAMES_PER_SIDE} -l ${NBL} -c ${NBC} 2>${GAME_DIR}/log1.txt 1>&2
pike run_many_games.pike -f ${PRG_2} -s ${PRG_1} -o ${GAME_DIR} -n ${NB_GAMES_PER_SIDE} -l ${NBL} -c ${NBC} 2>${GAME_DIR}/log2.txt 1>&2
echo " ================" > ${GAME_DIR}/resume.txt
echo " NB_GAMES_PER_SIDE ${NB_GAMES_PER_SIDE}" >> ${GAME_DIR}/resume.txt
echo " NBL ${NBL}" >> ${GAME_DIR}/resume.txt
echo " NBC ${NBC}" >> ${GAME_DIR}/resume.txt
echo "" >> ${GAME_DIR}/resume.txt
echo " number of wins" >> ${GAME_DIR}/resume.txt
echo " ================" >> ${GAME_DIR}/resume.txt
STR_WIN1=$(echo ${PRG_1} win)
NB_WIN1=$(grep "${STR_WIN1}" ${GAME_DIR}/scores.txt | wc -l)
echo " "${PRG_1}" is "${NB_WIN1} >> ${GAME_DIR}/resume.txt
STR_WIN2=$(echo ${PRG_2} win)
NB_WIN2=$(grep "${STR_WIN2}" ${GAME_DIR}/scores.txt | wc -l)
echo " "${PRG_2}" is "${NB_WIN2} >> ${GAME_DIR}/resume.txt
echo " ================" >> ${GAME_DIR}/resume.txt

307
TP2/mybt.h Normal file
View file

@ -0,0 +1,307 @@
#ifndef MYBT_H
#define MYBT_H
#include <cstdio>
#include <cstdlib>
#include <random>
#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 */

100
TP2/new_stats/log1.txt Normal file
View file

@ -0,0 +1,100 @@
nb_turn: 26 timers : 24.00 : 24.00
6 . . . .
5 @ @ o @
4 @ o . .
3 o @ . o
2 . . . .
1 o @ . .
a b c d
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
================= player2 WIN
nb_turn: 26 timers : 24.00 : 24.00
6 @ . . .
5 . . . @
4 @ o o @
3 . o @ o
2 . . . .
1 @ . . o
a b c d
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
================= player2 WIN
nb_turn: 25 timers : 24.00 : 24.00
6 . . . o
5 o @ . .
4 . @ @ @
3 . . o @
2 . o @ o
1 . . . o
a b c d
(./player_A 12 24.00) (./player_B -12 24.00) => ./player_A win
================= player1 WIN
nb_turn: 28 timers : 24.00 : 24.00
6 . . . .
5 . @ . .
4 @ o . @
3 o o . @
2 . . o .
1 . @ o .
a b c d
(./player_A -10 24.00) (./player_B 10 24.00) => ./player_B win
================= player2 WIN
nb_turn: 22 timers : 24.00 : 24.00
6 @ @ . .
5 . . . @
4 o @ o o
3 . o . .
2 . . . o
1 . . @ o
a b c d
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
================= player2 WIN
nb_turn: 19 timers : 24.00 : 24.00
6 . o @ .
5 . . @ @
4 @ . @ .
3 . o @ o
2 o . . o
1 . . o o
a b c d
(./player_A 13 24.00) (./player_B -13 24.00) => ./player_A win
================= player1 WIN
nb_turn: 30 timers : 24.00 : 24.00
6 . . @ .
5 @ . . o
4 . . @ .
3 @ o . o
2 @ . . .
1 o . @ .
a b c d
(./player_A -10 24.00) (./player_B 10 24.00) => ./player_B win
================= player2 WIN
nb_turn: 29 timers : 24.00 : 24.00
6 . . o .
5 . @ . .
4 . . o .
3 . @ o o
2 . . @ .
1 o . . .
a b c d
(./player_A 8 24.00) (./player_B -8 24.00) => ./player_A win
================= player1 WIN
nb_turn: 30 timers : 24.00 : 24.00
6 @ . . .
5 . . . .
4 @ . o @
3 o . @ o
2 . . . .
1 . @ . .
a b c d
(./player_A -8 24.00) (./player_B 8 24.00) => ./player_B win
================= player2 WIN
nb_turn: 19 timers : 24.00 : 24.00
6 . @ @ o
5 . . . @
4 o . @ .
3 o . . @
2 . . . o
1 o . o o
a b c d
(./player_A 12 24.00) (./player_B -12 24.00) => ./player_A win
================= player1 WIN

100
TP2/new_stats/log2.txt Normal file
View file

@ -0,0 +1,100 @@
nb_turn: 26 timers : 24.00 : 24.00
6 . . . .
5 @ @ o @
4 @ o . .
3 o @ . o
2 . . . .
1 o @ . .
a b c d
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
================= player2 WIN
nb_turn: 26 timers : 24.00 : 24.00
6 @ . . .
5 . . . @
4 @ o o @
3 . o @ o
2 . . . .
1 @ . . o
a b c d
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
================= player2 WIN
nb_turn: 25 timers : 24.00 : 24.00
6 . . . o
5 o @ . .
4 . @ @ @
3 . . o @
2 . o @ o
1 . . . o
a b c d
(./player_B 12 24.00) (./player_A -12 24.00) => ./player_B win
================= player1 WIN
nb_turn: 28 timers : 24.00 : 24.00
6 . . . .
5 . @ . .
4 @ o . @
3 o o . @
2 . . o .
1 . @ o .
a b c d
(./player_B -10 24.00) (./player_A 10 24.00) => ./player_A win
================= player2 WIN
nb_turn: 22 timers : 24.00 : 24.00
6 @ @ . .
5 . . . @
4 o @ o o
3 . o . .
2 . . . o
1 . . @ o
a b c d
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
================= player2 WIN
nb_turn: 19 timers : 24.00 : 24.00
6 . o @ .
5 . . @ @
4 @ . @ .
3 . o @ o
2 o . . o
1 . . o o
a b c d
(./player_B 13 24.00) (./player_A -13 24.00) => ./player_B win
================= player1 WIN
nb_turn: 30 timers : 24.00 : 24.00
6 . . @ .
5 @ . . o
4 . . @ .
3 @ o . o
2 @ . . .
1 o . @ .
a b c d
(./player_B -10 24.00) (./player_A 10 24.00) => ./player_A win
================= player2 WIN
nb_turn: 29 timers : 24.00 : 24.00
6 . . o .
5 . @ . .
4 . . o .
3 . @ o o
2 . . @ .
1 o . . .
a b c d
(./player_B 8 24.00) (./player_A -8 24.00) => ./player_B win
================= player1 WIN
nb_turn: 30 timers : 24.00 : 24.00
6 @ . . .
5 . . . .
4 @ . o @
3 o . @ o
2 . . . .
1 . @ . .
a b c d
(./player_B -8 24.00) (./player_A 8 24.00) => ./player_A win
================= player2 WIN
nb_turn: 19 timers : 24.00 : 24.00
6 . @ @ o
5 . . . @
4 o . @ .
3 o . . @
2 . . . o
1 o . o o
a b c d
(./player_B 12 24.00) (./player_A -12 24.00) => ./player_B win
================= player1 WIN

10
TP2/new_stats/resume.txt Normal file
View file

@ -0,0 +1,10 @@
================
NB_GAMES_PER_SIDE 10
NBL 6
NBC 4
number of wins
================
./player_A is 10
./player_B is 10
================

20
TP2/new_stats/scores.txt Normal file
View file

@ -0,0 +1,20 @@
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
(./player_A 12 24.00) (./player_B -12 24.00) => ./player_A win
(./player_A -10 24.00) (./player_B 10 24.00) => ./player_B win
(./player_A -11 24.00) (./player_B 11 24.00) => ./player_B win
(./player_A 13 24.00) (./player_B -13 24.00) => ./player_A win
(./player_A -10 24.00) (./player_B 10 24.00) => ./player_B win
(./player_A 8 24.00) (./player_B -8 24.00) => ./player_A win
(./player_A -8 24.00) (./player_B 8 24.00) => ./player_B win
(./player_A 12 24.00) (./player_B -12 24.00) => ./player_A win
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
(./player_B 12 24.00) (./player_A -12 24.00) => ./player_B win
(./player_B -10 24.00) (./player_A 10 24.00) => ./player_A win
(./player_B -11 24.00) (./player_A 11 24.00) => ./player_A win
(./player_B 13 24.00) (./player_A -13 24.00) => ./player_B win
(./player_B -10 24.00) (./player_A 10 24.00) => ./player_A win
(./player_B 8 24.00) (./player_A -8 24.00) => ./player_B win
(./player_B -8 24.00) (./player_A 8 24.00) => ./player_A win
(./player_B 12 24.00) (./player_A -12 24.00) => ./player_B win

109
TP2/rand_player.cpp Normal file
View file

@ -0,0 +1,109 @@
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <iostream>
#include <string>
#include "mybt.h"
bt_t B;
int boardwidth = 0;
int boardheight = 0;
bool white_turn = true;
#ifndef VERBOSE_RAND_PLAYER
#define VERBOSE_RAND_PLAYER
bool verbose = true;
bool showboard_at_each_move = false;
#endif
void help() {
fprintf(stderr, " quit\n");
fprintf(stderr, " echo ON | OFF\n");
fprintf(stderr, " help\n");
fprintf(stderr, " name <PLAYER_NAME>\n");
fprintf(stderr, " newgame <NBCOL> <NBLINE>\n");
fprintf(stderr, " genmove\n");
fprintf(stderr, " play <L0C0L1C1>\n");
fprintf(stderr, " showboard\n");
}
void name() {
printf("= rand_player\n\n");
}
void newgame() {
if((boardheight < 1 || boardheight > 10) && (boardwidth < 1 || boardwidth > 10)) {
fprintf(stderr, "boardsize is %d %d ???\n", boardheight, boardwidth);
printf("= \n\n");
return;
}
B.init(boardheight, boardwidth);
white_turn = true;
if(verbose) fprintf(stderr, "ready to play on %dx%d board\n", boardheight, boardwidth);
printf("= \n\n");
}
void showboard() {
B.print_board(stderr);
printf("= \n\n");
}
void genmove() {
int ret = B.endgame();
if(ret != EMPTY) {
fprintf(stderr, "game finished\n");
if(ret == WHITE) fprintf(stderr, "white player wins\n");
else fprintf(stderr, "black player wins\n");
printf("= \n\n");
return;
}
bt_move_t m = B.get_rand_move();
B.play(m);
if(verbose) {
m.print(stderr, white_turn, B.nbl);
fprintf(stderr, "\n");
}
white_turn = !white_turn;
printf("= %s\n\n", m.tostr(B.nbl).c_str());
}
void play(char a, char b, char c, char d) {
bt_move_t m;
m.line_i = boardheight-(a-'0');
m.col_i = b-'a';
m.line_f = boardheight-(c-'0');
m.col_f = d-'a';
if(B.can_play(m)) {
B.play(m);
if(verbose) {
m.print(stderr, white_turn, B.nbl);
fprintf(stderr, "\n");
}
white_turn = !white_turn;
} else {
fprintf(stderr, "CANT play %d %d %d %d ?\n", m.line_i, m.col_i, m.line_f, m.col_f);
}
if(showboard_at_each_move) showboard();
printf("= \n\n");
}
int main(int _ac, char** _av) {
bool echo_on = false;
setbuf(stdout, 0);
setbuf(stderr, 0);
if(verbose) fprintf(stderr, "rand_player started\n");
char a,b,c,d; // for play cmd
for (std::string line; std::getline(std::cin, line);) {
if(verbose) fprintf(stderr, "rand_player receive %s\n", line.c_str());
if(echo_on) if(verbose) fprintf(stderr, "%s\n", line.c_str());
if(line.compare("quit") == 0) { printf("= \n\n"); break; }
else if(line.compare("echo ON") == 0) echo_on = true;
else if(line.compare("echo OFF") == 0) echo_on = false;
else if(line.compare("help") == 0) help();
else if(line.compare("name") == 0) name();
else if(sscanf(line.c_str(), "newgame %d %d\n", &boardheight, &boardwidth) == 2) newgame();
else if(line.compare("genmove") == 0) genmove();
else if(sscanf(line.c_str(), "play %c%c%c%c\n", &a,&b,&c,&d) == 4) play(a,b,c,d);
else if(line.compare("showboard") == 0) showboard();
else if(line.compare(0,2,"//") == 0) ; // just comments
else fprintf(stderr, "???\n");
if(echo_on) printf(">");
}
if(verbose) fprintf(stderr, "bye.\n");
return 0;
}

463
TP2/run_many_games.pike Normal file
View file

@ -0,0 +1,463 @@
#!/usr/bin/env pike
// pike run_many_games.pike -f ./rand_player -s ./rand_player -v 1 -p 1 -l 6 -c 4
// "Options:\n"
// " -n, --number=NB_GAMES the number of games to play\n"
// " -l, --nbl=NB_LINES the number of lines on the board\n"
// " -c, --nbc=NB_COLS the number of cols on the board\n"
// " -f, --first=COMMAND_LINE\n"
// " -s, --second=COMMAND_LINE command lines to run the two engines with.\n\n"
// " -o, --outputdir=OUTPUT_DIRECTORY (default ouput is data)\n"
// " --help display this help and exit.\n"
// " -v, --verbose=LEVEL 1 - print moves, 2 and higher - draw boards.\n"
// " -p, --pause=SECONDS 1 - sleep(1), 2 and more - sleep(2 and more).\n";
#define DUMP_GTP_PIPES 0
class btp_server { // breakthrough text protocol server
int server_is_up;
private Stdio.File file_out; // reading without buffer (stream mode)
private Stdio.FILE file_in; // reading with buffer (line per line mode)
string command_line;
string|int engine_name; // just for fun
void create(string _command_line) {
file_out = Stdio.File();
file_in = Stdio.FILE();
command_line = _command_line;
array error = catch {
Process.create_process(command_line / " ",
([ "stdin" : file_out->pipe(),
"stdout" : file_in->pipe() ])); };
if (error) {
werror(error[0]); werror("Command line was `%s'.\n", command_line);
destruct(this_object());
} else {
array error = catch {
engine_name = get_name();
server_is_up = 1;
};
if (error) {
werror("Engine `%s' crashed at startup.\nPerhaps command line is wrong.\n", command_line);
destruct(this_object());
}
}
}
array send_command(string command) {
#if DUMP_GTP_PIPES
werror("[%s%s] %s\n", full_engine_name ? full_engine_name + ", " : "", command);
#endif
command = String.trim_all_whites(command);
sscanf(command, "%[0-9]", string id);
if (command[0] == '#' || command == id) return ({ 0, "" });
file_out->write("%s\n", command);
string response = file_in->gets();
if (!response) {
server_is_up = 0;
error("Engine `%s' playing crashed!", command_line);
}
#if DUMP_GTP_PIPES
werror("%s\n", response);
#endif
array result;
int id_length = strlen(id);
if (response && response[..id_length] == "=" + id)
result = ({ 0, response[id_length + 1 ..] });
else if (response && response[..id_length] == "?" + id)
result = ({ 1, response[id_length + 1 ..] });
else
result = ({ -1, response });
result[1] = String.trim_all_whites(result[1]);
while (1) {
response = file_in->gets();
#if DUMP_GTP_PIPES
werror("%s\n", response);
#endif
if (response == "") {
if (result[0] < 0) {
werror("Warning, unrecognized response to command `%s':\n", command);
werror("%s\n", result[1]);
}
return result;
}
result[1] += "\n" + response;
}
}
string get_name() {
return send_command("name")[1];
}
string generate_move() {
return send_command("genmove")[1];
}
void new_game(int _nbl, int _nbc) {
send_command("newgame "+_nbl+" "+_nbc);
}
void move(string _movestr) {
send_command("play " +_movestr);
}
void quit() {
send_command("quit");
}
};
#define ENDGAME_WHITE_WIN 0
#define ENDGAME_BLACK_WIN 0
#define ENDGAME_WHITE_WIN 0
class btp_game {
private btp_server p0;
private btp_server p1;
private int verbose;
private int in_game_pause;
public int nb_games;
public string p0_name;
public int p0_score;
public int p0_new_win;
public int p0_wins;
public string p1_name;
public int p1_score;
public int p1_new_win;
public int p1_wins;
public int nb_turn;
public int board_nbl = 0;
public int board_nbc = 0;
bool board_alloc = false;
public string board; // board length = board_nbl*board_nbc
float p0_remaining_time;
float p1_remaining_time;
public string output_dir = "data"; // default dir
void create(string command_line_player0, string command_line_player1,
int game_nbl, int game_nbc,
string new_output_dir, int _in_game_pause, int _verbose) {
in_game_pause = _in_game_pause;
verbose = _verbose;
p0 = btp_server(command_line_player0);
if (p0) p1 = btp_server(command_line_player1);
if (!p0 || !p1) {
werror("!p0 || !p1"); finalize(); exit(0);
}
board_nbl = game_nbl;
board_nbc = game_nbc;
nb_games = 0;
p0_name = command_line_player0; p0_new_win = 0; p0_wins = 0;
p1_name = command_line_player1; p1_new_win = 0; p1_wins = 0;
if(new_output_dir != "") {
output_dir = new_output_dir;
}
}
void show_endgame() {
print_board();
werror("(%s %d %.2f) (%s %d %.2f) ",
p0_name, p0_score, p0_remaining_time,
p1_name, p1_score, p1_remaining_time);
if(p0_new_win == 1) {
werror("=> "+p0_name+" win\n");
} else if(p1_new_win == 1) {
werror("=> "+p1_name+" win\n");
} else {
werror("=> draw game\n");
}
}
void print_score(string file_name) {
Stdio.File o = Stdio.File();
if(!o->open(file_name,"wac")) {
write("Failed to open file.\n");
return;
}
o->write(" (%s %d %.2f) (%s %d %.2f) ",
p0_name, p0_score, p0_remaining_time,
p1_name, p1_score, p1_remaining_time);
if(p0_new_win == 1) {
o->write("=> "+p0_name+" win\n");
} else if(p1_new_win == 1) {
o->write("=> "+p1_name+" win\n");
} else {
o->write("=> draw game\n");
}
o->close();
}
// @ is black player and o is white player
void init_board() {
nb_turn = 0;
p0_remaining_time = 24.0;
p1_remaining_time = 24.0;
if(board_alloc == false) {
for(int i = 0; i < board_nbl*board_nbc; i++)
board = board+".";
board_alloc = true;
} else {
for(int i = 0; i < board_nbl*board_nbc; i++)
board[i] = '.';
}
for(int i = 0; i < 2*board_nbc; i++)
board[i] = '@';
for(int i = (board_nbl-2)*board_nbc; i < board_nbl*board_nbc; i++)
board[i] = 'o';
}
void print_board() {
bool color_print = true;
if(color_print) {
werror("nb_turn: %d timers : \x1b[31m%.2f\x1b[0m : %.2f\n",
nb_turn, p0_remaining_time, p1_remaining_time);
} else {
werror("nb_turn: %d timers : %.2f : %.2f\n",
nb_turn, p0_remaining_time, p1_remaining_time);
}
for(int i = 0; i < board_nbl; i++) {
werror(""+(board_nbl-i)+" ");
for(int j = 0; j < board_nbc; j++) {
if(color_print) {
if(board[i*board_nbc+j] == '@') {
werror("\x1b[31m%c\x1b[0m ", board[i*board_nbc+j]);
} else {
werror("%c ",board[i*board_nbc+j]);
}
} else {
werror("%c ",board[i*board_nbc+j]);
}
}
werror("\n");
}
werror(" ");
for(int j = 0; j < board_nbc; j++)
werror("%c ", 'a'+j);
werror("\n");
}
bool play_move(string move) {
if(verbose >= 1) werror("==== play_move "+move+"\n");
if(move == "PASS") { nb_turn ++; return true; }
int strpos = 0;
int line_i = board_nbl-(move[0]-'0');
int col_i = move[1]-'a';
int line_f = board_nbl-(move[2]-'0');
int col_f = move[3]-'a';
if(verbose >= 2) werror("==== play at "+line_i+" "+col_i+" "+line_f+" "+col_f+"\n");
if(line_i < 0 || line_f < 0) return false;
if(line_i >= board_nbl || line_f >= board_nbl) return false;
if(col_i < 0 || col_f < 0) return false;
if(col_i >= board_nbc || col_f >= board_nbc) return false;
if(abs(line_f-line_i) > 1) return false;
if(abs(col_f-col_i) > 1) return false;
if(nb_turn%2==0) {
board[line_i*board_nbc+col_i] = '.';
board[line_f*board_nbc+col_f] = 'o';
} else {
board[line_i*board_nbc+col_i] = '.';
board[line_f*board_nbc+col_f] = '@';
}
nb_turn ++;
return true;
}
bool endgame() {
for(int i = 0; i < board_nbc; i++)
if(board[i] == 'o') return true;
for(int i = (board_nbl-1)*board_nbc; i < board_nbl*board_nbc; i++)
if(board[i] == '@') return true;
return false;
}
int count_pawn_on_board() {
int ret = 0;
for(int i = 0; i < board_nbl*board_nbc; i++) {
if(board[i] != '.') ret += 1;
}
return ret;
}
void play() {
if (verbose >= 2) werror("\nBeginning a new game.\n");
p0_new_win = 0;
p1_new_win = 0;
p0_score = 0;
p1_score = 0;
p0->new_game(board_nbl, board_nbc);
p1->new_game(board_nbl, board_nbc);
init_board();
// perform a match
string p0_move = "";
string p1_move = "";
while(true) {
if(verbose >= 1) print_board();
array(int) Ti = System.gettimeofday();
p0_move = p0->generate_move();
if(verbose >= 2) werror("P0_move received : "+p0_move+"\n");
array(int) Tf = System.gettimeofday();
float ms = (float)((Tf[0] - Ti[0]))+(float)(Tf[1] - Ti[1])/1000000;
p0_remaining_time -= ms;
if(p0_remaining_time < 0.0) {
p0_new_win = 0; p1_new_win = 1;
werror(" ===> "+p0_name+" time exceeded\n");
print_board();
werror(" ===> "+p1_name+" WIN\n");
break;
}
if(play_move(p0_move) == false) {
p0_new_win = 0; p1_new_win = 1;
werror(" ===> "+p0_name+" try to play "+p0_move+"\n");
print_board();
werror(" ===> "+p1_name+" WIN\n");
break;
} else {
if(verbose >= 2) {
werror("==== ok\n");
}
}
p1->move(p0_move);
if(endgame()) {
if(verbose >= 2) {
werror("=== endgame DETECTED\n");
print_board();
}
p0_new_win = 1;
p0_score = count_pawn_on_board();
p1_new_win = 0;
p1_score = -count_pawn_on_board();
break;
}
if(p0_move == "PASS" && p1_move == "PASS") {
if(verbose >= 2) werror("=== all players PASS DETECTED\n");
break;
}
if(verbose >= 2) print_board();
Ti = System.gettimeofday();
p1_move = p1->generate_move();
if(verbose >= 2) werror("P1_move received : "+p1_move+"\n");
Tf = System.gettimeofday();
ms = (float)((Tf[0] - Ti[0]))+(float)(Tf[1] - Ti[1])/1000000;
p1_remaining_time -= ms;
if(p1_remaining_time < 0.0) {
p1_new_win = 0; p0_new_win = 1;
werror(" ===> "+p1_name+" time exceeded\n");
print_board();
werror(" ===> "+p0_name+" WIN\n");
break;
}
if(play_move(p1_move) == false) {
p1_new_win = 0; p0_new_win = 1;
werror(" ===> "+p1_name+" try to play "+p1_move+"\n");
print_board();
werror(" ===> "+p0_name+" WIN\n");
break;
} else {
if(verbose >= 2) {
werror("==== ok\n");
}
}
p0->move(p1_move);
if(in_game_pause > 0)
sleep(in_game_pause);
if(endgame()) {
if(verbose >= 2) {
werror("=== endgame DETECTED\n");
print_board();
}
p1_new_win = 1;
p1_score = count_pawn_on_board();
p0_new_win = 0;
p0_score = -count_pawn_on_board();
break;
}
if(p0_move == "PASS" && p1_move == "PASS") {
if(verbose >= 2) werror("=== all players PASS DETECTED\n");
break;
}
}
}
void finalize() {
p0->quit(); p1->quit();
}
}
void run_many_games(btp_game game, int _nb_games_to_play, int verbose) {
game->nb_games = 0;
for (int k = 0; k < _nb_games_to_play; k++) {
game->play();
if(game->p0_new_win == 1) {
game->show_endgame();
werror("================= player1 WIN\n");
game->p0_wins ++;
}
if(game->p1_new_win == 1) {
game->show_endgame();
werror("================= player2 WIN\n");
game->p1_wins ++;
}
if(game->p0_new_win == 0 && game->p1_new_win == 0) {
werror("================= noone WIN\n");
}
game->nb_games ++;
game->print_score(game->output_dir+"/scores.txt");
}
game->finalize();
}
string help_message =
"Usage: %s [OPTION]... [FILE]...\n\n"
"Runs one or many matches between two programs text protocol engines.\n"
"`--white' and `--black' options are mandatory.\n\n"
"Options:\n"
" -n, --number=NB_GAMES the number of games to play\n"
" -l, --nbl=NB_LINES the number of lines on the board\n"
" -c, --nbc=NB_COLS the number of cols on the board\n"
" -f, --first=COMMAND_LINE\n"
" -s, --second=COMMAND_LINE command lines to run the two engines with.\n\n"
" -o, --outputdir=OUTPUT_DIRECTORY (default ouput is data)\n"
" --help display this help and exit.\n"
" -v, --verbose=LEVEL 1 - print moves, 2 and higher - draw boards.\n"
" -p, --pause=SECONDS 1 - sleep(1), 2 and more - sleep(2 and more).\n";
int main(int argc, array(string) argv) {
string hint = sprintf("Try `%s --help' for more information.\n",
basename(argv[0]));
if (Getopt.find_option(argv, UNDEFINED, "help")) {
write(help_message, basename(argv[0]));
return 0;
}
string str_p0 = Getopt.find_option(argv, "f", "first", UNDEFINED, "");
if (str_p0 == "") {
werror("First player is not specified.\n" + hint);
return 1;
}
string str_p1 = Getopt.find_option(argv, "s", "second", UNDEFINED, "");
if (str_p1 == "") {
werror("Second player is not specified.\n" + hint);
return 1;
}
string str_nb_games = Getopt.find_option(argv, "n", "games", UNDEFINED, "");
string str_nbl = Getopt.find_option(argv, "l", "nbl", UNDEFINED, "");
string str_nbc = Getopt.find_option(argv, "c", "nbc", UNDEFINED, "");
string str_output_dir = Getopt.find_option(argv, "o", "outputdir", UNDEFINED, "");
int verbose = (int) Getopt.find_option(argv, "v", "verbose", UNDEFINED, "0");
int in_game_pause = (int) Getopt.find_option(argv, "p", "pause", UNDEFINED, "0");
int game_nbl = 8; // default
int game_nbc = 8; // default
int nb_games = 1; // default
if (str_nbl != "") {
sscanf(str_nbl, "%d", game_nbl);
if(game_nbl <= 0) game_nbl = 8;
}
if (str_nbc != "") {
sscanf(str_nbc, "%d", game_nbc);
if(game_nbc <= 0) game_nbc = 8;
}
if (str_nb_games != "") {
sscanf(str_nb_games, "%d", nb_games);
if(nb_games <= 0) nb_games = 1;
}
btp_game game = btp_game(str_p0, str_p1, game_nbl, game_nbc, str_output_dir, in_game_pause, verbose);
if (game) {
run_many_games(game, nb_games, verbose);
}
return 0;
}