
Security News
Astral Launches pyx: A Python-Native Package Registry
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
Please read this entire readme before using the gem, thank you.
The hand_rank gem is a Ruby, with C extension, implementation of the Two Plus Two hand evaluation algorithm for Texam Hold'em hands (or any hands following the same ranking order).
The algorithm uses a large, 130+MB, lookup table and ranks a hand 5-7 card hand by doing 5-7 jumps in hte table and landing on the cell that represents the hand you walked to get there, regardless of the order of the steps.
Each, final, cell contains the Cactus Kev hands equivalence number, a number describing the hand among every possible hand. This number can then be compared to any other hands equivalence number to see who is the winner.
The Plus Two version also reorders the equivalence classes to allow for getting a rank within a category. So you can split the rank into a category and a rank within that category.
For some not so light reading on the subject I suggest you check out the original sources for all the pieces as well as a comparison roundup from, the now defunct, codingthewheel site:
Cactus Kev's original Poker Hand Evaluator describes the ordering of hands in the lookup table and the concept of the hand equivalence classes.
Paul Senzee - "Some Perfect Hash" describes a hashing algorithm to improve on the size of the Cactus Kev lookup table and is the same that is used for the lookup table to the Two Plus Two solution.
The original thread on the Two Plus Two forums where it all came together. It's long and threatens to become a bit flamy at times. But in the end I think it is a great example of what you can accomplich on the internet, with strangers if you are all prepared to act for the greater good.
And finally the poker evaluator roundup from codingthewheel.com unfortunately via the waybackmachine since the original site is no longer live :/ Great roundup, with code, of all the relevant approaches. The code from the roundup is still available on Github so there is that ...
When the gem is finished this is what you will do. Right now you also need to manually extract the
ranks.data.zip
inlib/hand_rank/
toranks.data
in the same folder. This is the lookup table and without it you get nothing :)
Add this line to your application's Gemfile:
gem 'hand_rank'
And then execute:
$ bundle
Or install it yourself as:
$ gem install hand_rank
To create a hand you need the cards absolute values. You somehow have to convert your representation of a hand into an array of integers where each integer represents a card following this encoding:
ABSOLUTE_CARD_VALUE_LOOKUP = {
# spacer, A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A
club: [ nil, 49, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49 ],
diamond: [ nil, 50, 2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50 ],
heart: [ nil, 51, 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51 ],
spade: [ nil, 52, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52 ],
}
This table allows you to lookup and card by suit and value (from 1 to 14,
allowing for both high and low aces). In our implementation the Card
class has
an abs
method and the Hand
class impersonates an array. Since this gem will
actually run map!(&:abs)
on the input before handing it off to the C code our
setup allows us to give it a real Hand
and just leave it to the magic to
transform that into an array of integers.
It will still work fine if you feed it an array of integers though. Arrays
respond to map
and fixnum responds to abs
so it is golden either way.
# A hand of AH KH 9D 4C JS QD 10H
cards_array = [ 51, 47, 30, 9, 40, 42, 35 ]
rank = HandRank.get( cards_array )
# 20490
categories = [
"invalid_hand",
"high_card",
"one_pair",
"two_pairs",
"three_of_a_kind",
"straight",
"flush",
"full_house",
"four_of_a_kind",
"straight_flush"
]
HandRank.category( rank )
# 5
HandRank.rank_in_category( rank )
# 10
HandRank.category_key( rank )
# "straight"
puts HandRank.explain( rank )
# => The hand is a straight
# Rank: 20490 Category: 5 Rank in category: 10
Some simple timing might be in order.
require 'benchmark'
n = 8000000
a = [1,2,3,4,5,6,7]
Benchmark.bm(7) do |x|
x.report('ranking') do
for i in 1..n
HandRank.get(a)
end
end
x.report('"s"+"s"') do
for i in 1..n
"Hello" + "world!"
end
end
end
Running on a 2015 MacBook pro gives these results:
user system total real
ranking 0.900000 0.000000 0.900000 ( 0.907518)
"s"+"s" 1.850000 0.000000 1.850000 ( 1.856820)
So ranking a hand is about twice as fast as a string concatenation. On the test machine it can rank over 8 million hands a second, that is one hand every 8 or so microseconds.
git checkout -b my-new-feature
)git commit -am 'Add some feature'
)git push origin my-new-feature
)FAQs
Unknown package
We found that hand_rank demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Astral unveils pyx, a Python-native package registry in beta, designed to speed installs, enhance security, and integrate deeply with uv.
Security News
The Latio podcast explores how static and runtime reachability help teams prioritize exploitable vulnerabilities and streamline AppSec workflows.
Security News
The latest Opengrep releases add Apex scanning, precision rule tuning, and performance gains for open source static code analysis.