Newer
Older
#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.
**/
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"))
{
Bariatti Francesco
committed
for(int i = 0; i < 4; i++)
state.peng_red[i] = json_state["penguins"]["red"][i];
}
if(json_state["penguins"].count("blue"))
{
Bariatti Francesco
committed
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"]; }
}
Bariatti Francesco
committed
Bariatti Francesco
committed
// We compute the moves for all penguin
uint64_t obstacles = create_obstacles_bitboard();
state.nb_moves_red = 0;
state.nb_moves_blue = 0;
Bariatti Francesco
committed
for(int i = 0; i < 4; i++)
{
state.nb_moves_red += update_penguin_moves(&state.peng_red[i], obstacles);
state.nb_moves_blue += update_penguin_moves(&state.peng_blue[i], 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)
{
Bariatti Francesco
committed
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;
/*
Moves the penguin p (modify its position value), making it do its rel_move move.
At the end of the function the penguin will be composed of just its new position (every other bit is at 0)
*/
void penguin::move_penguin(uint32_t* p, uint16_t rel_move)
if(PENGUIN_MOVES_A(*p) > rel_move) //If the penguin total moves in this direction are greater than the move we want to do for it (not equal because moves start at 0)
(*p) = (7 * (rel_move +1)) + ((*p) & 63);
rel_move -= PENGUIN_MOVES_A(*p);
if(PENGUIN_MOVES_B(*p) > rel_move)
(*p) = (-1 * (rel_move +1)) + ((*p) & 63);
rel_move -= PENGUIN_MOVES_B(*p);
if(PENGUIN_MOVES_C(*p) > rel_move)
(*p) = (-8 * (rel_move +1)) + ((*p) & 63);
rel_move -= PENGUIN_MOVES_C(*p);
if(PENGUIN_MOVES_D(*p) > rel_move)
(*p) = (-7 * (rel_move +1)) + ((*p) & 63);
rel_move -= PENGUIN_MOVES_D(*p);
if(PENGUIN_MOVES_E(*p) > rel_move)
(*p) = (1 * (rel_move +1)) + ((*p) & 63);
rel_move -= PENGUIN_MOVES_E(*p);
(*p) = (8 * (rel_move +1)) + ((*p) & 63);
Bariatti Francesco
committed
/* Create bitboard of obstacles: 1 if there is an obstacle, 0 if the penguin can
move freely on the tile
*/
uint64_t penguin::create_obstacles_bitboard()
{
uint64_t obstacles = (~(state.one_fish | state.two_fish | state.three_fish));
for(int i = 0; i < 4; i++)
{
obstacles |= ((uint64_t) 1) << PENGUIN_POS(state.peng_red[i]);
obstacles |= ((uint64_t) 1) << PENGUIN_POS(state.peng_blue[i]);
}
return obstacles;
}
/* Updates the moves of a signle penguin.
This computes the moves in every direction according to the penguin position and the obstacles.
Parameters:
- p: a penguin that will be updated. Only his position is used and the rest is computed
- obstacles: a bitboard of obstacles: 1 means an obstacle in that tile
Returns:
Total moves of this penguin.
*/
int penguin::update_penguin_moves(uint32_t* p, uint64_t obstacles)
Bariatti Francesco
committed
#define IsFree(i) (((obstacles >> (i)) & 1) == 0)
int pos = PENGUIN_POS(*p);
(*p) = pos; //Reset the penguin to all zeros except the position
int i = pos;
Bariatti Francesco
committed
uint32_t nbmoves = 0; //Nb of moves in one direction
//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;
Bariatti Francesco
committed
while((i-8 >= 0) && (i%15 != 0) && IsFree(i-8))
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
{
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)
Bariatti Francesco
committed
//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)
Bariatti Francesco
committed
if ((state.current_player_red == true && state.canPlay_red) || ((state.current_player_red == false) && state.canPlay_blue))
Bariatti Francesco
committed
//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 */
for(i = 0; (i < 3) && (PENGUIN_TOT_MOVES(state.peng_red[i]) <= rel_move); i ++) //While we didn't find the penguin
rel_move -= PENGUIN_TOT_MOVES(state.peng_red[i]);
Bariatti Francesco
committed
// 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
{
for(i = 0; (i < 3) && (PENGUIN_TOT_MOVES(state.peng_blue[i]) <= rel_move); i ++) //While we didn't find the penguin
rel_move -= PENGUIN_TOT_MOVES(state.peng_blue[i]);
Bariatti Francesco
committed
peng = &state.peng_blue[i];
}
// ADD PENGUIN TILE TO THE SCORE
if((state.one_fish >> PENGUIN_POS(*peng)) & 1) //If there is a one fish on this position
Bariatti Francesco
committed
{
if(state.current_player_red)
Bariatti Francesco
committed
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) << PENGUIN_POS(*peng));
Bariatti Francesco
committed
}
else if((state.two_fish >> PENGUIN_POS(*peng)) & 1)
Bariatti Francesco
committed
{
if(state.current_player_red)
Bariatti Francesco
committed
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) << PENGUIN_POS(*peng));
Bariatti Francesco
committed
}
Bariatti Francesco
committed
{
if(state.current_player_red)
Bariatti Francesco
committed
state.score_red += 3;
else
state.score_blue += 3;
//We replace this tile with an empty one (0 in the bitboard)
Bariatti Francesco
committed
state.three_fish = state.three_fish & ~(((uint64_t) 1) << PENGUIN_POS(*peng));
Bariatti Francesco
committed
}
// MOVE THE PENGUIN
move_penguin(peng, rel_move);
Bariatti Francesco
committed
}
// END CAN_WE PLAY. We will now compute the moves for every penguin and for the player.
Bariatti Francesco
committed
uint64_t obstacles = create_obstacles_bitboard();
state.nb_moves_red = 0;
state.nb_moves_blue = 0;
Bariatti Francesco
committed
if (state.current_player_red) //Red just played
{
Bariatti Francesco
committed
if(state.canPlay_blue) //If blue couldn't play last turn there is no way he could play this new turn
Bariatti Francesco
committed
for(int i = 0; i < 4; i++)
state.nb_moves_blue += update_penguin_moves(&state.peng_blue[i], obstacles);
Bariatti Francesco
committed
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
}
Bariatti Francesco
committed
{
Bariatti Francesco
committed
state.nb_moves_blue = 1; //We create an artificial move so that the mcts works
Bariatti Francesco
committed
}
state.current_player_red = false;
}
else //Blue just played
{
Bariatti Francesco
committed
if(state.canPlay_red)
Bariatti Francesco
committed
for(int i = 0; i < 4; i++)
state.nb_moves_red += update_penguin_moves(&state.peng_red[i], obstacles);
Bariatti Francesco
committed
if (state.nb_moves_red == 0)
{
state.canPlay_red = false;
state.nb_moves_red = 1;
}
Bariatti Francesco
committed
{
state.nb_moves_red = 1;
}
state.current_player_red = true;
string penguin::player_to_string(uint8_t player) const
{
string penguin::move_to_string(uint16_t m) const
{
}
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";
Bariatti Francesco
committed
Bariatti Francesco
committed
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();