Skip to content
Snippets Groups Projects
morpion.cpp 4.88 KiB
Newer Older
#include "morpion.hpp"
#include <sstream>

using namespace std;

namespace game
{
	static vector<vector<uint64_t>> create_hash_values()
	{
		default_random_engine generator;
		uniform_int_distribution<uint64_t> distribution;
		vector<vector<uint64_t>> res(7, vector<uint64_t>(6, 0));
		for (int i = 0; i < 7; ++i) 
		{
			for (int j = 0; j < 6; ++j)
			{
				res[i][j] = distribution(generator);
			}
		}
		return res;
	}

	vector<vector<uint64_t>> morpion::cross_hash_values = create_hash_values();
	vector<vector<uint64_t>> morpion::circle_hash_values = create_hash_values();

	morpion::morpion()
	{
	}

	shared_ptr<game<morpion_state>> morpion::do_copy() const
	{
		return shared_ptr<morpion>(new morpion(*this));
	}

	morpion_state morpion::get_state()
	{
		return state;
	}
	
	void morpion::set_state(const morpion_state& s)
	{
		state = s; 
	}

	bool morpion::end_of_game() const
	{
Le Mikael's avatar
Le Mikael committed
		return state.first_player_win || state.second_player_win || state.total_moves == 9;
	}

	bool morpion::won(std::uint8_t player) const
	{
		if (player == CROSS) return state.first_player_win;
		return state.second_player_win;
	}
	
	bool morpion::lost(std::uint8_t player) const
	{
		if (player == CIRCLE) return state.first_player_win;
		return state.second_player_win;
	}

	bool morpion::draw(std::uint8_t player) const
	{
		if (state.first_player_win || state.second_player_win) return false;
		return state.total_moves == 9;
	}

	uint8_t morpion::current_player() const
	{
Le Mikael's avatar
Le Mikael committed
		return state.total_moves & 1 ? CIRCLE : CROSS; // CROSS even, CIRCLE odd
Le Mikael's avatar
Le Mikael committed
	} 

	int morpion::value(uint8_t player) const
	{
Gaste Adrien's avatar
Gaste Adrien committed
		if (player == CROSS) {
			return state.first_player_win? 1 : (state.second_player_win? -1 : 0);
Gaste Adrien's avatar
Gaste Adrien committed
		}
		else if (player == CIRCLE) {
			return state.second_player_win? 1 : (state.first_player_win? -1 : 0);
		return 0;
	}

	uint16_t morpion::number_of_moves() const
	{
Le Mikael's avatar
Le Mikael committed
		return state.total_moves;
	bool morpion::get(uint16_t bitboard, uint8_t col, uint8_t row) const
Bariatti Francesco's avatar
Bariatti Francesco committed
		return bitboard & (1LL << (3*row)) << col;
	}

//#define set(bitboard, col, row) (bitboard |= (1LL << (((col) << 3) + (row))))

	void morpion::update_win()
	{
Le Mikael's avatar
Le Mikael committed
		if(has_won(state.cross_bitboard))
			state.first_player_win = true;
		else if(has_won(state.circle_bitboard))
			state.second_player_win = true;
Le Mikael's avatar
Le Mikael committed
	bool morpion::has_won(uint16_t bitboard)
		if(((bitboard | ROW0_MASK) == ALL_ONES) || ((bitboard | ROW1_MASK) == ALL_ONES) || ((bitboard | ROW2_MASK) == ALL_ONES)) // Check horizontal ---
Le Mikael's avatar
Le Mikael committed
			return true;
		if(((bitboard | COL0_MASK) == ALL_ONES) || ((bitboard | COL1_MASK) == ALL_ONES) || ((bitboard | COL2_MASK) == ALL_ONES)) // Check vertical |
Le Mikael's avatar
Le Mikael committed
			return true;
		if(((bitboard | DIA0_MASK) == ALL_ONES) || ((bitboard | DIA1_MASK) == ALL_ONES)) // Chack diagonal \ /
Le Mikael's avatar
Le Mikael committed
			return true;
Bariatti Francesco's avatar
Bariatti Francesco committed
	void morpion::update_moves()
		uint16_t free_bitboard = ~(state.cross_bitboard | state.circle_bitboard);
		state.possible_moves = 0;
		for(int i = 0; i <=8; i++)
		{
			if(free_bitboard & 1)
			{
					state.possible_moves += i;
Bariatti Francesco's avatar
Bariatti Francesco committed
					state.possible_moves = state.possible_moves << 4;
			}
			free_bitboard = free_bitboard >> 1;
		}
	void morpion::play(uint16_t m)
Le Mikael's avatar
Le Mikael committed
	{   
Gaste Adrien's avatar
Gaste Adrien committed
		if (current_player() == CROSS)
			state.cross_bitboard += (1 << m);
Gaste Adrien's avatar
Gaste Adrien committed
		else
			state.circle_bitboard += (1 << m);
Gaste Adrien's avatar
Gaste Adrien committed
		
		//State update
		state.total_moves++;
		update_win();
		update_moves();
	
	
	/**
	 * player_to_string
	 * Retourne X si le joueur joue les croix, O s'il joue les ronds, 
	 * et un espace sinon.
	 */
	string morpion::player_to_string(uint8_t player) const
	{
		return player == CROSS ? "X" : (player == CIRCLE ? "O" : " ");
	string morpion::move_to_string(uint16_t m) const
	{
		return "( "+std::to_string(row)+", "+std::to_string(col)+" )";
	}

	set<int> morpion::to_input_vector() const
	{
		return set<int>();
	}

	void morpion::from_input_vector(const std::set<int>& input)
	{
	}

	string morpion::to_string() const
	{
		string result = "";
		for (int row = 2; row >= 0; row--)
		{
Bariatti Francesco's avatar
Bariatti Francesco committed
			result += "|";
			for (int col = 2; col >= 0; col--)
			{
				if(((state.cross_bitboard >> (3*row)) >> col) & 1)
					result += player_to_string(CROSS)+"|";
				else if (((state.circle_bitboard >> (3*row)) >> col) & 1)
					result += player_to_string(CIRCLE)+"|";
				else
					result += " |";
			}
			result += "\n-------\n";
		}
		return result;
	}

	void morpion::playout(mt19937& engine, int max_depth)
	{
		while (!end_of_game())
		{
			uniform_int_distribution<uint16_t> distribution(0, 8-state.total_moves);
			uint16_t move = distribution(engine);
			uint16_t position = (state.possible_moves >> 4*move) & 15; //15 is the mask to get only one move
			play(position);
		}
	}

	std::uint64_t morpion::hash() const
	{
		//TODO: Implement
		return 0;
	}

	std::uint64_t morpion::hash(std::uint16_t m) const
	{
		//TODO: Implement
		return 0;
	}
	
	ostream& operator<<(ostream& os, const morpion& mor)
	{
		os << mor.to_string() << endl;
		return os;
	}
}