Skip to content

Commit

Permalink
Ensure raises are called, fix edge cases with player options
Browse files Browse the repository at this point in the history
  • Loading branch information
charleskawczynski committed Jun 12, 2021
1 parent 87ba8ba commit 777e656
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 9 deletions.
54 changes: 46 additions & 8 deletions src/game.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,56 @@ function end_of_actions(table::Table, player)
@debug " all_playing_checked(table) = $(all_playing_checked(table))"
@debug " all_all_in_or_checked(table) = $(all_all_in_or_checked(table))"
@debug " all_all_in_except_bank_roll_leader(table) = $(all_all_in_except_bank_roll_leader(table))"
# all_all_in_except_bank_roll_leader does not supersede
# all_playing_all_in, since it always returns false if
# there are multiple players (still playing) with the
# same (max) bank roll:
@debug " all_oppononents_all_in(table, player) = $(all_oppononents_all_in(table, player))"

case_1 = last_to_raise(player)
case_2 = all_playing_checked(table)
case_3 = all_playing_all_in(table)
case_4 = all_all_in_except_bank_roll_leader(table)
case_5 = all_all_in_or_checked(table)
case_6 = !any(action_required.(players))
@debug " cases = $((case_1, case_2, case_3, case_4, case_5, case_6))"
case_7 = all_oppononents_all_in(table, player) && paid_current_raise_amount(table, player)
@debug " cases = $((case_1, case_2, case_3, case_4, case_5, case_6, case_7))"

return any((case_1, case_2, case_3, case_4, case_5, case_6))
return any((case_1, case_2, case_3, case_4, case_5, case_6, case_7))
end

function last_player_to_raise(table::Table)
for player in players_at_table(table)
last_to_raise(player) && return player
end
return nothing
end

function all_raises_were_called(table::Table)
lptr = last_player_to_raise(table)
lptr===nothing && return true

players = players_at_table(table)
ltr = last_to_raise.(players)
@assert count(ltr) == 1
lptr = last_player_to_raise(table)
players_who_called = []
@debug "Checking if all raises were called"
@debug " table.winners.declared = $(table.winners.declared)"
for (i, opponent) in enumerate(circle(table, lptr))
i>length(players) && break
seat_number(opponent) == seat_number(lptr) && continue
not_playing(opponent) && continue
ah = action_history(opponent)
@assert !isempty(ah)
la = last(ah)
push!(players_who_called, (seat_number(opponent), la isa Call || (la isa Raise && all_in(opponent))))
if !(pot_investment(opponent) pot_investment(lptr))
@debug " all_in(lptr) = $(all_in(lptr))"
@debug " pot_investment(lptr) = $(pot_investment(lptr))"
@debug " pot_investment(opponent) = $(pot_investment(opponent))"
if !all_in(opponent)
error("Pot investments of all players must be equal for all non-in players still playing.")
end
end
end
return all(map(pwc->last(pwc), players_who_called))
end

function act_generic!(game::Game, state::AbstractGameState)
Expand All @@ -114,6 +150,7 @@ function act_generic!(game::Game, state::AbstractGameState)
reset_round_bank_rolls!(game, state)

any_actions_required(game) || return
play_out_game(table) && return
for (i, player) in enumerate(circle(table, FirstToAct()))
@debug "Checking to see if it's $(name(player))'s turn to act"
@debug " not_playing(player) = $(not_playing(player))"
Expand All @@ -128,6 +165,7 @@ function act_generic!(game::Game, state::AbstractGameState)
player_option!(game, player)
table.winners.declared && break
end
@assert all_raises_were_called(table)
end

function act!(game::Game, state::AbstractGameState)
Expand All @@ -146,6 +184,7 @@ function play!(game::Game)
@info "------ Playing game!"

table = game.table
set_active_status!(table)
players = players_at_table(table)

initial_brs = deepcopy(bank_roll.(players))
Expand Down Expand Up @@ -215,7 +254,6 @@ end
function reset_game!(game::Game)
table = game.table
players = players_at_table(table)
set_active_status!(game.table)

game.table = Table(;
deck=ordered_deck(),
Expand All @@ -236,7 +274,7 @@ function reset_game!(game::Game)
player.round_contribution = 0
player.active = true
end
set_active_status!(game.table)
set_active_status!(table)
end

"""
Expand Down
27 changes: 26 additions & 1 deletion src/table.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ function bank_roll_leader(table::Table)
return br_leader, multiple_leaders
end

paid_current_raise_amount(table::Table, player::Player) =
round_contribution(player) current_raise_amt(table)

# Can be true in exactly 2 cases:
# 1) Everyone (still playing) is all-in.
# 2) Everyone (still playing), except `player`, is all-in.
Expand All @@ -223,6 +226,7 @@ end
# everyone else does not, so nobody can respond to their raise
# (if they chose to do so). Therefore, we must "play out" the
# entire game with no further actions.
# Note that this method is intended to be used _during_ a round.
function all_all_in_except_bank_roll_leader(table::Table)
br_leader, multiple_leaders = bank_roll_leader(table)
players = players_at_table(table)
Expand All @@ -231,7 +235,28 @@ function all_all_in_except_bank_roll_leader(table::Table)
@assert !multiple_leaders # We have a single bank roll leader

return all(map(players) do player
not_playing(player) || all_in(player) || seat_number(player) == seat_number(br_leader)
cond1 = not_playing(player)
cond2 = all_in(player)
cond3 = seat_number(player) == seat_number(br_leader) && !action_required(br_leader)
any((cond1, cond2, cond3))
end)
end

# Note that this method is only valid before or after a round has ended.
function play_out_game(table::Table)
br_leader, multiple_leaders = bank_roll_leader(table)
players = players_at_table(table)
if multiple_leaders
return all(map(player -> not_playing(player) || all_in(player), players))
end

@assert !multiple_leaders # We have a single bank roll leader

return all(map(players) do player
cond1 = not_playing(player)
cond2 = all_in(player)
cond3 = seat_number(player) == seat_number(br_leader)
any((cond1, cond2, cond3))
end)
end

Expand Down

0 comments on commit 777e656

Please sign in to comment.