Skip to content
Snippets Groups Projects
penguin.cpp 11.9 KiB
Newer Older
Gaste Adrien's avatar
Gaste Adrien committed
#include "penguin.hpp"
#include <sstream>

using namespace std;

namespace game
{
	penguin::penguin()
	{
		//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);
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
	}
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;
Gaste Adrien's avatar
Gaste Adrien committed
	}
	/* 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;
	}
Gaste Adrien's avatar
Gaste Adrien committed
	//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);
			}
			{
				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
				}
			{
				state.nb_moves_blue = 1;
			}
			
			state.current_player_red = false;
		}
		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;
	}
}