#include "penguin.hpp" #include <sstream> using namespace std; namespace game { /** * Creates the game: load the state from standard input. * Penguins in state can be composed of just their position: the moves will be updated automatically. **/ penguin::penguin() { cout << "Enter penguin game state as JSON on one line" << endl; string line; getline(cin, line); json json_state = json::parse(line); //Charging every element of the state if it exists if(json_state.count("bitboards")) { if(json_state["bitboards"].count("onefish")) {state.one_fish = json_state["bitboards"]["onefish"];} if(json_state["bitboards"].count("twofish")) {state.two_fish = json_state["bitboards"]["twofish"];} if(json_state["bitboards"].count("threefish")) {state.three_fish = json_state["bitboards"]["threefish"];} } if(json_state.count("current_player")) state.current_player_red = json_state["current_player"] == "Red" ? true : false; if(json_state.count("penguins")) { if(json_state["penguins"].count("red")) { state.p1_red = json_state["penguins"]["red"][0]; state.p2_red = json_state["penguins"]["red"][1]; state.p3_red = json_state["penguins"]["red"][2]; state.p4_red = json_state["penguins"]["red"][3]; } if(json_state["penguins"].count("blue")) { state.p1_blue = json_state["penguins"]["blue"][0]; state.p2_blue = json_state["penguins"]["blue"][1]; state.p3_blue = json_state["penguins"]["blue"][2]; state.p4_blue = json_state["penguins"]["blue"][3]; } } if(json_state.count("score")) { if(json_state["score"].count("red")) { state.score_red = json_state["score"]["red"]; } if(json_state["score"].count("blue")) { state.score_blue = json_state["score"]["blue"]; } } //Update moves on all penguins uint64_t obstacles = (~(state.one_fish | state.two_fish | state.three_fish)); obstacles |= ((uint64_t) 1) << (state.p1_red & 63); obstacles |= ((uint64_t) 1) << (state.p2_red & 63); obstacles |= ((uint64_t) 1) << (state.p3_red & 63); obstacles |= ((uint64_t) 1) << (state.p4_red & 63); obstacles |= ((uint64_t) 1) << (state.p1_blue & 63); obstacles |= ((uint64_t) 1) << (state.p2_blue & 63); obstacles |= ((uint64_t) 1) << (state.p3_blue & 63); obstacles |= ((uint64_t) 1) << (state.p4_blue & 63); state.nb_moves_red = 0; state.nb_moves_blue = 0; state.nb_moves_red += update_moves(&state.p1_red, obstacles); state.nb_moves_red += update_moves(&state.p2_red, obstacles); state.nb_moves_red += update_moves(&state.p3_red, obstacles); state.nb_moves_red += update_moves(&state.p4_red, obstacles); state.nb_moves_blue += update_moves(&state.p1_blue, obstacles); state.nb_moves_blue += update_moves(&state.p2_blue, obstacles); state.nb_moves_blue += update_moves(&state.p3_blue, obstacles); state.nb_moves_blue += update_moves(&state.p4_blue, obstacles); if (state.nb_moves_red == 0) { state.canPlay_red = false; state.nb_moves_red = 1; //We create an artificial move so that the mcts works } if (state.nb_moves_blue == 0) { state.canPlay_blue = false; state.nb_moves_blue = 1; //We create an artificial move so that the mcts works } } shared_ptr<game<penguin_state>> penguin::do_copy() const { return shared_ptr<penguin>(new penguin(*this)); } penguin_state penguin::get_state() { return state; } void penguin::set_state(const penguin_state& s) { state = s; } bool penguin::end_of_game() const { return state.canPlay_red == false && state.canPlay_blue == false; } bool penguin::won(std::uint8_t player) const { if (player == RED) return state.score_red > state.score_blue; return state.score_blue > state.score_red; } bool penguin::lost(std::uint8_t player) const { if(player == RED) return state.score_red < state.score_blue; return state.score_blue < state.score_red; } bool penguin::draw(std::uint8_t player) const { return state.score_blue == state.score_red; } uint8_t penguin::current_player() const { return state.current_player_red ? RED : BLUE; } int penguin::value(uint8_t player) const { if (won(player)) return 1; else if (lost(player)) return -1; else return 0; } /* Number of moves that you can play */ uint16_t penguin::number_of_moves() const { return state.current_player_red ? state.nb_moves_red : state.nb_moves_blue; } /* The penguin that will move if we want to play the #move_number move in the list of possible moves. * What this function does: * Find the penguin that will move. * Change its total number of moves so that it is relative to that penguin's possible moves and not relative to ALL the penguins' moves. * Return a pointer to that penguin * */ uint32_t* penguin::penguin_that_moves(uint16_t move_number) { if(state.current_player_red) { if(((state.p1_red >> 6) & 63) > move_number) { uint32_t* p = &state.p1_red; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p1_red >> 6) & 63; if(((state.p2_red >> 6) & 63) > move_number) { uint32_t* p = &state.p2_red; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p2_red >> 6) & 63; if(((state.p3_red >> 6) & 63) > move_number) { uint32_t* p = &state.p3_red; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p3_red >> 6) & 63; uint32_t* p = &state.p4_red; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } else { if(((state.p1_blue >> 6) & 63) > move_number) { uint32_t* p = &state.p1_blue; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p1_blue >> 6) & 63; if(((state.p2_blue >> 6) & 63) > move_number) { uint32_t* p = &state.p2_blue; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p2_blue >> 6) & 63; if(((state.p3_blue >> 6) & 63) > move_number) { uint32_t* p = &state.p3_blue; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } move_number -= (state.p3_blue >> 6) & 63; uint32_t* p = &state.p4_blue; (*p) = (*p) & 0xFFFFF03F; //Reset move number for the penguin to 0 (*p) = (*p) | ((uint32_t) move_number) << 6; return p; } } void penguin::move_penguin(uint32_t* p) { uint8_t move_number = ((*p) >> 6) & 63; //Move number for the current penguin uint32_t penguin_copy = (*p) >> 12; //Direction A if((penguin_copy & 7) > move_number) { //Move direction A (*p) = (7 * (move_number +1)) + ((*p) & 63); return; } move_number -= penguin_copy & 7; penguin_copy = penguin_copy >> 3; if((penguin_copy & 7) > move_number) { //Move direction B (*p) = (-1 * (move_number +1)) + ((*p) & 63); return; } move_number -= penguin_copy & 7; penguin_copy = penguin_copy >> 3; if((penguin_copy & 7) > move_number) { //Move direction C (*p) = (-8 * (move_number +1)) + ((*p) & 63); return; } move_number -= penguin_copy & 7; penguin_copy = penguin_copy >> 3; if((penguin_copy & 7) > move_number) { //Move direction D (*p) = (-7 * (move_number +1)) + ((*p) & 63); return; } move_number -= penguin_copy & 7; penguin_copy = penguin_copy >> 3; if((penguin_copy & 7) > move_number) { //Move direction E (*p) = (1 * (move_number +1)) + ((*p) & 63); return; } move_number -= penguin_copy & 7; penguin_copy = penguin_copy >> 3; //Move direction F (*p) = (8 * (move_number +1)) + ((*p) & 63); } int penguin::update_moves(uint32_t* p, uint64_t obstacles) { #define IsFree(i) (((obstacles >> (i)) & 1) == 0) int pos = (*p) & 63; (*p) = pos; //Reset the penguin to all zeros except the position int i = pos; uint32_t nbmoves = 0; uint32_t total_moves = 0; //Direction A while(((i+7) < 60) && (i%15 != 0) && IsFree(i+7)) { i += 7; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 12; //Direction B nbmoves = 0; i = pos; while((i%15 != 0) && (i%15 != 8) && IsFree(i-1)) { i --; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 15; //Direction C nbmoves = 0; i = pos; while((i-8 > 0) && (i%15 != 0) && IsFree(i-8)) { i -= 8; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 18; //Direction D nbmoves = 0; i = pos; while((i-7 > 0) && (i%15 != 7) && IsFree(i-7)) { i -= 7; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 21; //Direction E nbmoves = 0; i = pos; while((i%15 != 7) && (i%15 != 14) && IsFree(i+1)) { i ++; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 24; //Direction F nbmoves = 0; i = pos; while((i+8 < 60) && (i%15 != 7) && IsFree(i+8)) { i += 8; nbmoves++; total_moves++; } (*p) = (*p) | nbmoves << 27; (*p) = (*p) | total_moves << 6; return total_moves; } //Play the mth move in the possible moves list. void penguin::play(uint16_t m) { if ((state.current_player_red == true && state.canPlay_red) || ((state.current_player_red == false) && state.canPlay_blue)) { //Find which penguin will move uint32_t* p = penguin_that_moves(m); uint8_t position = (*p) & 63; //Find the value of the tile the penguin is on and update score if ((state.one_fish >> position) & 1) { if(current_player() == RED) state.score_red += 1; else state.score_blue += 1; //We replace this tile with an empty one (0 in the bitboard) state.one_fish = state.one_fish & ~(((uint64_t) 1) << position); } else if ((state.two_fish >> position) & 1) { if(current_player() == RED) state.score_red += 2; else state.score_blue += 2; //We replace this tile with an empty one (0 in the bitboard) state.two_fish = state.two_fish & ~(((uint64_t) 1) << position); } else { if(current_player() == RED) state.score_red += 3; else state.score_blue += 3; //We replace this tile with an empty one (0 in the bitboard) state.three_fish = state.three_fish & ~(((uint64_t) 1) << position); } //Move the current penguin move_penguin(p); } //Update moves on all penguins of the next player uint64_t obstacles = (~(state.one_fish | state.two_fish | state.three_fish)); obstacles |= ((uint64_t) 1) << (state.p1_red & 63); obstacles |= ((uint64_t) 1) << (state.p2_red & 63); obstacles |= ((uint64_t) 1) << (state.p3_red & 63); obstacles |= ((uint64_t) 1) << (state.p4_red & 63); obstacles |= ((uint64_t) 1) << (state.p1_blue & 63); obstacles |= ((uint64_t) 1) << (state.p2_blue & 63); obstacles |= ((uint64_t) 1) << (state.p3_blue & 63); obstacles |= ((uint64_t) 1) << (state.p4_blue & 63); state.nb_moves_red = 0; state.nb_moves_blue = 0; if (state.current_player_red) //Red just played { if(state.canPlay_blue) { state.nb_moves_blue += update_moves(&state.p1_blue, obstacles); state.nb_moves_blue += update_moves(&state.p2_blue, obstacles); state.nb_moves_blue += update_moves(&state.p3_blue, obstacles); state.nb_moves_blue += update_moves(&state.p4_blue, obstacles); if (state.nb_moves_blue == 0) { state.canPlay_blue = false; state.nb_moves_blue = 1; //We create an artificial move so that the mcts works } } else { state.nb_moves_blue = 1; } state.current_player_red = false; } else //Blue just played { if(state.canPlay_red) { state.nb_moves_red += update_moves(&state.p1_red, obstacles); state.nb_moves_red += update_moves(&state.p2_red, obstacles); state.nb_moves_red += update_moves(&state.p3_red, obstacles); state.nb_moves_red += update_moves(&state.p4_red, obstacles); if (state.nb_moves_red == 0) { state.canPlay_red = false; state.nb_moves_red = 1; } } else { state.nb_moves_red = 1; } state.current_player_red = true; } } string penguin::player_to_string(uint8_t player) const { return player == RED ? "Red" : "Blue"; } string penguin::move_to_string(uint16_t m) const { return std::to_string(m); } set<int> penguin::to_input_vector() const { return set<int>(); } void penguin::from_input_vector(const std::set<int>& input) { } json penguin::to_JSON() const { json json_state; json_state["bitboards"]["onefish"] = state.one_fish; json_state["bitboards"]["twofish"] = state.two_fish; json_state["bitboards"]["threefish"] = state.three_fish; json_state["penguins"]["red"][0] = state.p1_red; json_state["penguins"]["red"][1] = state.p2_red; json_state["penguins"]["red"][2] = state.p3_red; json_state["penguins"]["red"][3] = state.p4_red; json_state["penguins"]["blue"][0] = state.p1_blue; json_state["penguins"]["blue"][1] = state.p2_blue; json_state["penguins"]["blue"][2] = state.p3_blue; json_state["penguins"]["blue"][3] = state.p4_blue; json_state["score"]["red"] = state.score_red; json_state["score"]["blue"] = state.score_blue; json_state["possible_moves"]["red"] = state.nb_moves_red; json_state["possible_moves"]["blue"] = state.nb_moves_blue; json_state["current_player"] = state.current_player_red ? "Red" : "Blue"; json_state["can_play"]["red"] = state.canPlay_red; json_state["can_play"]["blue"] = state.canPlay_blue; return json_state; } string penguin::to_string() const { ostringstream os; os << to_JSON() << endl; return os.str(); } std::uint64_t penguin::hash() const { return 0; } std::uint64_t penguin::hash(std::uint16_t m) const { return 0; } ostream& operator<<(ostream& os, const penguin& pen) { os << pen.to_string(); return os; } }