Skip to content
Snippets Groups Projects
Commit 0f0f9cef authored by Bariatti Francesco's avatar Bariatti Francesco
Browse files

Merge branch 'penguinArray'

Conflicts:
	AI/src/game/penguin.cpp
parents 793a36bf fbb086f0
No related branches found
No related tags found
No related merge requests found
...@@ -28,17 +28,13 @@ namespace game ...@@ -28,17 +28,13 @@ namespace game
{ {
if(json_state["penguins"].count("red")) if(json_state["penguins"].count("red"))
{ {
state.p1_red = json_state["penguins"]["red"][0]; for(int i = 0; i < 4; i++)
state.p2_red = json_state["penguins"]["red"][1]; state.peng_red[i] = json_state["penguins"]["red"][i];
state.p3_red = json_state["penguins"]["red"][2];
state.p4_red = json_state["penguins"]["red"][3];
} }
if(json_state["penguins"].count("blue")) if(json_state["penguins"].count("blue"))
{ {
state.p1_blue = json_state["penguins"]["blue"][0]; for(int i = 0; i < 4; i++)
state.p2_blue = json_state["penguins"]["blue"][1]; state.peng_blue[i] = json_state["penguins"]["blue"][i];
state.p3_blue = json_state["penguins"]["blue"][2];
state.p4_blue = json_state["penguins"]["blue"][3];
} }
} }
if(json_state.count("score")) if(json_state.count("score"))
...@@ -46,29 +42,16 @@ namespace game ...@@ -46,29 +42,16 @@ namespace game
if(json_state["score"].count("red")) { state.score_red = json_state["score"]["red"]; } 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"]; } if(json_state["score"].count("blue")) { state.score_blue = json_state["score"]["blue"]; }
} }
// We compute the moves for all penguin
//Update moves on all penguins uint64_t obstacles = create_obstacles_bitboard();
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_red = 0;
state.nb_moves_blue = 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);
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) if (state.nb_moves_red == 0)
{ {
state.canPlay_red = false; state.canPlay_red = false;
...@@ -139,140 +122,81 @@ namespace game ...@@ -139,140 +122,81 @@ namespace game
return state.current_player_red ? state.nb_moves_red : state.nb_moves_blue; return state.current_player_red ? state.nb_moves_red : state.nb_moves_blue;
} }
/* The penguin that will move if we want to play the #move_number move in the list of possible moves. /*
* What this function does: Moves the penguin p (modify its position value), making it do its rel_move move.
* Find the penguin that will move. At the end of the function the penguin will be composed of just its new position (every other bit is at 0)
* 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 void penguin::move_penguin(uint32_t* p, uint16_t rel_move)
* */
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 //Direction A
if((penguin_copy & 7) > move_number) 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)
{ {
//Move direction A //Move direction A
(*p) = (7 * (move_number +1)) + ((*p) & 63); (*p) = (7 * (rel_move +1)) + ((*p) & 63);
return; return;
} }
move_number -= penguin_copy & 7; rel_move -= PENGUIN_MOVES_A(*p);
penguin_copy = penguin_copy >> 3; if(PENGUIN_MOVES_B(*p) > rel_move)
if((penguin_copy & 7) > move_number)
{ {
//Move direction B //Move direction B
(*p) = (-1 * (move_number +1)) + ((*p) & 63); (*p) = (-1 * (rel_move +1)) + ((*p) & 63);
return; return;
} }
move_number -= penguin_copy & 7; rel_move -= PENGUIN_MOVES_B(*p);
penguin_copy = penguin_copy >> 3; if(PENGUIN_MOVES_C(*p) > rel_move)
if((penguin_copy & 7) > move_number)
{ {
//Move direction C //Move direction C
(*p) = (-8 * (move_number +1)) + ((*p) & 63); (*p) = (-8 * (rel_move +1)) + ((*p) & 63);
return; return;
} }
move_number -= penguin_copy & 7; rel_move -= PENGUIN_MOVES_C(*p);
penguin_copy = penguin_copy >> 3; if(PENGUIN_MOVES_D(*p) > rel_move)
if((penguin_copy & 7) > move_number)
{ {
//Move direction D //Move direction D
(*p) = (-7 * (move_number +1)) + ((*p) & 63); (*p) = (-7 * (rel_move +1)) + ((*p) & 63);
return; return;
} }
move_number -= penguin_copy & 7; rel_move -= PENGUIN_MOVES_D(*p);
penguin_copy = penguin_copy >> 3; if(PENGUIN_MOVES_E(*p) > rel_move)
if((penguin_copy & 7) > move_number)
{ {
//Move direction E //Move direction E
(*p) = (1 * (move_number +1)) + ((*p) & 63); (*p) = (1 * (rel_move +1)) + ((*p) & 63);
return; return;
} }
move_number -= penguin_copy & 7; rel_move -= PENGUIN_MOVES_E(*p);
penguin_copy = penguin_copy >> 3;
//Move direction F //Move direction F
(*p) = (8 * (move_number +1)) + ((*p) & 63); (*p) = (8 * (rel_move +1)) + ((*p) & 63);
}
/* 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;
} }
int penguin::update_moves(uint32_t* p, uint64_t 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)
{ {
#define IsFree(i) (((obstacles >> (i)) & 1) == 0) #define IsFree(i) (((obstacles >> (i)) & 1) == 0)
int pos = (*p) & 63; int pos = PENGUIN_POS(*p);
(*p) = pos; //Reset the penguin to all zeros except the position (*p) = pos; //Reset the penguin to all zeros except the position
int i = pos; int i = pos;
uint32_t nbmoves = 0; uint32_t nbmoves = 0; //Nb of moves in one direction
uint32_t total_moves = 0; uint32_t total_moves = 0;
//Direction A //Direction A
...@@ -335,68 +259,74 @@ namespace game ...@@ -335,68 +259,74 @@ namespace game
//Play the mth move in the possible moves list. //Play the mth move in the possible moves list.
void penguin::play(uint16_t m) void penguin::play(uint16_t m)
{ {
//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)
if ((state.current_player_red == true && state.canPlay_red) || ((state.current_player_red == false) && state.canPlay_blue)) if ((state.current_player_red == true && state.canPlay_red) || ((state.current_player_red == false) && state.canPlay_blue))
{ {
//Find which penguin will move //WHICH PENGUIN WILL MOVE?
uint32_t* p = penguin_that_moves(m); uint32_t* peng; // The penguin that will move
uint8_t position = (*p) & 63; 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]);
// 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]);
peng = &state.peng_blue[i];
}
//Find the value of the tile the penguin is on and update score // ADD PENGUIN TILE TO THE SCORE
if ((state.one_fish >> position) & 1) if((state.one_fish >> PENGUIN_POS(*peng)) & 1) //If there is a one fish on this position
{ {
if(current_player() == RED) if(state.current_player_red)
state.score_red += 1; state.score_red += 1;
else else
state.score_blue += 1; state.score_blue += 1;
//We replace this tile with an empty one (0 in the bitboard) //We replace this tile with an empty one (0 in the bitboard)
state.one_fish = state.one_fish & ~(((uint64_t) 1) << position); state.one_fish = state.one_fish & ~(((uint64_t) 1) << PENGUIN_POS(*peng));
} }
else if ((state.two_fish >> position) & 1) else if((state.two_fish >> PENGUIN_POS(*peng)) & 1)
{ {
if(state.current_player_red)
if(current_player() == RED)
state.score_red += 2; state.score_red += 2;
else else
state.score_blue += 2; state.score_blue += 2;
//We replace this tile with an empty one (0 in the bitboard) //We replace this tile with an empty one (0 in the bitboard)
state.two_fish = state.two_fish & ~(((uint64_t) 1) << position); state.two_fish = state.two_fish & ~(((uint64_t) 1) << PENGUIN_POS(*peng));
} }
else else
{ {
if(current_player() == RED) if(state.current_player_red)
state.score_red += 3; state.score_red += 3;
else else
state.score_blue += 3; state.score_blue += 3;
//We replace this tile with an empty one (0 in the bitboard) //We replace this tile with an empty one (0 in the bitboard)
state.three_fish = state.three_fish & ~(((uint64_t) 1) << position); state.three_fish = state.three_fish & ~(((uint64_t) 1) << PENGUIN_POS(*peng));
} }
//Move the current penguin // MOVE THE PENGUIN
move_penguin(p); move_penguin(peng, rel_move);
} }
// 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 = create_obstacles_bitboard();
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_red = 0;
state.nb_moves_blue = 0; state.nb_moves_blue = 0;
if (state.current_player_red) //Red just played if (state.current_player_red) //Red just played
{ {
if(state.canPlay_blue) if(state.canPlay_blue) //If blue couldn't play last turn there is no way he could play this new turn
{ {
state.nb_moves_blue += update_moves(&state.p1_blue, obstacles); for(int i = 0; i < 4; i++)
state.nb_moves_blue += update_moves(&state.p2_blue, obstacles); state.nb_moves_blue += update_penguin_moves(&state.peng_blue[i], 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) if (state.nb_moves_blue == 0)
{ {
state.canPlay_blue = false; state.canPlay_blue = false;
...@@ -405,19 +335,16 @@ namespace game ...@@ -405,19 +335,16 @@ namespace game
} }
else else
{ {
state.nb_moves_blue = 1; state.nb_moves_blue = 1; //We create an artificial move so that the mcts works
} }
state.current_player_red = false; state.current_player_red = false;
} }
else //Blue just played else //Blue just played
{ {
if(state.canPlay_red) if(state.canPlay_red)
{ {
state.nb_moves_red += update_moves(&state.p1_red, obstacles); for(int i = 0; i < 4; i++)
state.nb_moves_red += update_moves(&state.p2_red, obstacles); state.nb_moves_red += update_penguin_moves(&state.peng_red[i], 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) if (state.nb_moves_red == 0)
{ {
state.canPlay_red = false; state.canPlay_red = false;
...@@ -428,7 +355,6 @@ namespace game ...@@ -428,7 +355,6 @@ namespace game
{ {
state.nb_moves_red = 1; state.nb_moves_red = 1;
} }
state.current_player_red = true; state.current_player_red = true;
} }
} }
...@@ -460,14 +386,11 @@ namespace game ...@@ -460,14 +386,11 @@ namespace game
json_state["bitboards"]["twofish"] = state.two_fish; json_state["bitboards"]["twofish"] = state.two_fish;
json_state["bitboards"]["threefish"] = state.three_fish; json_state["bitboards"]["threefish"] = state.three_fish;
json_state["penguins"]["red"][0] = state.p1_red; for(int i = 0; i < 4; i++)
json_state["penguins"]["red"][1] = state.p2_red; {
json_state["penguins"]["red"][2] = state.p3_red; json_state["penguins"]["red"][i] = state.peng_red[i];
json_state["penguins"]["red"][3] = state.p4_red; json_state["penguins"]["blue"][i] = state.peng_blue[i];
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"]["red"] = state.score_red;
json_state["score"]["blue"] = state.score_blue; json_state["score"]["blue"] = state.score_blue;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include "game.hpp" #include "game.hpp"
#include "json.hpp" #include "json.hpp"
using json = nlohmann::json; using json = nlohmann::json;
#include <random> #include <random>
#include <array> #include <array>
#include <iostream> #include <iostream>
#include <memory> #include <memory>
...@@ -13,32 +13,36 @@ namespace game ...@@ -13,32 +13,36 @@ namespace game
{ {
struct penguin_state struct penguin_state
{ {
uint64_t one_fish = 1152921504606846975; //Position of one-fish tiles (bitboard) uint64_t one_fish = 1152921504606846975; //Position of one-fish tiles (bitboard)
uint64_t two_fish = 0; //Position of two-fish tiles (bitboard) uint64_t two_fish = 0; //Position of two-fish tiles (bitboard)
uint64_t three_fish = 0; //Position of three-fish tiles (bitboard) uint64_t three_fish = 0; //Position of three-fish tiles (bitboard)
//Penguins //Penguins
uint32_t p1_red = 0; uint32_t peng_red[4] = {0, 1, 6, 7};
uint32_t p2_red = 1; uint32_t peng_blue[4] = {59, 58, 53, 54};
uint32_t p3_red = 6;
uint32_t p4_red = 7;
uint32_t p1_blue = 59;
uint32_t p2_blue = 58;
uint32_t p3_blue = 53;
uint32_t p4_blue = 54;
int score_red = 0; int score_red = 0;
int score_blue = 0; int score_blue = 0;
bool current_player_red = true; //True if red must play now. Red always starts bool current_player_red = true; //True if red must play now. Red always starts
int nb_moves_red = 0; //Number of moves the red player can play int nb_moves_red = 0; //Number of moves the red player can play
int nb_moves_blue = 0; int nb_moves_blue = 0;
bool canPlay_red = true; bool canPlay_red = true;
bool canPlay_blue = true; bool canPlay_blue = true;
}; };
// Useful macros to get values out of penguins
#define PENGUIN_POS(penguin) ((penguin) & 63)
#define PENGUIN_TOT_MOVES(penguin) (((penguin) >> 6) & 63)
#define PENGUIN_MOVES_A(penguin) (((penguin) >> 12) & 7)
#define PENGUIN_MOVES_B(penguin) (((penguin) >> 15) & 7)
#define PENGUIN_MOVES_C(penguin) (((penguin) >> 18) & 7)
#define PENGUIN_MOVES_D(penguin) (((penguin) >> 21) & 7)
#define PENGUIN_MOVES_E(penguin) (((penguin) >> 24) & 7)
#define PENGUIN_MOVES_F(penguin) (((penguin) >> 27) & 7)
class penguin : public game<penguin_state> class penguin : public game<penguin_state>
{ {
public: public:
...@@ -65,16 +69,16 @@ namespace game ...@@ -65,16 +69,16 @@ namespace game
std::shared_ptr<game<penguin_state>> do_copy() const; std::shared_ptr<game<penguin_state>> do_copy() const;
std::uint64_t hash(std::uint16_t m) const; std::uint64_t hash(std::uint16_t m) const;
std::uint64_t hash() const; std::uint64_t hash() const;
private: private:
penguin_state state; penguin_state state;
uint32_t* penguin_that_moves(uint16_t move_number); void move_penguin(uint32_t* p, uint16_t rel_move);
void move_penguin(uint32_t* p); uint64_t create_obstacles_bitboard();
int update_moves(uint32_t* p, uint64_t obstacles); int update_penguin_moves(uint32_t* p, uint64_t obstacles);
const uint8_t RED = 0; const uint8_t RED = 0;
const uint8_t BLUE = 1; const uint8_t BLUE = 1;
}; };
std::ostream& operator<<(std::ostream& os, const penguin& pen); std::ostream& operator<<(std::ostream& os, const penguin& pen);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment