A Pure R Poker Hand Evaluator
There’s already a lot of great posts out there about poker hand evaluators, so I’ll keep this short. Kenneth J. Shackleton recently released a very slick 5-card and 7-card poker hand evaluator called SpecialK. This evaluator is licensed under GPL 3, and is described in detail in 2 blog posts: part 1 and part 2. Since the provided code is open source, I felt free to hack around with it a bit, and ported the python source to R.
You can download my code from github, and save it to ~/SpecialK/R. Run the following script to initialize the evaluator and test it out. Higher numbers=better hands.
set.seed(42)
rm(list = ls(all = TRUE))
setwd('~/SpecialK/R')
source('Evaluator/Constants.R')
source('Evaluator/FiveEval.R')
source('Evaluator/SevenEval.R')
#Convert human-readable cards to integers
card <- function(x) {
allCards <- paste(
do.call(c,lapply(c('A','K','Q','J','T',9:2),function(x) rep(x,4))),
c('s','h','d','c'), sep='')
which(allCards==x)-1
}
card('As')
card('2d')
#Wrapper for the evaluator
evaluate <- function(hand) {
hand <- do.call(c,lapply(hand,card))
SevenEval$getRankOfSeven(hand[1], hand[2], hand[3], hand[4], hand[5], hand[6], hand[7])
}
evaluate(c('As','Ks','Qs','Js','Ts','8d','7d'))
evaluate(c('As','Ks','Qs','Td','9d','8d','7d'))
evaluate(c('7s','6s','5s','4s','2d','9d','Td'))
#Generate 10,000 random hands
randomHand <- function(...) {
sample(0:51,7)
}
n <- 10000
hands <- lapply(1:n,randomHand)
#Evaluate them!
evaluate <- function(hand) {
SevenEval$getRankOfSeven(hand[1], hand[2], hand[3], hand[4], hand[5], hand[6], hand[7])
}
T <- system.time(lapply(hands,evaluate))
c('Hands Per Second'=as.numeric(round(n/T['elapsed'],0)))
My R code is almost identical to the python source, as all I did was change python classes to R lists and make the lists 1-indexed (R) rather than 0-indexed (python). I also used the wonderful bitops package for bitwise operations. Obviously this code should be vectorized, but I don’t have time to do that right now. I also used the “compiler” package to speed things up somewhat, but the “SevenEval” file still takes a long time to load.
Right now, I’m getting about 18,000 hands per second on my core i5 laptop, which is pretty crappy compared to the 250 million hands per second Shackleton reports for the C++ version. Vectorization should further increase performance, but I don’t think pure R is ever going to approach C++ in terms of raw speed. While this was a fun port to make, I think this code is an obvious candidate for a re-write using the Rcpp package.
I’m interested to see how far the pure R code can be optimized.