Skip to content
Snippets Groups Projects
penguin.cpp 12.3 KiB
Newer Older
Gaste Adrien's avatar
Gaste Adrien committed
#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.
	**/
Gaste Adrien's avatar
Gaste Adrien committed
	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"))
			{
				for(int i = 0; i < 4; i++)
					state.peng_red[i] = json_state["penguins"]["red"][i];
			}
			if(json_state["penguins"].count("blue"))
			{
				for(int i = 0; i < 4; i++)
					state.peng_blue[i] = json_state["penguins"]["blue"][i];
			}
		}
		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
		}
Gaste Adrien's avatar
Gaste Adrien committed
	}

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

	penguin_state penguin::get_state()
	{
		return state;
	}
Gaste Adrien's avatar
Gaste Adrien committed
	void penguin::set_state(const penguin_state& s)
	{
		state = s;
Gaste Adrien's avatar
Gaste Adrien committed
	}

	bool penguin::end_of_game() const
	{
		return state.canPlay_red == false && state.canPlay_blue == false;
Gaste Adrien's avatar
Gaste Adrien committed
	}

	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;
Gaste Adrien's avatar
Gaste Adrien committed
	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;
Gaste Adrien's avatar
Gaste Adrien committed
	}

	bool penguin::draw(std::uint8_t player) const
	{
		return state.score_blue == state.score_red;
Gaste Adrien's avatar
Gaste Adrien committed
	}

	uint8_t penguin::current_player() const
	{
		return state.current_player_red ? RED : BLUE;
Gaste Adrien's avatar
Gaste Adrien committed

	int penguin::value(uint8_t player) const
	{
		if (won(player))
			return 1;
		else if (lost(player))
			return -1;
		else
			return 0;
Gaste Adrien's avatar
Gaste Adrien committed
	}

	/* 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;
	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;
	}
Gaste Adrien's avatar
Gaste Adrien committed
	//Play the mth move in the possible moves list.
	void penguin::play(uint16_t m)
		//CAN WE PLAY?
		// We check if we can effectively play: if yes, the move is parsed and player, otherwise we do nothing (the move can be whatever, we won't look at it, so the player actually skip the turn)
		if ((state.current_player_red == true && state.canPlay_red) || ((state.current_player_red == false) && state.canPlay_blue))
			//WHICH PENGUIN WILL MOVE?
			uint32_t* peng; // The penguin that will move
			uint16_t rel_move = m; // Move number relative to this penguin
			int i = 0;
			if(state.current_player_red)
			{
				/* We search for the first penguin that can make the move. If a penguin can't, we will decrese the move number
				by the number of moves that he can do */
				#define TOT_MOVES(penguin) ((penguin >> 6) & 63)
				for(i = 0; (i < 3) && (TOT_MOVES(state.peng_red[i]) <= rel_move); i ++) //While we didn't find the penguin
					rel_move -= TOT_MOVES(state.peng_red[i]);
				// Now i is the number of the penguin that will move and rel_move is the move relative to this penguin (because we decreased it)
				peng = &state.peng_red[i];
			}
			else //If blue
			{
				#define TOT_MOVES(penguin) ((penguin >> 6) & 63)
				for(i = 0; (i < 3) && (TOT_MOVES(state.peng_blue[i]) <= rel_move); i ++) //While we didn't find the penguin
					rel_move -= TOT_MOVES(state.peng_blue[i]);
				peng = &state.peng_blue[i];
			}

			// ADD PENGUIN TILE TO THE 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);
			}
			{
				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);
			}
		//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
		{
				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 //Blue just played
		{
				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;
				}
Gaste Adrien's avatar
Gaste Adrien committed
	string penguin::player_to_string(uint8_t player) const
	{
		return player == RED ? "Red" : "Blue";
Gaste Adrien's avatar
Gaste Adrien committed
	string penguin::move_to_string(uint16_t m) const
	{
Bariatti Francesco's avatar
Bariatti Francesco committed
		return std::to_string(m);
Gaste Adrien's avatar
Gaste Adrien committed
	}

	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;
	}

	string penguin::to_string() const
	{
		ostringstream os;
		os << to_JSON() << endl;
		return os.str();
Gaste Adrien's avatar
Gaste Adrien committed
	}

	std::uint64_t penguin::hash() const
	{
		return 0;
	}

	std::uint64_t penguin::hash(std::uint16_t m) const
	{
		return 0;
	}
Gaste Adrien's avatar
Gaste Adrien committed
	ostream& operator<<(ostream& os, const penguin& pen)
	{
Gaste Adrien's avatar
Gaste Adrien committed
		return os;
	}
}