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
//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);
Bariatti Francesco
committed
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)
{
uint32_t penguin_copy = (*p) >> 12;
//Direction A
if((penguin_copy & 7) > 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_copy & 7;
if((penguin_copy & 7) > rel_move)
(*p) = (-1 * (rel_move +1)) + ((*p) & 63);
rel_move -= penguin_copy & 7;
if((penguin_copy & 7) > rel_move)
(*p) = (-8 * (rel_move +1)) + ((*p) & 63);
rel_move -= penguin_copy & 7;
if((penguin_copy & 7) > rel_move)
(*p) = (-7 * (rel_move +1)) + ((*p) & 63);
rel_move -= penguin_copy & 7;
if((penguin_copy & 7) > rel_move)
(*p) = (1 * (rel_move +1)) + ((*p) & 63);
rel_move -= penguin_copy & 7;
penguin_copy = penguin_copy >> 3;
//Move direction F
(*p) = (8 * (rel_move +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;
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
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
//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)
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 */
#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
#define POS(penguin) ((penguin) & 63)
if((state.one_fish >> 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) << POS(*peng));
Bariatti Francesco
committed
}
else if((state.two_fish >> 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) << 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)
state.one_fish = state.one_fish & ~(((uint64_t) 1) << 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.
//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;
Bariatti Francesco
committed
if (state.current_player_red) //Red just played
{
Bariatti Francesco
committed
if(state.canPlay_blue)
Bariatti Francesco
committed
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
}
Bariatti Francesco
committed
{
state.nb_moves_blue = 1;
}
Bariatti Francesco
committed
Bariatti Francesco
committed
state.current_player_red = false;
}
else //Blue just played
{
Bariatti Francesco
committed
if(state.canPlay_red)
Bariatti Francesco
committed
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;
}
Bariatti Francesco
committed
{
state.nb_moves_red = 1;
}
Bariatti Francesco
committed
Bariatti Francesco
committed
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();