Skip to content

Commit

Permalink
Merge #33
Browse files Browse the repository at this point in the history
33: Upgrade PlayingCards r=charleskawczynski a=charleskawczynski

This PR upgrades to the new PlayingCards.jl, which now no longer has suit type parameters. This means that we should be able to write more type-stable methods, and fewer methods may be compiled for the `evaluate5`.

Co-authored-by: Charles Kawczynski <kawczynski.charles@gmail.com>
  • Loading branch information
bors[bot] and charleskawczynski authored Jun 29, 2021
2 parents 311d658 + 99ca56f commit a3af217
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 22 deletions.
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "PokerHandEvaluator"
uuid = "18ed25b1-892a-4a3b-b8fc-1036dc9a6a89"
authors = ["Charles Kawczynski <kawczynski.charles@gmail.com>"]
version = "0.2.1"
version = "0.2.2"

[deps]
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
Expand All @@ -10,5 +10,5 @@ PlayingCards = "ecfe714a-bcc2-4d11-ad00-25525ff8f984"

[compat]
Combinatorics = "1.0"
PlayingCards = "0.2.0"
PlayingCards = "0.3.0"
julia = "1.3"
14 changes: 8 additions & 6 deletions docs/src/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ prime(card::Card) = primes[rank(card)]

The product of prime numbers are (1) unique and (2) order-agnostic (due to the multiplication commutative property). This mapped relationship can be implemented in various ways, for example via lookup tables, binary search etc.. PokerHandEvaluator.jl simply loops over the combinations of hands (using [Combinatorics.jl](https://github.com/JuliaMath/Combinatorics.jl)) and `eval`s the methods (by dispatching on types `::Val{prod(primes.(cards))}`) to return the rank directly.

Finally, PokerHandEvaluator.jl specializes on [PlayingCards.jl](https://github.com/charleskawczynski/PlayingCards.jl)'s `suit` type parameter to disambiguate flush vs off-suited hands:
Finally, PokerHandEvaluator.jl checks to see the card's `suit` to disambiguate flush vs off-suited hands:

```julia
evaluate5(t::Tuple{Card{S1},Card{S2},Card{S3},Card{S4},Card{S5}}) where {S1,S2,S3,S4,S5} =
evaluate5_offsuit(Val(prod(prime.(t))))

evaluate5(t::Tuple{Card{S},Card{S},Card{S},Card{S},Card{S}}) where {S} =
evaluate5_flush(Val(prod(prime.(t))))
function evaluate5(t::NTuple{N,Card}) where {N}
if suit(t[1]) == suit(t[2]) == suit(t[3]) == suit(t[4]) == suit(t[5])
evaluate5_flush(Val(prod(prime.(t))))
else
evaluate5_offsuit(Val(prod(prime.(t))))
end
end
```

This approach has performance / compile-time implications. See the [performance](./perf.md) documentation for more information.
18 changes: 9 additions & 9 deletions src/HandCombinations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export prime,
##### Helpers

const primes = (41,2,3,5,7,11,13,17,19,23,29,31,37)
prime(i::UInt8) = primes[i]
prime(i::Int) = prime(UInt8(i))
prime(i::Int8) = primes[i]
prime(i::Int) = prime(Int8(i))
prime(card::Card) = primes[rank(card)]

function sort_combinations(comb, sort_by_first_val = false)
Expand Down Expand Up @@ -65,8 +65,8 @@ end
##### Rows 167:322 (full house)

function full_house_ranks()
three_quarter_deck = filter(x->suit(x) isa Club || suit(x) isa Heart || suit(x) isa Spade, full_deck())
half_deck = filter(x->suit(x) isa Club || suit(x) isa Heart, full_deck())
three_quarter_deck = filter(x->suit(x) == || suit(x) == || suit(x) ==, full_deck())
half_deck = filter(x->suit(x) == || suit(x) ==, full_deck())
trip_combos = collect(combinations(three_quarter_deck, 3))
pair_combos = collect(combinations(half_deck, 2))
trip_combos = sort.(trip_combos; by = x->high_value(x), rev=true)
Expand Down Expand Up @@ -98,7 +98,7 @@ function is_straight(cards)
end

function flush_ranks()
club_combos = combinations(filter(x->suit(x) isa Club, full_deck()), 5)
club_combos = combinations(filter(x->suit(x) ==, full_deck()), 5)
sorted_club_combos = sort.(club_combos; by = x->high_value(x), rev=true)
sorted_club_combos = sort_combinations(sorted_club_combos)
card_ranks = [begin
Expand All @@ -109,7 +109,7 @@ end
##### Rows 1610:2467 (trips)

function trip_ranks()
club_deck = filter(x->suit(x) isa Club, full_deck())
club_deck = filter(x->suit(x) ==, full_deck())
club_kicker_combos = collect(combinations(club_deck, 2))
sorted_club_kicker_combos = sort.(club_kicker_combos; by = x->high_value(x), rev=true)
sorted_club_kicker_combos = sort_combinations(sorted_club_kicker_combos)
Expand All @@ -123,7 +123,7 @@ end
##### Rows 2468:3325 (two pair)

function two_pair_ranks()
half_deck = filter(x->suit(x) isa Club || suit(x) isa Heart, full_deck())
half_deck = filter(x->suit(x) == || suit(x) ==, full_deck())
combos = collect(combinations(half_deck, 4))
combos = sort.(combos; by = x->high_value(x), rev=true)
two_pair_combos = filter(x->high_value(x[1])==high_value(x[2]) && high_value(x[3])==high_value(x[4]), combos)
Expand All @@ -138,7 +138,7 @@ end
##### Rows 3326:6185 (pair)

function pair_ranks()
three_quarters_deck = filter(x->suit(x) isa Club, full_deck())
three_quarters_deck = filter(x->suit(x) ==, full_deck())
combos = collect(combinations(three_quarters_deck, 3))
combos = sort.(combos; by = x->high_value(x), rev=true)
combos = sort_combinations(combos)
Expand All @@ -152,7 +152,7 @@ end
##### Rows 6186:7462 (high card)

function high_card_ranks()
club_deck = filter(x->suit(x) isa Club, full_deck())
club_deck = filter(x->suit(x) ==, full_deck())
combos = collect(combinations(club_deck, 5))
combos = sort.(combos; by = x->high_value(x), rev=true)
combos = sort_combinations(combos)
Expand Down
13 changes: 8 additions & 5 deletions src/evaluate5.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ evaluate5(cards::Card...)::Int = evaluate5(cards)
# for which a method, `evaluate_offsuit` and
# `evaluate_flush` are defined. First, we dispatch
# based on flush/non-flush:
evaluate5(t::Tuple{Card{S1},Card{S2},Card{S3},Card{S4},Card{S5}}) where {S1,S2,S3,S4,S5} =
evaluate5_offsuit(Val(prod(prime.(t))))

evaluate5(t::Tuple{Card{S},Card{S},Card{S},Card{S},Card{S}}) where {S} =
evaluate5_flush(Val(prod(prime.(t))))
function evaluate5(t::NTuple{N,Card}) where {N}
@assert N == 5
if suit(t[1]) == suit(t[2]) == suit(t[3]) == suit(t[4]) == suit(t[5])
evaluate5_flush(Val(prod(prime.(t))))
else
evaluate5_offsuit(Val(prod(prime.(t))))
end
end

for (i,card_ranks) in enumerate(straight_ranks())
p = prod(prime.(card_ranks))
Expand Down

2 comments on commit a3af217

@charleskawczynski
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

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/39888

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:

git tag -a v0.2.2 -m "<description of version>" a3af217cdc67ad24cf5803859a149f8beb9f1ed7
git push origin v0.2.2

Please sign in to comment.