Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesdfrost committed Sep 24, 2019
1 parent 89b65ac commit 04b249b
Show file tree
Hide file tree
Showing 3 changed files with 1,574 additions and 1,814 deletions.
68 changes: 64 additions & 4 deletions open_spiel/games/backgammon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,14 @@ std::string PositionToString(int pos) {
switch (pos) {
case kBarPos:
return "Bar";
case 25:
return "Bar";
case kScorePos:
return "Score";
case -1:
return "Pass";
case -2:
return "Off";
default:
return absl::StrCat(pos);
}
Expand All @@ -114,10 +118,66 @@ std::string BackgammonState::ActionToString(Player player,
kChanceOutcomeValues[move_id][1], ")");
} else {
std::vector<CheckerMove> cmoves = SpielMoveToCheckerMoves(player, move_id);
return absl::StrCat(move_id, " (", PositionToString(cmoves[0].pos), "-",
cmoves[0].num, cmoves[0].hit ? "*" : "", " ",
PositionToString(cmoves[1].pos), "-", cmoves[1].num,
cmoves[1].hit ? "*" : "", ")");

int cmove0_start;
int cmove1_start;
if (player == kOPlayerId)
{
cmove0_start = (cmoves[0].pos == kBarPos ? 25 : cmoves[0].pos + 1);
cmove1_start = (cmoves[1].pos == kBarPos ? 25 : cmoves[1].pos + 1);
}
else //swap the board numbering round for Player X so player is moving from 24->0
{
cmove0_start = (cmoves[0].pos == kBarPos ? 25 : 24- cmoves[0].pos);
cmove1_start = (cmoves[1].pos == kBarPos ? 25 : 24 - cmoves[1].pos);
}
int cmove0_end= cmoves[0].num;
if (cmove0_end != kPassPos) //Not a pass, so work out where the piece finished
{
cmove0_end = cmove0_start - cmoves[0].num;
if (cmove0_end <= 0) cmove0_end = -2; //Off
else if (board_[Opponent(player)][player == kOPlayerId ? (cmove0_end-1) : (24- cmove0_end)] == 1) cmoves[0].hit = true; //Check to see if move is a hit
}
int cmove1_end = cmoves[1].num;
if (cmove1_end != kPassPos) //Not a pass, so work out where the piece finished
{
cmove1_end = cmove1_start - cmoves[1].num;
if (cmove1_end <= 0) cmove1_end = -2; //Off
else if (board_[Opponent(player)][player == kOPlayerId ? (cmove1_end - 1) : (24 - cmove1_end)] == 1) cmoves[1].hit = true; //Check to see if move is a hit
}
bool double_hit = (cmoves[1].hit && cmoves[0].hit && cmove1_end == cmove0_end); // check for 2 pieces hitting on the same point.
std::string returnVal = "";
if (cmove0_start == cmove1_start && cmove0_end == cmove1_end) // same move, show as (2).
{
if (cmoves[1].num == kPassPos) // Player can't move at all!
returnVal = "Pass";
else
returnVal = absl::StrCat(move_id, " - ", PositionToString(cmove0_start), "/",
PositionToString(cmove0_end), cmoves[0].hit ? "*" : "", "(2)");
}
else if ((cmove0_start < cmove1_start || (cmove0_start == cmove1_start && cmove0_end < cmove1_end) || cmoves[0].num == kPassPos) && cmoves[1].num != kPassPos) // tradition to start with higher numbers first, so swap moves round if this not the case. If there is a pass move, put it last.
{
if (cmove1_end == cmove0_start) // Check to see if the same piece is moving for both moves, as this changes the format of the output.
returnVal = absl::StrCat(move_id, " - ", PositionToString(cmove1_start), "/",
PositionToString(cmove1_end), cmoves[1].hit ? "*" : "", "/", PositionToString(cmove0_end),
cmoves[0].hit ? "*" : "");
else
returnVal = absl::StrCat(move_id, " - ", PositionToString(cmove1_start), "/", PositionToString(cmove1_end),
cmoves[1].hit ? "*" : "", " ", (cmoves[0].num != kPassPos) ? PositionToString(cmove0_start) : "", (cmoves[0].num != kPassPos) ? "/" : "",
PositionToString(cmove0_end), (cmoves[0].hit && !double_hit) ? "*" : "");
}
else
{
if (cmove0_end == cmove1_start) // Check to see if the same piece is moving for both moves, as this changes the format of the output.
returnVal = absl::StrCat(move_id, " - ", PositionToString(cmove0_start), "/",
PositionToString(cmove0_end), cmoves[0].hit ? "*" : "", "/", PositionToString(cmove1_end),
cmoves[1].hit ? "*" : "");
else
returnVal = absl::StrCat(move_id, " - ", PositionToString(cmove0_start), "/", PositionToString(cmove0_end),
cmoves[0].hit ? "*" : "", " ", (cmoves[1].num != kPassPos) ? PositionToString(cmove1_start) : "", (cmoves[1].num != kPassPos) ? "/" : "",
PositionToString(cmove1_end), (cmoves[1].hit && !double_hit) ? "*" : "");
}
return returnVal;
}
}

Expand Down
191 changes: 191 additions & 0 deletions open_spiel/games/backgammon_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,196 @@ void DoublesBearOffOutsideHome() {
action = bstate->CheckerMovesToSpielMove({{20, 4, false}, {20, 4, false}});
SPIEL_CHECK_TRUE(ActionsContains(legal_actions, action));
}
void HumanReadableNotation() {
std::unique_ptr<Game> game = LoadGame("backgammon");
std::unique_ptr<State> state = game->NewInitialState();
BackgammonState* bstate = static_cast<BackgammonState*>(state.get());


// void SetState(int cur_player, bool double_turn, const std::vector<int> & dice,
// const std::vector<int> & bar, const std::vector<int> & scores,
// const std::vector<std::vector<int>> & board);


//Check double repeated move and moving on from Bar displayed correctly
bstate->SetState(
kXPlayerId, false, { 1, 1 }, { 13, 5 }, { 0, 0 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();

std::vector<Action> legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
std::string notation = bstate->ActionToString(kXPlayerId, legal_actions[0]) ;

std::cout << notation << std::endl;

SPIEL_CHECK_TRUE(notation.find("Bar/24(2)") != std::string::npos);

//Check hits displayed correctly
bstate->SetState(
kXPlayerId, false, { 2, 1 }, { 13, 5 }, { 0, 0 },
{ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{1, 1, 1, 1, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();

legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);

std::cout << notation << std::endl;

SPIEL_CHECK_TRUE(notation.find("Bar/24* Bar/23*") != std::string::npos);


//Check moving off displayed correctly
bstate->SetState(
kXPlayerId, false, { 2, 1 }, { 0, 0 }, { 13, 5 },
{ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();

legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);

std::cout << notation << std::endl;

SPIEL_CHECK_TRUE(notation.find("2/Off 1/Off") != std::string::npos);

//Check die order doesnt impact narrative
bstate->SetState(
kXPlayerId, false, { 1, 2 }, { 0, 0 }, { 13, 5 },
{ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{0, 0, 0, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("2/Off 1/Off") != std::string::npos);

//Check double move
bstate->SetState(
kXPlayerId, false, { 6,5 }, { 0, 0 }, { 13, 5 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/18/13") != std::string::npos);

//Check double move with hit
bstate->SetState(
kXPlayerId, false, { 6,5 }, { 0, 0 }, { 13, 4 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/18*/13") != std::string::npos);

//Check double move with double hit
bstate->SetState(
kXPlayerId, false, { 6,5 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/18*/13*") != std::string::npos);

//Check ordinary move!
bstate->SetState(
kXPlayerId, false, { 6,5 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/19 24/18") != std::string::npos);

//Check ordinary move with die reversed
bstate->SetState(
kXPlayerId, false, { 5,6 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/19 24/18") != std::string::npos);

//Check ordinary move with 1st hit
bstate->SetState(
kXPlayerId, false, { 6,5 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 3, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/19* 24/18") != std::string::npos);

//Check ordinary move with 2nd hit
bstate->SetState(
kXPlayerId, false, { 5,6 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 3, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/19 24/18*") != std::string::npos);

//Check ordinary move with double hit
bstate->SetState(
kXPlayerId, false, { 5,6 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/19* 24/18*") != std::string::npos);

//Check double pass
bstate->SetState(
kXPlayerId, false, { 5,3 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("Pass") != std::string::npos);

//Check single pass
bstate->SetState(
kXPlayerId, false, { 5,6 }, { 0, 0 }, { 13, 3 },
{ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} });
std::cout << bstate->ToString();
legal_actions = bstate->LegalActions();
std::cout << "Legal actions:" << std::endl;
notation = bstate->ActionToString(kXPlayerId, legal_actions[0]);
std::cout << notation << std::endl;
SPIEL_CHECK_TRUE(notation.find("24/18 Pass") != std::string::npos);

}

} // namespace
} // namespace backgammon
Expand All @@ -346,4 +536,5 @@ int main(int argc, char** argv) {
open_spiel::backgammon::BearOffOutsideHome();
open_spiel::backgammon::DoublesBearOffOutsideHome();
open_spiel::backgammon::BasicBackgammonTestsVaryScoring();
open_spiel::backgammon::HumanReadableNotation();
}
Loading

0 comments on commit 04b249b

Please sign in to comment.