Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions bayes/README.md

This file was deleted.

3 changes: 3 additions & 0 deletions bayes/include/bayes.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ ExpectedValue EvPlayerHits(const RuleSet& ruleset, PlayerHand playerHand,
ExpectedValue EvPlayerDoubles(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand);

ExpectedValue EvPlayerSplits(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand);

} // namespace BlackjackEngine::Bayes
28 changes: 23 additions & 5 deletions bayes/src/bayes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ ExpectedValue EvDoubles(const RuleSet& ruleset, const State& state) {
});
}

// EV of splitting: split the hand into two and evaluate both
ExpectedValue EvSplits(const RuleSet& ruleset, const State& state) {
const auto& [first, second] = Split(ruleset, state);
return ExpectedValue(EvBest(ruleset, first).value +
EvBest(ruleset, second).value);
}

// Value of playing a state optimally: a terminal state is simply scored,
// otherwise it is the greatest expected value over every allowed action. This
// drives both the player's choices and the dealer's forced play, since a
Expand All @@ -87,31 +94,42 @@ ExpectedValue EvBest(const RuleSet& ruleset, const State& state) {
if (IsAllowed(state.allowedActions, Action::Double))
best = std::max(best, EvDoubles(ruleset, state));

if (IsAllowed(state.allowedActions, Action::Split))
best = std::max(best, EvSplits(ruleset, state));

return best;
}

ExpectedValue EvPlayerBestAction(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand) {
return EvBest(ruleset,
InitiateState(ruleset, Turn::Player, playerHand, dealerHand));
InitializeState(ruleset, Turn::Player, playerHand, dealerHand));
}

ExpectedValue EvPlayerStands(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand) {
return EvStands(ruleset,
InitiateState(ruleset, Turn::Player, playerHand, dealerHand));
return EvStands(
ruleset, InitializeState(ruleset, Turn::Player, playerHand, dealerHand));
}

ExpectedValue EvPlayerHits(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand) {
return EvHits(ruleset,
InitiateState(ruleset, Turn::Player, playerHand, dealerHand));
InitializeState(ruleset, Turn::Player, playerHand, dealerHand));
}

ExpectedValue EvPlayerDoubles(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand) {
return EvDoubles(
ruleset, InitiateState(ruleset, Turn::Player, playerHand, dealerHand));
ruleset, InitializeState(ruleset, Turn::Player, playerHand, dealerHand));
}

ExpectedValue EvPlayerSplits(const RuleSet& ruleset, PlayerHand playerHand,
DealerHand dealerHand) {
return EvSplits(ruleset,
InitializeState(ruleset, Turn::Player, playerHand, dealerHand,
Action::Hit | Action::Stand | Action::Double |
Action::Split));
}

} // namespace BlackjackEngine::Bayes
2 changes: 1 addition & 1 deletion bayes/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_executable(bayes_tests
bayes_tests.cpp)
bayes_macau_tests.cpp)

target_link_libraries(bayes_tests blackjack_bayes gtest_main)

Expand Down
171 changes: 171 additions & 0 deletions bayes/tests/bayes_macau_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#include <gtest/gtest.h>

#include "bayes.h"

using namespace BlackjackEngine::StateMachine;
using namespace BlackjackEngine::Bayes;

constexpr double Epsilon = 0.000001;

const RuleSet macauRule = {
.hitOnSoft17 = false,
.maxSplittedHands = 4,
.resplitAces = false,
.splitLosesOriginalToDealerBJ = false,
.doubleLosesOriginalToDealerBJ = true,
.doubleOnSplits = true,
};

TEST(EvTests, TestPlayer16Dealer9Hit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(16, false, 2), DealerHand(9));
EXPECT_NEAR(ev.value, -0.509322, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer9Stand) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(16), DealerHand(9));
EXPECT_NEAR(ev.value, -0.543150, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer10Hit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(16), DealerHand(10));
EXPECT_NEAR(ev.value, -0.575224, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer10Stand) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(16), DealerHand(10));
EXPECT_NEAR(ev.value, -0.575782, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer10Best) {
const ExpectedValue ev =
EvPlayerBestAction(macauRule, PlayerHand(16), DealerHand(10));
EXPECT_NEAR(ev.value, -0.575224, Epsilon);
}

TEST(EvTests, TestPlayer13Dealer6Hit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(13), DealerHand(6));
EXPECT_NEAR(ev.value, -0.235626, Epsilon);
}

TEST(EvTests, TestPlayer13Dealer6Stand) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(13), DealerHand(6));
EXPECT_NEAR(ev.value, -0.153699, Epsilon);
}

TEST(EvTests, TestPlayer13Dealer6Best) {
const ExpectedValue ev =
EvPlayerBestAction(macauRule, PlayerHand(13), DealerHand(6));
EXPECT_NEAR(ev.value, -0.153699, Epsilon);
}

TEST(EvTests, TestPlayer10Dealer6Double) {
const ExpectedValue ev =
EvPlayerDoubles(macauRule, PlayerHand(10), DealerHand(6));
EXPECT_NEAR(ev.value, 0.575590, Epsilon);
}

TEST(EvTests, TestPlayer11Dealer7Double) {
const ExpectedValue ev =
EvPlayerDoubles(macauRule, PlayerHand(11), DealerHand(7));
EXPECT_NEAR(ev.value, 0.462889, Epsilon);
}

TEST(EvTests, TestPlayer9DealerAceHit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(9), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.353164, Epsilon);
}

TEST(EvTests, TestPlayer9DealerAceStand) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(9), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.769427, Epsilon);
}

TEST(EvTests, TestPlayer4DealerAceHit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(4), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.482899, Epsilon);
}

TEST(EvTests, TestPlayer4DealerAceStand) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(4), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.769427, Epsilon);
}

TEST(EvTests, TestPlayerSoft16Dealer9Hit) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(16, true), DealerHand(9));
EXPECT_NEAR(ev.value, -0.148644, Epsilon);
}

TEST(EvTests, TestPlayerSoft16Dealer9Stands) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(16, true), DealerHand(9));
EXPECT_NEAR(ev.value, -0.543150, Epsilon);
}

TEST(EvTests, TestPlayerSoft16Dealer9Doubles) {
const ExpectedValue ev =
EvPlayerDoubles(macauRule, PlayerHand(16, true), DealerHand(9));
EXPECT_NEAR(ev.value, -0.456367, Epsilon);
}

TEST(EvTests, TestPlayerSoft19DealerAceHits) {
const ExpectedValue ev =
EvPlayerHits(macauRule, PlayerHand(19, true), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.311668, Epsilon);
}

TEST(EvTests, TestPlayerSoft19DealerAceStands) {
const ExpectedValue ev =
EvPlayerStands(macauRule, PlayerHand(19, true), DealerHand(11, true));
EXPECT_NEAR(ev.value, -0.115483, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer6Split) {
const ExpectedValue ev =
EvPlayerSplits(macauRule, PlayerHand(16), DealerHand(6));
EXPECT_NEAR(ev.value, 0.412349, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer5Split) {
const ExpectedValue ev =
EvPlayerSplits(macauRule, PlayerHand(16), DealerHand(5));
EXPECT_NEAR(ev.value, 0.299967, Epsilon);
}

TEST(EvTests, TestPlayer20Dealer6Split) {
const ExpectedValue ev =
EvPlayerSplits(macauRule, PlayerHand(20), DealerHand(6));
EXPECT_NEAR(ev.value, 0.575590, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer9Split) {
const ExpectedValue ev =
EvPlayerSplits(macauRule, PlayerHand(16), DealerHand(9));
EXPECT_NEAR(ev.value, -0.386573, Epsilon);
}

TEST(EvTests, TestPlayer16Dealer9Best) {
const ExpectedValue ev =
EvPlayerBestAction(macauRule, PlayerHand(16), DealerHand(9));
EXPECT_NEAR(ev.value, -0.386573, Epsilon);
}

/*
* Commented out because it is too slow at the moment.
* We will introduce caches to fix this.
TEST(EvTests, TestPlayerSoft12Dealer9Split) {
const ExpectedValue ev =
EvPlayerSplits(macauRule, PlayerHand(12, true), DealerHand(9));
EXPECT_NEAR(ev.value, 0.642847, Epsilon);
}
*/
Loading
Loading