diff --git a/Makefile b/Makefile
index f1a40f3c1104950808299b45b56d6109d5876d2d..c414ab9075d6b9761320e9520aa568316dd9f904 100644
--- a/Makefile
+++ b/Makefile
@@ -1,9 +1,9 @@
-CC=g++
+CC=g++-4.9
 BIN=bin
 INCLUDE=-I src/game -I src/util -I src/monte_carlo -I src/mcts -I src/minmax
 CFLAGS=-g -O3 -ffast-math -fopenmp -c -Wall -std=c++11 $(INCLUDE)
 LDFLAGS=-fopenmp -std=c++11 #-lprofiler -Wl,-no_pie
-SOURCES=omp_util.cpp fast_log.cpp display_node.cpp morpion.cpp test_morpion.cpp connect4.cpp test_connect4.cpp monte_carlo.cpp test_monte_carlo.cpp test_fast_log.cpp\
+SOURCES=omp_util.cpp fast_log.cpp display_node.cpp connect4.cpp morpion.cpp test_two_players_game.cpp test_connect4.cpp monte_carlo.cpp test_monte_carlo.cpp test_fast_log.cpp\
 statistics.cpp node.cpp allocator.cpp test_allocator.cpp openings.cpp mcts_two_players.cpp test_mcts_two_players.cpp test_minmax.cpp\
 bits.cpp test_bits.cpp main.cpp
 OBJECTS=$(addprefix $(BIN)/, $(SOURCES:.cpp=.o))
diff --git a/doc/GameInterface.markdown b/doc/GameInterface.markdown
index 2a9f8c9984c1d66c3b376b4c419fd974d806228f..a41d5eeee67bc88773d9587ab22bf5f5ffd0d8cc 100644
--- a/doc/GameInterface.markdown
+++ b/doc/GameInterface.markdown
@@ -74,7 +74,7 @@ Representation d'un joueur de façon comprehensible par un humain
 
 ### string move_to_string(int move)
 Representation d'un coup de façon comprehensible par un humain (par exemple B7).
-**Note:** est-ce que le coup doit être compris comme le coup numéro `move` dans la liste des coups possibles ou `move` est la representation que l'ordi a du coup ?
+`move` est l'indice du coup parmi tous les coups possibles
 
 ### string to_string()
 Representation de l'état actuel du jeu (c'est à dire, dessiner l'état actuel du jeu)
@@ -111,4 +111,4 @@ void JEU::playout(mt19937& engine, int max_depth)
 ```
 
 Choisit un coup au hasard parmi les coups possibles et le joue.
-	
\ No newline at end of file
+	
diff --git a/src/game/connect4.cpp b/src/game/connect4.cpp
index c7d4a713ee93bf8e6ed6d5350696906a2c7b0f05..c4d05c85e6b0ce05879becd5c38048ca8a843f94 100644
--- a/src/game/connect4.cpp
+++ b/src/game/connect4.cpp
@@ -332,15 +332,15 @@ namespace game
     return buffer.str();
   }
 
-  void connect4::playout(mt19937& engine, int max_depth)
-  {
-    while (!end_of_game())
-      {
-  	uniform_int_distribution<uint16_t> distribution(0, number_of_moves() - 1);
-  	uint16_t move = distribution(engine);
-  	play(move);
-      }
-  }
+  // void connect4::playout(mt19937& engine, int max_depth)
+  // {
+  //   while (!end_of_game())
+  //     {
+  // 	uniform_int_distribution<uint16_t> distribution(0, number_of_moves() - 1);
+  // 	uint16_t move = distribution(engine);
+  // 	play(move);
+  //     }
+  // }
 
   std::uint64_t connect4::hash() const
   {
diff --git a/src/game/connect4.hpp b/src/game/connect4.hpp
index 369bd8ecdd43c73ba7a4ca1da790885c023dde40..1ea92aedf328a7fb13d090f7dd9c39a54a7f8183 100644
--- a/src/game/connect4.hpp
+++ b/src/game/connect4.hpp
@@ -42,7 +42,7 @@ namespace game
     std::string player_to_string(std::uint8_t player) const;
     std::string move_to_string(std::uint16_t m) const;
     std::string to_string() const;
-    void playout(std::mt19937& engine, int max_depth = -1);
+    //    void playout(std::mt19937& engine, int max_depth = -1);
     std::set<int> to_input_vector() const;
     void from_input_vector(const std::set<int>& input);
     connect4_state get_state();
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 20f5e2f1938ca0d3a1eb50e4c97736e851189ae0..1854891fc6637a4452bc1772234229c7565df960 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -25,7 +25,7 @@ namespace game
     virtual std::string player_to_string(std::uint8_t player) const = 0;
     virtual std::string move_to_string(std::uint16_t m) const = 0;
     virtual std::string to_string() const = 0;
-    virtual void playout(std::mt19937& engine, int max_depth = -1) = 0;
+    virtual void playout(std::mt19937& engine, int max_depth = -1);
     virtual std::set<int> to_input_vector() const = 0; 
     virtual void from_input_vector(const std::set<int>& input) = 0;
     virtual State get_state() = 0;
@@ -43,6 +43,15 @@ namespace game
   {
     return value(current_player());
   }
+  template<typename State> void game<State>::playout(std::mt19937& engine, int max_depth)
+  {
+    while (!end_of_game())
+      {
+	std::uniform_int_distribution<uint16_t> distribution(0, number_of_moves() - 1);
+	std::uint16_t move = distribution(engine);
+  	play(move);
+      }
+  }
 }
 
 #endif
diff --git a/src/game/morpion.cpp b/src/game/morpion.cpp
index 27030269fb70bf26e83dfd28350bfcc0c1de3b02..4662a6fc0689030159e852f4941b588ae13d64ea 100644
--- a/src/game/morpion.cpp
+++ b/src/game/morpion.cpp
@@ -172,8 +172,7 @@ namespace game
 	
 	string morpion::move_to_string(uint16_t m) const
 	{
-		return std::to_string(m);
-		
+		return std::to_string((state.possible_moves >> (4 * m)) & 0xf);
 	}
 
 	set<int> morpion::to_input_vector() const
@@ -187,7 +186,7 @@ namespace game
 
 	string morpion::to_string() const
 	{
-		string result = "";
+		string result = "-------\n";
 		for (int row = 2; row >= 0; row--)
 		{
 			result += "|";
@@ -198,23 +197,13 @@ namespace game
 				else if (((state.circle_bitboard >> (3*row)) >> col) & 1)
 					result += player_to_string(CIRCLE)+"|";
 				else
-					result += " |";
+					result += std::to_string(row * 3 + col) + "|";
 			}
 			result += "\n-------\n";
 		}
 		return result;
 	}
 
-	void morpion::playout(mt19937& engine, int max_depth)
-	{
-		while (!end_of_game())
-		{
-			uniform_int_distribution<uint16_t> distribution(0, number_of_moves() -1);
-			uint16_t move = distribution(engine);
-			play(move);
-		}
-	}
-
 	std::uint64_t morpion::hash() const
 	{
 		//TODO: Implement
diff --git a/src/game/morpion.hpp b/src/game/morpion.hpp
index 4ab8594c6d8434c9c5c4d7f3b48ae11142b0d61e..e210f5e5a419df9b26f084415ac58e454ddea600 100644
--- a/src/game/morpion.hpp
+++ b/src/game/morpion.hpp
@@ -38,7 +38,6 @@ namespace game
 			std::string player_to_string(std::uint8_t player) const; //String representation of a player
 			std::string move_to_string(std::uint16_t m) const; //String representation of a move (for example, A1)
 			std::string to_string() const; //String representation of the entire game
-			void playout(std::mt19937& engine, int max_depth = -1);
 			std::set<int> to_input_vector() const;
 			void from_input_vector(const std::set<int>& input);
 			morpion_state get_state(); //Return the state
diff --git a/src/game/test_morpion.cpp b/src/game/test_morpion.cpp
deleted file mode 100644
index 705224015a9f26c2126df6c99b80fcb06f0ad51a..0000000000000000000000000000000000000000
--- a/src/game/test_morpion.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-#include "test_morpion.hpp"
-#include "mcts_two_players.hpp"
-#include "morpion.hpp"
-#include <iostream>
-#include <map>
-
-using namespace std;
-
-
-namespace game
-{
-	test_morpion::test_morpion()
-	{
-		cout << "=== Play tic tac toe ==="<<endl;
-		cout << "Do you want to play a Player vs (P)layer or a Player vs (C)omputer match? (enter P or C) "<<endl;
-		string choice;
-		cin >> choice;
-		if (choice == "P")
-			play();
-		else if (choice == "C")
-			playout();
-		else
-			cout << "Bad choice." << endl;
-	}
-	
-	/* Start a complete Player vs Player game */
-	void test_morpion::play()
-	{
-		morpion mor;
-		cout << "Player vs Player game!" << endl;
-		while(!mor.end_of_game())
-		{
-			cout << mor << endl;
-			cout << "It's " << mor.player_to_string(mor.current_player()) << " turn." << endl;
-			map<string, int> movesMap;
-			//cout << "Number of possible moves: " << mor.number_of_moves() << endl;
-			cout << "Possible moves:";
-			uint64_t possible_moves = mor.get_state().possible_moves;
-			for(int i = 0; i < mor.number_of_moves(); i++)
-			{
-				uint16_t move = possible_moves & ((uint64_t) 15); //15 = 1111 (a move is on 4 bits)
-				//cout << "Possible move: " << mor.move_to_string(move) << endl;
-				cout << " " << mor.move_to_string(move);
-				movesMap[mor.move_to_string(move)] = i; //In the map: the move as seen by the player and its representation for the computer
-				possible_moves = possible_moves >> 4;
-			}
-			cout << endl << "Choose your move: ";
-			string move;
-			cin >> move;
-			mor.play(movesMap[move]);
-		}
-		//Game ended: print the final state of the board
-		cout << mor << endl;
-		if (mor.won(0))
-			cout << mor.player_to_string(0) << " has won" << endl;
-		else if (mor.won(1))
-			cout << mor.player_to_string(1) << " has won" << endl;
-		else
-			cout << "Draw! too bad :(" << endl;
-		
-	}
-	
-	/* Start a complete Player vs Computer game */
-	void test_morpion::playout()
-	{
-		morpion mor;
-		auto mctsPlayer = mcts::make_mcts_two_players(mor, 1000, 0.3, 4); // creation du player a partir du morpion. 1000: ms de reflexion 0.3 fateur d'exploration 4: nb_visit_before_expansion on attend d'etre arrive 4 fois sur un noeud avant de le developper
-		cout << "Player vs Computer game!" << endl;
-		cout << "Who's first? (P)layer or (C)omputer?" << endl;
-		string choice;
-		cin >> choice;
-		int IAPlayer = 1; //Default: the computer will play second
-		if (choice == "C") //If however we choosed to let the computer play first
-			IAPlayer = 0;
-		while(!mor.end_of_game())
-		{
-			cout << mor << endl;
-			if(mor.current_player() == IAPlayer) //It's computer's turn
-			{
-				mctsPlayer.reset(); //Delete the entire tree: it will construct a new one starting from this state
-				uint16_t move = mctsPlayer.select_move();
-				//cout << "Computer played move number " << move << endl;
-				mor.play(move);
-			}
-			else //Human turn to play
-			{
-				cout << "It's your time to shine!" << endl;
-				map<string, int> movesMap;
-				//cout << "Number of possible moves: " << mor.number_of_moves() << endl;
-				cout << "Possible moves:";
-				uint64_t possible_moves = mor.get_state().possible_moves;
-				for(int i = 0; i < mor.number_of_moves(); i++)
-				{
-					uint16_t move = possible_moves & ((uint64_t) 15); //15 = 1111 (a move is on 4 bits)
-					//cout << "Possible move: " << mor.move_to_string(move) << endl;
-					cout << " " << mor.move_to_string(move);
-					movesMap[mor.move_to_string(move)] = i; //In the map: the move as seen by the player and 
-					possible_moves = possible_moves >> 4;
-				}
-				cout << endl << "Choose your move: ";
-				string move;
-				cin >> move;
-				mor.play(movesMap[move]);
-			}
-		}
-		//Game ended: print the final state of the board
-		cout << mor << endl;
-		if (mor.won(0))
-			cout << mor.player_to_string(0) << " has won" << endl;
-		else if (mor.won(1))
-			cout << mor.player_to_string(1) << " has won" << endl;
-		else
-			cout << "Draw! too bad :(" << endl;
-	}
-
-}
diff --git a/src/game/test_morpion.hpp b/src/game/test_morpion.hpp
deleted file mode 100644
index 03966986fc5befd5e4c88fe9dc7d3cae98904501..0000000000000000000000000000000000000000
--- a/src/game/test_morpion.hpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __TEST_MORPION_HPP__
-#define __TEST_MORPION_HPP__
-
-namespace game
-{
-	class test_morpion
-	{
-		void playout();
-		void play();
-		public:
-			test_morpion();
-	};
-}
-#endif
diff --git a/src/game/test_two_players_game.cpp b/src/game/test_two_players_game.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a1cebabea372f759a6114bbf74dd82dc1765421
--- /dev/null
+++ b/src/game/test_two_players_game.cpp
@@ -0,0 +1,10 @@
+#include "game.hpp"
+#include "test_two_players_game.hpp"
+#include <iostream>
+#include <map>
+
+using namespace std;
+
+namespace game
+{
+}
diff --git a/src/game/test_two_players_game.hpp b/src/game/test_two_players_game.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ce7de78d460bc662b27556b3be10de6c2e4169db
--- /dev/null
+++ b/src/game/test_two_players_game.hpp
@@ -0,0 +1,76 @@
+#ifndef __TEST_TWO_PLAYERS_GAME_HPP__
+#define __TEST_TWO_PLAYERS_GAME_HPP__
+
+#include <random>
+#include <iostream>
+#include <map>
+#include <string>
+
+namespace game
+{
+  template<typename Game>
+  class test_two_players_game
+  {
+    void playout(Game g);
+    void play(Game g);
+  public:
+    test_two_players_game(Game g);
+  };
+
+  template<typename Game>
+  test_two_players_game<Game>::test_two_players_game(Game g)
+  {    
+    //    playout(g);
+    play(g);
+  }
+
+  template <typename Game>
+  void run_test_two_players_game(const Game& g)
+  {
+    test_two_players_game<Game>{g};
+  }
+
+  template <typename Game>
+  void test_two_players_game<Game>::playout(Game g)
+  {
+    std::mt19937 mt;
+    std::cout << "playout" << std::endl;
+    for (int i = 0; i < 100; ++i) 
+      {
+	uint8_t player = g.current_player();
+	auto state = g.get_state();
+	g.playout(mt);
+	std::cout << "value: " << g.value(player) << std::endl << g.to_string() << std::endl;
+	g.set_state(state);
+	std::string wait;
+	getline(std::cin, wait);
+      }
+  }
+
+  template<typename Game>
+  void test_two_players_game<Game>::play(Game g)
+  {
+    int player = 0;
+    std::cout << "play one game" << std::endl;
+    while (!g.end_of_game()) 
+      {
+	std::cout << g.to_string() << std::endl;
+	std::cout << g.player_to_string(player) << " move: ";
+	std::map<std::string, int> m;
+	for (int i = 0; i < g.number_of_moves(); ++i) 
+	  {
+	    m[g.move_to_string(i)] = i;
+	  }
+	std::string move;
+	std::cin >> move;
+	g.play(m[move]);
+	player = 1 - player;
+      }
+    std::cout << g.to_string() << std::endl;
+    if (g.won(0)) std::cout << g.player_to_string(0) << " won";
+    else if (g.won(1)) std::cout << g.player_to_string(1) << " won";
+    else std::cout << "draw";
+    std::cout << std::endl;
+  }
+}
+#endif
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 075076f250c4410c14d665fd05d2c7c838320f60..fe3a17ba54ed227c095ae715f39ea9c1dac794a5 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -1,5 +1,7 @@
-//#include "test_connect4.hpp"
-#include "test_morpion.hpp"
+#include "test_connect4.hpp"
+#include "connect4.hpp"
+#include "morpion.hpp"
+#include "test_two_players_game.hpp"
 #include "test_monte_carlo.hpp"
 #include "test_fast_log.hpp"
 #include "test_allocator.hpp"
@@ -15,11 +17,15 @@ using namespace std;
 int main(int argc, char *argv[])
 {
 	// game::test_connect4();
-	game::test_morpion();
 	// util::test_fast_log(100000000);
 	// mcts::test_allocator(10, 2);
 	// omp_set_num_threads(8);
-	//mcts::test_mcts_two_players();
+	//  game::run_test_two_players_game(game::connect4());
+	//mcts::run_test_mcts_two_players(game::connect4());
+	
+	//game::run_test_two_players_game(game::morpion());
+	mcts::run_test_mcts_two_players(game::morpion());
+
 	// minmax::test_minmax();
 	//util::test_bits(200000000);
 	//game::connect4 c4;
diff --git a/src/mcts/allocator.hpp b/src/mcts/allocator.hpp
index 9ee278779ec061547a6383404507d7e29bb0a1ec..f887fdc79c0ac430980c76aee6ba995e94b13200 100644
--- a/src/mcts/allocator.hpp
+++ b/src/mcts/allocator.hpp
@@ -15,7 +15,7 @@ namespace mcts
     void copy(node* n1, node* n2, unsigned int prunning = 0);
 
   public:
-    allocator(unsigned int size = 20000000U);
+    allocator(unsigned int size = 100000000U);
     ~allocator();
     node* allocate(unsigned int size);
     void clear();
diff --git a/src/mcts/allocator.hpp~ b/src/mcts/allocator.hpp~
deleted file mode 100644
index 150a2ffc1d220711051c77e21fe5d33779f145fa..0000000000000000000000000000000000000000
--- a/src/mcts/allocator.hpp~
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __ALLOCATOR_HPP__
-#define __ALLOCATOR_HPP__
-
-#include "node.hpp"
-
-namespace mcts
-{
-  class allocator
-  {
-    node* node_arena;
-    node* limit;
-    node* free_pointer;
-
-    node* allocate_unsafe(unsigned int size);
-    void copy(node* n1, node* n2, unsigned int prunning = 0);
-
-  public:
-    allocator(unsigned int size = 1000000U);
-    ~allocator();
-    node* allocate(unsigned int size);
-    void clear();
-    node* move(node* root, unsigned int prunning = 0);
-    unsigned int size() const;
-    unsigned int free_space() const;
-  };
-}
-
-#endif
diff --git a/src/mcts/mcts_two_players.hpp b/src/mcts/mcts_two_players.hpp
index 29e4e96abf3daa5f696c514780f86da7919d9652..b640dc66e8939938e5cf3bafac89671d2c01ab5b 100644
--- a/src/mcts/mcts_two_players.hpp
+++ b/src/mcts/mcts_two_players.hpp
@@ -210,7 +210,7 @@ namespace mcts
       }
     // std::ofstream ofs ("graph.gv", ofstream::out);
     //    util::display_node::node_to_dot(ofs, this->root, 1000, 50);
-    util::display_node::node_to_ascii(cout, this->root, 2);
+    util::display_node::node_to_ascii(cout, this->root, 1);
     //    std::cout << "finished " << new_version_ << std::endl;
     // string _;
     // getline(cin, _);
diff --git a/src/mcts/test_mcts_two_players.cpp b/src/mcts/test_mcts_two_players.cpp
index 931ccd367b26876d83c84dfb889c024cd7b85ab9..c462a7bdff0253f6375a993f6566a376dd37d311 100644
--- a/src/mcts/test_mcts_two_players.cpp
+++ b/src/mcts/test_mcts_two_players.cpp
@@ -1,6 +1,6 @@
 #include "mcts_two_players.hpp"
 #include "test_mcts_two_players.hpp"
-#include "morpion.hpp"
+#include "connect4.hpp"
 #include <iostream>
 #include <iomanip>
 #include <map>
@@ -12,269 +12,269 @@ using namespace game;
 
 namespace mcts
 {
-  test_mcts_two_players::test_mcts_two_players() : openings_(morpion())
-  {
-    //self_play(1000);
-    play();
-    //test_openings(10000, 1000);
-  }
+  // test_mcts_two_players::test_mcts_two_players() : openings_(connect4())
+  // {
+  //   //self_play(1000);
+  //   play();
+  //   //test_openings(10000, 1000);
+  // }
 
-  void test_mcts_two_players::test_openings(int nb_learning, int nb_testing)
-  {
-    //    self_play(nb_testing);
-    self_play_learn_openings(nb_learning);
-    self_play(nb_testing, true);
-  }
+  // void test_mcts_two_players::test_openings(int nb_learning, int nb_testing)
+  // {
+  //   //    self_play(nb_testing);
+  //   self_play_learn_openings(nb_learning);
+  //   self_play(nb_testing, true);
+  // }
 
-  template <typename Game>
-  int test_mcts_two_players::select_move(Game& game)
-  {
-    cout << game.player_to_string(game.current_player()) << " move: ";
-    map<string, int> m;
-    for (int i = 0; i < game.number_of_moves(); ++i)
-      {
-        m[game.move_to_string(i)] = i;
-      }
-    string move;
-    getline(cin, move);
-    game.play(m[move]);
-    return m[move];
-  }
+  // template <typename Game>
+  // int test_mcts_two_players::select_move(Game& game)
+  // {
+  //   cout << game.player_to_string(game.current_player()) << " move: ";
+  //   map<string, int> m;
+  //   for (int i = 0; i < game.number_of_moves(); ++i)
+  //     {
+  //       m[game.move_to_string(i)] = i;
+  //     }
+  //   string move;
+  //   getline(cin, move);
+  //   game.play(m[move]);
+  //   return m[move];
+  // }
 
-  void test_mcts_two_players::play()
-  {
-    //    ProfilerStart("theturk.prof");
-    morpion mor;
-    auto the_turk = make_mcts_two_players(mor, 5000, 0.3, 4);
-    cout << "play one game" << endl;
-    cout << "who's first? (h)uman/(c)omputer ";
-    string ans;
-    getline(cin, ans);
-    cout << mor << endl;
-    int human_last_move = -1, computer_last_move = -1;
-    while (!mor.end_of_game())
-      {
-        if ((ans == "h" && mor.current_player() == 0) || (ans == "c" && mor.current_player() == 1))
-	  {
-            human_last_move = select_move(mor);
-	  }
-        else
-	  {
-            if (human_last_move != -1 && computer_last_move != -1)
-	      {
-                the_turk.last_moves(computer_last_move, human_last_move);
-	      }
-            uint16_t move = the_turk.select_move();
-            computer_last_move = move;
-            cout << mor.player_to_string(mor.current_player()) << " move: " << mor.move_to_string(move) << endl;
-            mor.play(move);
-	  }
-        cout << mor << endl;
-      }
-    if (mor.value(0) == 1) cout << mor.player_to_string(0) << " won";
-    else if (mor.value(1) == 1) cout << mor.player_to_string(1) << " won";
-    else cout << "draw";
-    cout << endl;
-    //    ProfilerStop();
-  }
+  // void test_mcts_two_players::play()
+  // {
+  //   //    ProfilerStart("theturk.prof");
+  //   connect4 c4;
+  //   auto the_turk = make_mcts_two_players(c4, 5000, 0.3, 4);
+  //   cout << "play one game" << endl;
+  //   cout << "who's first? (h)uman/(c)omputer ";
+  //   string ans;
+  //   getline(cin, ans);
+  //   cout << c4 << endl;
+  //   int human_last_move = -1, computer_last_move = -1;
+  //   while (!c4.end_of_game())
+  //     {
+  //       if ((ans == "h" && c4.current_player() == 0) || (ans == "c" && c4.current_player() == 1))
+  // 	  {
+  //           human_last_move = select_move(c4);
+  // 	  }
+  //       else
+  // 	  {
+  //           if (human_last_move != -1 && computer_last_move != -1)
+  // 	      {
+  //               the_turk.last_moves(computer_last_move, human_last_move);
+  // 	      }
+  //           uint16_t move = the_turk.select_move();
+  //           computer_last_move = move;
+  //           cout << c4.player_to_string(c4.current_player()) << " move: " << c4.move_to_string(move) << endl;
+  //           c4.play(move);
+  // 	  }
+  //       cout << c4 << endl;
+  //     }
+  //   if (c4.value(0) == 1) cout << c4.player_to_string(0) << " won";
+  //   else if (c4.value(1) == 1) cout << c4.player_to_string(1) << " won";
+  //   else cout << "draw";
+  //   cout << endl;
+  //   //    ProfilerStop();
+  // }
 
-  void test_mcts_two_players::self_play_learn_openings(int n)
-  {
-    morpion mor;
-    vector<uint16_t> moves(200);
-    auto state = mor.get_state();
-    auto the_turk_1 = make_mcts_two_players(mor, 1000, 0.6, 2);
-    auto the_turk_2 = make_mcts_two_players(mor, 1000, 0.6, 2);
-    map<set<int>, pair<uint32_t, double>> learning_examples;
-    for (int i = 0; i < n; ++i)
-      {
-        cout << i << endl;
-        cout << openings_ << endl << endl;
-        moves.clear();
-        mor.set_state(state);
-        the_turk_1.reset();
-        the_turk_1.init_with_openings(openings_);
-        the_turk_2.reset();
-        the_turk_2.init_with_openings(openings_);
-        int the_turk_1_last_move = -1, the_turk_2_last_move = -1;
-        int k = 0;
-        while (!mor.end_of_game())
-	  {
-            if (k == 1) the_turk_2.last_move(the_turk_1_last_move);
-            if (k % 2 == 0)
-	      {
-                if (the_turk_2_last_move != -1)
-		  {
-                    the_turk_1.last_moves(the_turk_1_last_move, the_turk_2_last_move);
-		  }
-                uint16_t move = the_turk_1.select_move();
-                moves.push_back(move);
-                the_turk_1_last_move = move;
-                mor.play(move);
-	      }
-            else
-	      {
-                if (the_turk_2_last_move != -1)
-		  {
-                    the_turk_2.last_moves(the_turk_2_last_move, the_turk_1_last_move);
-		  }
-                uint16_t move = the_turk_2.select_move();
-                moves.push_back(move);
-                the_turk_2_last_move = move;
-                mor.play(move);
-	      }
-            ++k;
-	  }
-	std::cout << mor << std::endl;
-        int v = mor.value(0);
-        cout << "value for first player " << v << endl;
-        mor.set_state(state);
-        openings_.update(mor, moves, v);
-	mor.set_state(state);
-	for (uint16_t m : moves) 
-	  {
-	    mor.play(m);
-	    v = -v;
-	    set<int> input_vector = std::move(mor.to_input_vector());
-	    auto it = learning_examples.find(input_vector);
-	    if (it == learning_examples.end())
-	      {
-		learning_examples[input_vector] = make_pair(1, v);
-	      }
-	    else
-	      {
-		it->second.second = (it->second.second * it->second.first + v) / (it->second.first + 1);
-		it->second.first += 1;
-	      }
-	  }
-      }
-    cout << "number of learning examples: " << learning_examples.size() << endl;
-    ofstream output("learning_examples.txt");
-    for (const auto& example : learning_examples) 
-      {
-	output << example.second.second;
-	for (int index : example.first) 
-	  {
-	    output << " " << index << ":" << 1;
-	  }
-	output << endl;
-      }
-    output.close();
-  }
+  // void test_mcts_two_players::self_play_learn_openings(int n)
+  // {
+  //   connect4 c4;
+  //   vector<uint16_t> moves(200);
+  //   auto state = c4.get_state();
+  //   auto the_turk_1 = make_mcts_two_players(c4, 1000, 0.6, 2);
+  //   auto the_turk_2 = make_mcts_two_players(c4, 1000, 0.6, 2);
+  //   map<set<int>, pair<uint32_t, double>> learning_examples;
+  //   for (int i = 0; i < n; ++i)
+  //     {
+  //       cout << i << endl;
+  //       cout << openings_ << endl << endl;
+  //       moves.clear();
+  //       c4.set_state(state);
+  //       the_turk_1.reset();
+  //       the_turk_1.init_with_openings(openings_);
+  //       the_turk_2.reset();
+  //       the_turk_2.init_with_openings(openings_);
+  //       int the_turk_1_last_move = -1, the_turk_2_last_move = -1;
+  //       int k = 0;
+  //       while (!c4.end_of_game())
+  // 	  {
+  //           if (k == 1) the_turk_2.last_move(the_turk_1_last_move);
+  //           if (k % 2 == 0)
+  // 	      {
+  //               if (the_turk_2_last_move != -1)
+  // 		  {
+  //                   the_turk_1.last_moves(the_turk_1_last_move, the_turk_2_last_move);
+  // 		  }
+  //               uint16_t move = the_turk_1.select_move();
+  //               moves.push_back(move);
+  //               the_turk_1_last_move = move;
+  //               c4.play(move);
+  // 	      }
+  //           else
+  // 	      {
+  //               if (the_turk_2_last_move != -1)
+  // 		  {
+  //                   the_turk_2.last_moves(the_turk_2_last_move, the_turk_1_last_move);
+  // 		  }
+  //               uint16_t move = the_turk_2.select_move();
+  //               moves.push_back(move);
+  //               the_turk_2_last_move = move;
+  //               c4.play(move);
+  // 	      }
+  //           ++k;
+  // 	  }
+  // 	std::cout << c4 << std::endl;
+  //       int v = c4.value(0);
+  //       cout << "value for first player " << v << endl;
+  //       c4.set_state(state);
+  //       openings_.update(c4, moves, v);
+  // 	c4.set_state(state);
+  // 	for (uint16_t m : moves) 
+  // 	  {
+  // 	    c4.play(m);
+  // 	    v = -v;
+  // 	    set<int> input_vector = std::move(c4.to_input_vector());
+  // 	    auto it = learning_examples.find(input_vector);
+  // 	    if (it == learning_examples.end())
+  // 	      {
+  // 		learning_examples[input_vector] = make_pair(1, v);
+  // 	      }
+  // 	    else
+  // 	      {
+  // 		it->second.second = (it->second.second * it->second.first + v) / (it->second.first + 1);
+  // 		it->second.first += 1;
+  // 	      }
+  // 	  }
+  //     }
+  //   cout << "number of learning examples: " << learning_examples.size() << endl;
+  //   ofstream output("learning_examples.txt");
+  //   for (const auto& example : learning_examples) 
+  //     {
+  // 	output << example.second.second;
+  // 	for (int index : example.first) 
+  // 	  {
+  // 	    output << " " << index << ":" << 1;
+  // 	  }
+  // 	output << endl;
+  //     }
+  //   output.close();
+  // }
 
-  void test_mcts_two_players::self_play(int n, bool with_openings)
-  {
-    morpion mor;
-    auto state = mor.get_state();
-    auto the_turk_v1 = make_mcts_two_players(mor, 1000, 0.6, 2);
-    auto the_turk_v2 = make_mcts_two_players(mor, 1000, 0.6, 2);
-    int nb_win_v1 = 0, nb_win_v2 = 0, nb_draw = 0;
-    for (int i = 0; i < n; ++i)
-      {
-        cout << i << endl;
-        mor.set_state(state);
-        the_turk_v1.reset();
-        the_turk_v2.reset();
-	if (with_openings) the_turk_v2.init_with_openings(openings_);
-        int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
-	int k = 0;
-        while (!mor.end_of_game())
-	  {
-            if (with_openings && k == 1 && i % 2 == 0) the_turk_v2.last_move(the_turk_v1_last_move);
-	    ++k;
-            //	    cout << mor << endl;
-            if ((i % 2 == 0 && mor.current_player() == 0) || (i % 2 == 1 && mor.current_player() == 1))
-	      {
-                if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
-		  {
-                    the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
-		  }
-                uint16_t move = the_turk_v1.select_move();
-                the_turk_v1_last_move = move;
-                mor.play(move);
-	      }
-            else
-	      {
-                if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
-		  {
-                    the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
-		  }
-                uint16_t move = the_turk_v2.select_move();
-                the_turk_v2_last_move = move;
-                mor.play(move);
-	      }
-	  }
-        if (mor.value(0) == 1)
-	  {
-            if (i % 2 == 0)
-	      {
-                /*cout << "v1 won" << endl;*/ ++nb_win_v1;
-	      }
-            else
-	      {
-                /*cout << "v2 won" << endl;*/ ++nb_win_v2;
-	      }
-	  }
-        else if (mor.value(1) == 1)
-	  {
-            if (i % 2 == 0)
-	      {
-                /*cout << "v2 won" << endl;*/ ++nb_win_v2;
-	      }
-            else
-	      {
-                /*cout << "v1 won" << endl;*/ ++nb_win_v1;
-	      }
-	  }
-        else
-	  {
-            /*cout << "draw" << endl;*/ ++nb_draw;
-	  }
-        cout << setw(10) << "v1 nb wins: " << nb_win_v1 << " v2 nb wins: " << nb_win_v2 << " nb draws: " << nb_draw << endl;
-      }
-  }
+  // void test_mcts_two_players::self_play(int n, bool with_openings)
+  // {
+  //   connect4 c4;
+  //   auto state = c4.get_state();
+  //   auto the_turk_v1 = make_mcts_two_players(c4, 1000, 0.6, 2);
+  //   auto the_turk_v2 = make_mcts_two_players(c4, 1000, 0.6, 2);
+  //   int nb_win_v1 = 0, nb_win_v2 = 0, nb_draw = 0;
+  //   for (int i = 0; i < n; ++i)
+  //     {
+  //       cout << i << endl;
+  //       c4.set_state(state);
+  //       the_turk_v1.reset();
+  //       the_turk_v2.reset();
+  // 	if (with_openings) the_turk_v2.init_with_openings(openings_);
+  //       int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
+  // 	int k = 0;
+  //       while (!c4.end_of_game())
+  // 	  {
+  //           if (with_openings && k == 1 && i % 2 == 0) the_turk_v2.last_move(the_turk_v1_last_move);
+  // 	    ++k;
+  //           //	    cout << c4 << endl;
+  //           if ((i % 2 == 0 && c4.current_player() == 0) || (i % 2 == 1 && c4.current_player() == 1))
+  // 	      {
+  //               if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+  // 		  {
+  //                   the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
+  // 		  }
+  //               uint16_t move = the_turk_v1.select_move();
+  //               the_turk_v1_last_move = move;
+  //               c4.play(move);
+  // 	      }
+  //           else
+  // 	      {
+  //               if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+  // 		  {
+  //                   the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
+  // 		  }
+  //               uint16_t move = the_turk_v2.select_move();
+  //               the_turk_v2_last_move = move;
+  //               c4.play(move);
+  // 	      }
+  // 	  }
+  //       if (c4.value(0) == 1)
+  // 	  {
+  //           if (i % 2 == 0)
+  // 	      {
+  //               /*cout << "v1 won" << endl;*/ ++nb_win_v1;
+  // 	      }
+  //           else
+  // 	      {
+  //               /*cout << "v2 won" << endl;*/ ++nb_win_v2;
+  // 	      }
+  // 	  }
+  //       else if (c4.value(1) == 1)
+  // 	  {
+  //           if (i % 2 == 0)
+  // 	      {
+  //               /*cout << "v2 won" << endl;*/ ++nb_win_v2;
+  // 	      }
+  //           else
+  // 	      {
+  //               /*cout << "v1 won" << endl;*/ ++nb_win_v1;
+  // 	      }
+  // 	  }
+  //       else
+  // 	  {
+  //           /*cout << "draw" << endl;*/ ++nb_draw;
+  // 	  }
+  //       cout << setw(10) << "v1 nb wins: " << nb_win_v1 << " v2 nb wins: " << nb_win_v2 << " nb draws: " << nb_draw << endl;
+  //     }
+  // }
 
-  void test_mcts_two_players::self_play()
-  {
-    morpion mor;
-    auto the_turk_v1 = make_mcts_two_players(mor, 1000, 1.2, 2);
-    auto the_turk_v2 = make_mcts_two_players(mor, 1000, 1.2, 2);
-    cout << "play one game" << endl;
-    cout << "who's first? the_turk_(v1)/the_turk_(v2) ";
-    string ans;
-    getline(cin, ans);
-    cout << mor << endl;
-    int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
-    while (!mor.end_of_game())
-      {
-        if ((ans == "v1" && mor.current_player() == 0) || (ans == "v2" && mor.current_player() == 1))
-	  {
-            if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
-	      {
-                the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
-	      }
-            uint16_t move = the_turk_v1.select_move();
-            the_turk_v1_last_move = move;
-            cout << mor.player_to_string(mor.current_player()) << " move: " << mor.move_to_string(move) << endl;
-            mor.play(move);
-	  }
-        else
-	  {
-            if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
-	      {
-                the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
-	      }
-            uint16_t move = the_turk_v2.select_move();
-            the_turk_v2_last_move = move;
-            cout << mor.player_to_string(mor.current_player()) << " move: " << mor.move_to_string(move) << endl;
-            mor.play(move);
-	  }
-        cout << mor << endl;
-      }
-    if (mor.value(0) == 1) cout << mor.player_to_string(0) << " won";
-    else if (mor.value(1) == 1) cout << mor.player_to_string(1) << " won";
-    else cout << "draw";
-    cout << endl;
-  }
+  // void test_mcts_two_players::self_play()
+  // {
+  //   connect4 c4;
+  //   auto the_turk_v1 = make_mcts_two_players(c4, 1000, 1.2, 2);
+  //   auto the_turk_v2 = make_mcts_two_players(c4, 1000, 1.2, 2);
+  //   cout << "play one game" << endl;
+  //   cout << "who's first? the_turk_(v1)/the_turk_(v2) ";
+  //   string ans;
+  //   getline(cin, ans);
+  //   cout << c4 << endl;
+  //   int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
+  //   while (!c4.end_of_game())
+  //     {
+  //       if ((ans == "v1" && c4.current_player() == 0) || (ans == "v2" && c4.current_player() == 1))
+  // 	  {
+  //           if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+  // 	      {
+  //               the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
+  // 	      }
+  //           uint16_t move = the_turk_v1.select_move();
+  //           the_turk_v1_last_move = move;
+  //           cout << c4.player_to_string(c4.current_player()) << " move: " << c4.move_to_string(move) << endl;
+  //           c4.play(move);
+  // 	  }
+  //       else
+  // 	  {
+  //           if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+  // 	      {
+  //               the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
+  // 	      }
+  //           uint16_t move = the_turk_v2.select_move();
+  //           the_turk_v2_last_move = move;
+  //           cout << c4.player_to_string(c4.current_player()) << " move: " << c4.move_to_string(move) << endl;
+  //           c4.play(move);
+  // 	  }
+  //       cout << c4 << endl;
+  //     }
+  //   if (c4.value(0) == 1) cout << c4.player_to_string(0) << " won";
+  //   else if (c4.value(1) == 1) cout << c4.player_to_string(1) << " won";
+  //   else cout << "draw";
+  //   cout << endl;
+  // }
 
 }
diff --git a/src/mcts/test_mcts_two_players.hpp b/src/mcts/test_mcts_two_players.hpp
index c04f71f676f0036ac61d1194924437e02baa757c..e8c10331fc13e2409528acbebbcae0ff5c25c894 100644
--- a/src/mcts/test_mcts_two_players.hpp
+++ b/src/mcts/test_mcts_two_players.hpp
@@ -2,24 +2,305 @@
 #define __TEST_MCTS_TWO_PLAYERS_HPP__
 
 #include "openings.hpp"
+#include "mcts_two_players.hpp"
+#include <string>
+#include <iostream>
+#include <map>
+#include <iomanip>
+#include <set>
+#include <fstream>
 
 namespace mcts
 {
+  template <typename Game>
   class test_mcts_two_players
   {
     openings openings_;
 
-    void play();
-    void self_play();
-    void self_play(int n, bool with_openings = false);
-    void self_play_learn_openings(int n);
-    void test_openings(int nb_learning, int nb_testing); 
-    
-    template <typename Game>
+    void play(Game g);
+    void self_play(Game g);
+    void self_play(Game g, int n, bool with_openings = false);
+    void self_play_learn_openings(Game g, int n);
+    void test_openings(Game g, int nb_learning, int nb_testing); 
     int select_move(Game& game);
   public:
-    test_mcts_two_players();    
+    test_mcts_two_players(const Game& g);    
   };
+
+  template <typename Game>
+  test_mcts_two_players<Game>::test_mcts_two_players(const Game& g) : openings_(g)
+  {
+    //self_play(g, 1000);
+    play(g);
+    //test_openings(g, 10000, 1000);
+  }
+
+  template <typename Game>
+  void run_test_mcts_two_players(const Game& g)
+  {
+    test_mcts_two_players<Game>{g};
+  }
+
+
+  template <typename Game>
+  void test_mcts_two_players<Game>::test_openings(Game g, int nb_learning, int nb_testing)
+  {
+    //    self_play(g, nb_testing);
+    self_play_learn_openings(g, nb_learning);
+    self_play(g, nb_testing, true);
+  }
+
+  template <typename Game>
+  int test_mcts_two_players<Game>::select_move(Game& game)
+  {
+    std::cout << game.player_to_string(game.current_player()) << " move: ";
+    std::map<std::string, int> m;
+    for (int i = 0; i < game.number_of_moves(); ++i)
+      {
+        m[game.move_to_string(i)] = i;
+      }
+    std::string move;
+    getline(std::cin, move);
+    game.play(m[move]);
+    return m[move];
+  }
+
+  template <typename Game>
+  void test_mcts_two_players<Game>::play(Game g)
+  {
+    //    ProfilerStart("theturk.prof");
+    auto the_turk = make_mcts_two_players(g, 5000, 0.3, 4);
+    std::cout << "play one game" << std::endl;
+    std::cout << "who's first? (h)uman/(c)omputer ";
+    std::string ans;
+    getline(std::cin, ans);
+    std::cout << g.to_string() << std::endl;
+    int human_last_move = -1, computer_last_move = -1;
+    while (!g.end_of_game())
+      {
+        if ((ans == "h" && g.current_player() == 0) || (ans == "c" && g.current_player() == 1))
+	  {
+            human_last_move = select_move(g);
+	  }
+        else
+	  {
+            if (human_last_move != -1 && computer_last_move != -1)
+	      {
+                the_turk.last_moves(computer_last_move, human_last_move);
+	      }
+            uint16_t move = the_turk.select_move();
+            computer_last_move = move;
+            std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
+            g.play(move);
+	  }
+        std::cout << g << std::endl;
+      }
+    if (g.won(0)) std::cout << g.player_to_string(0) << " won";
+    else if (g.won(1)) std::cout << g.player_to_string(1) << " won";
+    else std::cout << "draw";
+    std::cout << std::endl;
+    //    ProfilerStop();
+  }
+
+  template <typename Game>
+  void test_mcts_two_players<Game>::self_play_learn_openings(Game g, int n)
+  {
+    std::vector<uint16_t> moves(200);
+    auto state = g.get_state();
+    auto the_turk_1 = make_mcts_two_players(g, 1000, 0.6, 2);
+    auto the_turk_2 = make_mcts_two_players(g, 1000, 0.6, 2);
+    std::map<std::set<int>, std::pair<std::uint32_t, double>> learning_examples;
+    for (int i = 0; i < n; ++i)
+      {
+        std::cout << i << std::endl;
+        std::cout << openings_ << std::endl << std::endl;
+        moves.clear();
+        g.set_state(state);
+        the_turk_1.reset();
+        the_turk_1.init_with_openings(openings_);
+        the_turk_2.reset();
+        the_turk_2.init_with_openings(openings_);
+        int the_turk_1_last_move = -1, the_turk_2_last_move = -1;
+        int k = 0;
+        while (!g.end_of_game())
+	  {
+            if (k == 1) the_turk_2.last_move(the_turk_1_last_move);
+            if (k % 2 == 0)
+	      {
+                if (the_turk_2_last_move != -1)
+		  {
+                    the_turk_1.last_moves(the_turk_1_last_move, the_turk_2_last_move);
+		  }
+                std::uint16_t move = the_turk_1.select_move();
+                moves.push_back(move);
+                the_turk_1_last_move = move;
+                g.play(move);
+	      }
+            else
+	      {
+                if (the_turk_2_last_move != -1)
+		  {
+                    the_turk_2.last_moves(the_turk_2_last_move, the_turk_1_last_move);
+		  }
+                std::uint16_t move = the_turk_2.select_move();
+                moves.push_back(move);
+                the_turk_2_last_move = move;
+                g.play(move);
+	      }
+            ++k;
+	  }
+	std::cout << g.to_string() << std::endl;
+        int v = g.value(0);
+        std::cout << "value for first player " << v << std::endl;
+        g.set_state(state);
+        openings_.update(g, moves, v);
+	g.set_state(state);
+	for (std::uint16_t m : moves) 
+	  {
+	    g.play(m);
+	    v = -v;
+	    std::set<int> input_vector = std::move(g.to_input_vector());
+	    auto it = learning_examples.find(input_vector);
+	    if (it == learning_examples.end())
+	      {
+		learning_examples[input_vector] = std::make_pair(1, v);
+	      }
+	    else
+	      {
+		it->second.second = (it->second.second * it->second.first + v) / (it->second.first + 1);
+		it->second.first += 1;
+	      }
+	  }
+      }
+    std::cout << "number of learning examples: " << learning_examples.size() << std::endl;
+    std::ofstream output("learning_examples.txt");
+    for (const auto& example : learning_examples) 
+      {
+	output << example.second.second;
+	for (int index : example.first) 
+	  {
+	    output << " " << index << ":" << 1;
+	  }
+	output << std::endl;
+      }
+    output.close();
+  }
+
+  template <typename Game>
+  void test_mcts_two_players<Game>::self_play(Game g, int n, bool with_openings)
+  {
+    auto state = g.get_state();
+    auto the_turk_v1 = make_mcts_two_players(g, 1000, 0.6, 2);
+    auto the_turk_v2 = make_mcts_two_players(g, 1000, 0.6, 2);
+    int nb_win_v1 = 0, nb_win_v2 = 0, nb_draw = 0;
+    for (int i = 0; i < n; ++i)
+      {
+	std::cout << i << std::endl;
+        g.set_state(state);
+        the_turk_v1.reset();
+        the_turk_v2.reset();
+	if (with_openings) the_turk_v2.init_with_openings(openings_);
+        int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
+	int k = 0;
+        while (!g.end_of_game())
+	  {
+            if (with_openings && k == 1 && i % 2 == 0) the_turk_v2.last_move(the_turk_v1_last_move);
+	    ++k;
+            //	    cout << c4 << endl;
+            if ((i % 2 == 0 && g.current_player() == 0) || (i % 2 == 1 && g.current_player() == 1))
+	      {
+                if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+		  {
+                    the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
+		  }
+                std::uint16_t move = the_turk_v1.select_move();
+                the_turk_v1_last_move = move;
+                g.play(move);
+	      }
+            else
+	      {
+                if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+		  {
+                    the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
+		  }
+                std::uint16_t move = the_turk_v2.select_move();
+                the_turk_v2_last_move = move;
+                play(move);
+	      }
+	  }
+        if (g.won(0))
+	  {
+            if (i % 2 == 0)
+	      {
+                /*cout << "v1 won" << endl;*/ ++nb_win_v1;
+	      }
+            else
+	      {
+                /*cout << "v2 won" << endl;*/ ++nb_win_v2;
+	      }
+	  }
+        else if (g.won(1))
+	  {
+            if (i % 2 == 0)
+	      {
+                /*cout << "v2 won" << endl;*/ ++nb_win_v2;
+	      }
+            else
+	      {
+                /*cout << "v1 won" << endl;*/ ++nb_win_v1;
+	      }
+	  }
+        else
+	  {
+            /*cout << "draw" << endl;*/ ++nb_draw;
+	  }
+        std::cout << std::setw(10) << "v1 nb wins: " << nb_win_v1 << " v2 nb wins: " << nb_win_v2 << " nb draws: " << nb_draw << std::endl;
+      }
+  }
+
+  template <typename Game>
+  void test_mcts_two_players<Game>::self_play(Game g)
+  {
+    auto the_turk_v1 = make_mcts_two_players(g, 1000, 1.2, 2);
+    auto the_turk_v2 = make_mcts_two_players(g, 1000, 1.2, 2);
+    std::cout << "play one game" << std::endl;
+    std::cout << "who's first? the_turk_(v1)/the_turk_(v2) ";
+    std::string ans;
+    getline(std::cin, ans);
+    std::cout << g << std::endl;
+    int the_turk_v1_last_move = -1, the_turk_v2_last_move = -1;
+    while (!g.end_of_game())
+      {
+        if ((ans == "v1" && g.current_player() == 0) || (ans == "v2" && g.current_player() == 1))
+	  {
+            if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+	      {
+                the_turk_v1.last_moves(the_turk_v1_last_move, the_turk_v2_last_move);
+	      }
+            std::uint16_t move = the_turk_v1.select_move();
+            the_turk_v1_last_move = move;
+            std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
+            g.play(move);
+	  }
+        else
+	  {
+            if (the_turk_v1_last_move != -1 && the_turk_v2_last_move != -1)
+	      {
+                the_turk_v2.last_moves(the_turk_v2_last_move, the_turk_v1_last_move);
+	      }
+            std::uint16_t move = the_turk_v2.select_move();
+            the_turk_v2_last_move = move;
+            std::cout << g.player_to_string(g.current_player()) << " move: " << g.move_to_string(move) << std::endl;
+            g.play(move);
+	  }
+        std::cout << g << std::endl;
+      }
+    if (g.won(0)) std::cout << g.player_to_string(0) << " won";
+    else if (g.won(1)) std::cout << g.player_to_string(1) << " won";
+    else std::cout << "draw";
+    std::cout << std::endl;
+  }
+
 }
 
 #endif