-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
195: Add `recreate_game` r=charleskawczynski a=charleskawczynski `recreate_game` creates an exact copy of a given game, and then re-samples unobserved cards (from a given player's perspective). Co-authored-by: Charles Kawczynski <kawczynski.charles@gmail.com>
- Loading branch information
Showing
9 changed files
with
149 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
|
||
function resample_unobserved_table_cards!(table::Table, round::PreFlop) | ||
for c in table.cards | ||
PlayingCards.restore!(table.deck, c) | ||
end | ||
table.cards = ntuple(i->SB.sample!(table.deck), 5) | ||
return nothing | ||
end | ||
function resample_unobserved_table_cards!(table::Table, round::Flop) | ||
@inbounds PlayingCards.restore!(table.deck, table.cards[4]) | ||
@inbounds PlayingCards.restore!(table.deck, table.cards[5]) | ||
@inbounds table.cards = ( | ||
table.cards[1:3]..., | ||
SB.sample!(table.deck), | ||
SB.sample!(table.deck), | ||
) | ||
return nothing | ||
end | ||
function resample_unobserved_table_cards!(table::Table, round::Turn) | ||
@inbounds PlayingCards.restore!(table.deck, table.cards[5]) | ||
@inbounds table.cards = ( | ||
table.cards[1:4]..., | ||
SB.sample!(table.deck), | ||
) | ||
return nothing | ||
end | ||
resample_unobserved_table_cards!(table::Table, round::River) = nothing | ||
|
||
function resample_player_cards!(table::Table, player::Player) | ||
@assert player.cards ≠ (nothing, nothing) | ||
for c in player.cards | ||
PlayingCards.restore!(table.deck, c) | ||
end | ||
player.cards = (SB.sample!(table.deck), SB.sample!(table.deck)) | ||
return nothing | ||
end | ||
function resample_cards!(game::Game, player::Player) | ||
table = game.table | ||
for opponent in players_at_table(table) | ||
seat_number(opponent) == seat_number(player) && continue | ||
resample_player_cards!(table, opponent) | ||
end | ||
resample_unobserved_table_cards!(table, table.round) | ||
end | ||
|
||
""" | ||
recreate_game(game, player) | ||
Creates an exact (deep)copy of the input game, | ||
and then re-samples the _unobserved_ cards (i.e., | ||
the opponent cards and unobserved table cards). | ||
This is useful for repeatedly sampling a specific | ||
scenario so that we can compute the expected value | ||
of a particular action. | ||
TODO: we could make a mutating, in-place version of | ||
this to reduce allocations. | ||
""" | ||
function recreate_game(game, player) | ||
rgame = deepcopy(game) | ||
resample_cards!(rgame, player) | ||
return rgame | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Test | ||
using PlayingCards | ||
using TexasHoldem | ||
import TexasHoldem | ||
const TH = TexasHoldem | ||
import Random | ||
Random.seed!(1234) | ||
|
||
include("tester_bots.jl") | ||
|
||
sort_cards(cards) = | ||
sort(sort(collect(cards); by=x->PlayingCards.rank(x));by=x->PlayingCards.suit(x).i) | ||
|
||
@testset "Recreate game" begin | ||
players = TH.Players(ntuple(i->Player(BotCheckCall(), i), 3)) | ||
game = Game(players) | ||
TH.deal!(game.table, TH.blinds(game.table)) | ||
player = players[1] | ||
rgame = TH.recreate_game(game, player) | ||
|
||
# deep copy, should be pointing to separate memory | ||
@test !(player === rgame.table.players[1]) | ||
|
||
# For a recreated game: | ||
# - player[1]'s cards should be the same for every sample | ||
# - Opponents cards should be different upon different sampling | ||
# - visible table cards should be the same | ||
# - unobserved table cards should be different | ||
opponent_cards = players[2].cards | ||
n_player_cards_variation = 0 | ||
n_unobserved_opponent_cards_variation = 0 | ||
n_observed_table_variation = 0 | ||
n_unobserved_table_variation = 0 | ||
n_samples = 10_000 | ||
for i in 1:n_samples | ||
rgame = TH.recreate_game(game, player) | ||
if !all(sort_cards(rgame.table.players[1].cards) .== sort_cards(player.cards)) | ||
n_player_cards_variation+=1 | ||
end | ||
if !all(sort_cards(rgame.table.players[2].cards) .== sort_cards(opponent_cards)) | ||
n_unobserved_opponent_cards_variation+=1 | ||
end | ||
if !all(sort_cards(TH.observed_cards(rgame.table)) .== sort_cards(TH.observed_cards(game.table))) | ||
n_observed_table_variation+=1 | ||
end | ||
if !all(sort_cards(TH.unobserved_cards(rgame.table)) .== sort_cards(TH.unobserved_cards(game.table))) | ||
n_unobserved_table_variation+=1 | ||
end | ||
end | ||
@test n_player_cards_variation == 0 | ||
@test n_unobserved_opponent_cards_variation ≠ 0 | ||
@test n_unobserved_opponent_cards_variation > n_samples/25 # we shouldn't be getting the same hand more than 25% of the time | ||
@test n_unobserved_opponent_cards_variation ≠ n_samples # sometimes (but very rarely) we get the same hand! | ||
@test n_observed_table_variation == 0 | ||
|
||
@test n_unobserved_table_variation ≠ 0 | ||
@test n_unobserved_table_variation > n_samples/25 # we shouldn't be getting the same table cards more than 25% of the time | ||
# @test n_unobserved_table_variation ≠ n_samples # we need n_samples ~ 3*10^9 to test this, and that would take ~10 hours on my local machine :( | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
505a6f3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register
505a6f3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/89154
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via: