Skip to content

Commit

Permalink
Merge pull request #1242 from i-Madsen:master
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 656477404
Change-Id: I35e27bdfe46d6b4a4b69267aa1f1f3504871169b
  • Loading branch information
lanctot committed Jul 30, 2024
2 parents 2eed8b6 + 49a6d4b commit 5063bb3
Show file tree
Hide file tree
Showing 9 changed files with 895 additions and 743 deletions.
38 changes: 23 additions & 15 deletions open_spiel/games/spades/spades.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,6 @@
#include "open_spiel/spiel_globals.h"
#include "open_spiel/spiel_utils.h"

// Our preferred version of the double_dummy_solver defines a DDS_EXTERNAL
// macro to add a prefix to the exported symbols to avoid name clashes.
// In order to compile with versions of the double_dummy_solver which do not
// do this, we define DDS_EXTERNAL as an identity if it isn't already defined.
#ifndef DDS_EXTERNAL
#define DDS_EXTERNAL(x) x
#endif

namespace open_spiel {
namespace spades {
namespace {
Expand Down Expand Up @@ -69,10 +61,9 @@ const GameType kGameType{
{"mercy_threshold", GameParameter(-350)},
// Amount of points needed to win the game
{"win_threshold", GameParameter(500)},
// Partnership's current scores
// (can infer bags from last digit)
{"score_partnership_0", GameParameter(0)},
{"score_partnership_1", GameParameter(0)},
// The amount to add to reward return for winning
// (Will subtract for losing by mercy rule)
{"win_or_loss_bonus", GameParameter(200)},
// Number of played tricks in observation tensor
{"num_tricks", GameParameter(2)},
}};
Expand Down Expand Up @@ -116,13 +107,12 @@ SpadesGame::SpadesGame(const GameParameters& params)

SpadesState::SpadesState(std::shared_ptr<const Game> game, bool use_mercy_rule,
int mercy_threshold, int win_threshold,
int score_partnership_0, int score_partnership_1,
int num_tricks)
int win_or_loss_bonus, int num_tricks)
: State(game),
use_mercy_rule_(use_mercy_rule),
mercy_threshold_(mercy_threshold),
win_threshold_(win_threshold),
current_scores_{score_partnership_0, score_partnership_1},
win_or_loss_bonus_(win_or_loss_bonus),
num_tricks_(num_tricks) {
possible_contracts_.fill(true);
}
Expand Down Expand Up @@ -559,6 +549,24 @@ Player SpadesState::CurrentPlayer() const {
void SpadesState::ScoreUp() {
std::array<int, kNumPartnerships> scores =
Score(contracts_, num_player_tricks_, current_scores_);
// Check for if bonus reward should be applied for winning (or losing by mercy
// rule)
for (int pship = 0; pship < kNumPartnerships; ++pship) {
// Update overall scores
current_scores_[pship] += scores[pship];
// Check for bonus/penalty to returns and if overall game is over
if (scores[pship] >= win_threshold_ && scores[pship] > scores[pship ^ 1]) {
scores[pship] += win_or_loss_bonus_; // Add bonus reward for winning
is_game_over_ = true;
} else if (mercy_threshold_ && scores[pship] <= mercy_threshold_ &&
scores[pship] < scores[pship ^ 1]) {
scores[pship] -= win_or_loss_bonus_; // Subtract penalty reward for
// losing by mercy rule
is_game_over_ = true;
}
}
// Apply the partnership scores (with bonus/penalty applied) to corresponding
// players' returns
for (int pl = 0; pl < kNumPlayers; ++pl) {
returns_[pl] = scores[Partnership(pl)];
}
Expand Down
43 changes: 31 additions & 12 deletions open_spiel/games/spades/spades.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ class Trick {
class SpadesState : public State {
public:
SpadesState(std::shared_ptr<const Game> game, bool use_mercy_rule,
int mercy_threshold, int win_threshold, int score_partnership_0,
int score_partnership_1, int num_tricks);
int mercy_threshold, int win_threshold, int win_or_loss_bonus,
int num_tricks);
Player CurrentPlayer() const override;
std::string ActionToString(Player player, Action action) const override;
std::string ToString() const override;
Expand Down Expand Up @@ -133,6 +133,25 @@ class SpadesState : public State {
// Current phase.
int CurrentPhase() const { return static_cast<int>(phase_); }

// Current overall partnership scores
std::array<int, kNumPartnerships> GetCurrentScores() const {
return current_scores_;
}

// Set partnership scores
void SetCurrentScores(const std::array<int, kNumPartnerships>& new_scores) {
current_scores_ = new_scores;
}

// Indicates if overall game is over (did a partnership meet win/lose
// condition)
bool IsGameOver() const { return is_game_over_; }

// Manually set the current player (used to specify starting player)
void SetCurrentPlayer(const int current_player) {
current_player_ = current_player;
}

protected:
void DoApplyAction(Action action) override;

Expand All @@ -146,7 +165,6 @@ class SpadesState : public State {
void ApplyBiddingAction(int bid);
void ApplyPlayAction(int card);

void ComputeScoreByContract() const;
void ScoreUp();
Trick& CurrentTrick() { return tricks_[num_cards_played_ / kNumPlayers]; }
const Trick& CurrentTrick() const {
Expand All @@ -161,9 +179,11 @@ class SpadesState : public State {
const bool use_mercy_rule_;
const int mercy_threshold_;
const int win_threshold_;
const std::array<int, kNumPartnerships> current_scores_;
const int win_or_loss_bonus_;
const int num_tricks_;

std::array<int, kNumPartnerships> current_scores_ = {0, 0};
bool is_game_over_ = false;
std::array<int, kNumPlayers> num_player_tricks_ = {0, 0, 0, 0};
int num_cards_played_ = 0;
Player current_player_ = 0; // During the play phase, the hand to play.
Expand All @@ -185,13 +205,13 @@ class SpadesGame : public Game {
}
int MaxChanceOutcomes() const override { return kNumCards; }
std::unique_ptr<State> NewInitialState() const override {
return std::unique_ptr<State>(new SpadesState(
shared_from_this(), UseMercyRule(), MercyThreshold(), WinThreshold(),
PartnershipScore(0), PartnershipScore(1), NumTricks()));
return std::unique_ptr<State>(
new SpadesState(shared_from_this(), UseMercyRule(), MercyThreshold(),
WinThreshold(), WinOrLossBonus(), NumTricks()));
}
int NumPlayers() const override { return kNumPlayers; }
double MinUtility() const override { return -kMaxScore; }
double MaxUtility() const override { return kMaxScore; }
double MinUtility() const override { return -(kMaxScore + WinOrLossBonus()); }
double MaxUtility() const override { return kMaxScore + WinOrLossBonus(); }

static int GetPlayTensorSize(int num_tricks) {
return kNumBids * kNumPlayers // What each player's contract is
Expand Down Expand Up @@ -232,9 +252,8 @@ class SpadesGame : public Game {

int WinThreshold() const { return ParameterValue<int>("win_threshold", 500); }

int PartnershipScore(int partnership) const {
return partnership ? ParameterValue<int>("score_partnership_1", 0)
: ParameterValue<int>("score_partnership_0", 0);
int WinOrLossBonus() const {
return ParameterValue<int>("win_or_loss_bonus", 200);
}

int NumTricks() const { return ParameterValue<int>("num_tricks", 2); }
Expand Down
5 changes: 3 additions & 2 deletions open_spiel/games/spades/spades_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ void ScoringTests() {
void BasicGameTests() {
testing::LoadGameTest("spades");
testing::RandomSimTest(*LoadGame("spades"), 3);
testing::RandomSimTest(
*LoadGame("spades(score_partnership_0=59,score_partnership_1=99)"), 3);
testing::RandomSimTest(*LoadGame("spades(use_mercy_rule=false,win_threshold="
"250,win_or_loss_bonus=1000)"),
3);
}

} // namespace
Expand Down
Loading

0 comments on commit 5063bb3

Please sign in to comment.