#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 { 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 { return state.total_moves & 1 ? CIRCLE : CROSS; // CROSS even, CIRCLE odd } int morpion::value(uint8_t player) const { if (player == CROSS) { return state.first_player_win? 1 : (state.second_player_win? -1 : 0); } 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 { return state.total_moves; } bool morpion::get(uint16_t bitboard, uint8_t col, uint8_t row) const { return bitboard & (1LL << (3*row)) << col; } //#define set(bitboard, col, row) (bitboard |= (1LL << (((col) << 3) + (row)))) void morpion::update_win() { if(has_won(state.cross_bitboard)) state.first_player_win = true; else if(has_won(state.circle_bitboard)) state.second_player_win = true; } 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 --- return true; if(((bitboard | COL0_MASK) == ALL_ONES) || ((bitboard | COL1_MASK) == ALL_ONES) || ((bitboard | COL2_MASK) == ALL_ONES)) // Check vertical | return true; if(((bitboard | DIA0_MASK) == ALL_ONES) || ((bitboard | DIA1_MASK) == ALL_ONES)) // Chack diagonal \ / return true; return false; } 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; state.possible_moves = state.possible_moves << 4; } free_bitboard = free_bitboard >> 1; } } void morpion::play(uint16_t m) { if (current_player() == CROSS) state.cross_bitboard += (1 << m); else state.circle_bitboard += (1 << m); //State update state.total_moves++; update_win(); update_moves(); return; } /** * 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 { uint8_t row = m/3; uint8_t col = m%3; 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--) { 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; } }