Skip to content
Snippets Groups Projects
penguin.cpp 11.5 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);
		
		//Change player if the other one can play
		if(state.current_player_red && state.nb_moves_blue > 0)
			state.current_player_red = false;
		else if(state.current_player_red == false && state.nb_moves_red > 0)
			state.current_player_red = true;
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;
	}
	
	void penguin::set_state(const penguin_state& s)
	{
		state = s; 
	}

	bool penguin::end_of_game() const
	{
		return state.nb_moves_red == 0 && state.nb_moves_blue == 0;
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 9 - state.total_moves;
		return 0;
	}
	
	/* 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) + ((*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) + ((*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) + ((*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) + ((*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) + ((*p) & 63);
			return;
		}
		move_number -= penguin_copy & 7;
		penguin_copy = penguin_copy >> 3;
		//Move direction F
		(*p) = (8 * move_number) + ((*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)
	{   
		//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);
		}
Gaste Adrien's avatar
Gaste Adrien committed
		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
		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);
		
		//Change player if the other one can play
		if(state.current_player_red && state.nb_moves_blue > 0)
			state.current_player_red = false;
		else if(state.current_player_red == false && state.nb_moves_red > 0)
			state.current_player_red = true;
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)
	{
	}

	string penguin::to_string() const
	{
Bariatti Francesco's avatar
Bariatti Francesco committed
		string result= "--------------------";
		result += "\n1 fish bro: " + std::to_string(state.one_fish);
		result += "\nTwo fishes: " + std::to_string(state.two_fish);
		result += "\nThree fish: " + std::to_string(state.three_fish);
		result += "\nRed p1: " + std::to_string(state.p1_red);
		result += "\nRed p2: " + std::to_string(state.p2_red);
		result += "\nRed p3: " + std::to_string(state.p3_red);
		result += "\nRed p4: " + std::to_string(state.p4_red);
		result += "\nBlue p1: " + std::to_string(state.p1_blue);
		result += "\nBlue p2: " + std::to_string(state.p2_blue);
		result += "\nBlue p3: " + std::to_string(state.p3_blue);
		result += "\nBlue p4: " + std::to_string(state.p4_blue);
		
		result += "\nScore R: " + std::to_string(state.score_red);
		result += "\nScore B: " + std::to_string(state.score_blue);
		
		result += "\nNb possible moves R:" + std::to_string(state.nb_moves_red);
		result += "\nNb possible moves B:" + std::to_string(state.nb_moves_blue);
		
Gaste Adrien's avatar
Gaste Adrien committed
		return result;
	}

	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() << endl;
		return os;
	}
}