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.
**/
Pizon Antoine
committed
/*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"]; }
Pizon Antoine
committed
}*/
//Positioning penguins randomly
srand (time(NULL));
for(int i = 0; i < 4; i++){
int tmprand = rand()%60;
while(is_occupied(tmprand)){
tmprand = rand()%60;
}
state.peng_red[i] = tmprand;
while(is_occupied(tmprand)){
tmprand = rand()%60;
}
state.peng_blue[i] = tmprand;
cout << "Rouge " << i+1 << " : " << state.peng_red[i] << endl;
cout << "Bleu " << i+1 << " : " << state.peng_blue[i] << endl;
Pizon Antoine
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;
Bariatti Francesco
committed
/* 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;
while((i-8 >= 0) && (i%15 != 0) && IsFree(i-8))
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
{
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];
}
Bariatti Francesco
committed
// 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;
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;
const tile_content penguin::get_tile(std::uint8_t tile_index) const
{
for(int k = 0; k < 4; k++) {
if(PENGUIN_POS(state.peng_blue[k]) == tile_index)
return BLUE_PENGUIN;
if(PENGUIN_POS(state.peng_red[k]) == tile_index)
return RED_PENGUIN;
}
if(((state.one_fish >> (tile_index)) & 1) > 0)
return ONE_FISH;
if(((state.two_fish >> (tile_index)) & 1) > 0)
return TWO_FISH;
Pizon Antoine
committed
if(((state.three_fish >> (tile_index)) & 1) > 0)
return THREE_FISH;
return OBSTACLE;
Pizon Antoine
committed
}
Pizon Antoine
committed
const bool penguin::is_occupied(std::uint8_t tile_index) const
{
return get_tile(tile_index) == RED_PENGUIN || get_tile(tile_index) == BLUE_PENGUIN;
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;
for(int i = 0; i < 4; i++)
{
json_state["penguins"]["red"][i] = state.peng_red[i];
json_state["penguins"]["blue"][i] = state.peng_blue[i];
}
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
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;
Pizon Antoine
committed
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
//Display game in terminal
/*
cout << "|------------------------|" << endl << "| ";
for(int i = 59; i >= 0; i--){
switch(get_tile(i)){
case ONE_FISH:
cout << " 1 " ;
break;
case TWO_FISH:
cout << " 2 " ;
break;
case THREE_FISH:
cout << " 3 ";
break;
case BLUE_PENGUIN:
cout << " b ";
break;
case RED_PENGUIN:
cout << " r ";
break;
default:
cout << " * ";
}
if(i%15 == 8)
cout << " |" << endl << "|";
if(i%15 == 0 && i != 0)
cout << "|" << endl << "| ";
}
cout << "|" << endl << "|------------------------|" << 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();