Skip to content

Instantly share code, notes, and snippets.

@megafauna
Created August 30, 2014 21:32
Show Gist options
  • Save megafauna/6b9cac30982327f4406d to your computer and use it in GitHub Desktop.
Save megafauna/6b9cac30982327f4406d to your computer and use it in GitHub Desktop.
Simulate poker chicken hands in lua
local _ = require("moses")
local stats = require("stats")
local seed = 1
local HLEN = 5
local NUM_CARDS_IN_DECK = 52
local TOTAL_HANDS = NUM_CARDS_IN_DECK - HLEN + 1
local ranks = {nil, "2","3","4","5","6","7","8","9","T","J","Q","K","A"}
-- alt_rankmap is only for testing Ace-low straights
local rankmap = _.invert(ranks)
local alt_rankmap = _.clone(rankmap)
alt_rankmap["A"] = 1
local suits = {"C","S","D","H"}
local cards = {}
for j=1,#suits do
for i=2,#ranks do -- deuce to ace-high
cards[#cards+1] = ranks[i]..suits[j]
end
end
local hand_map = {[1]="High Card", [2]="Pair", [3]="Two Pair",
[4]="Three of a Kind", [5]="Straight", [6]="Flush",
[7]="Full House", [8]="Four of a Kind", [9]="Straight Flush"}
local ihand_map = _.invert(hand_map)
local level_cards
local level_scores
local hand
local prepare_cards
------------------------------------------------------------------------------------------
-- Given a hand, work out the score, so I can tell who won
--
local function score_hand(a_hand)
-- http://www.pokerlistings.com/poker-hand-ranking
-- map {AC, TD,} etc. to score
local hranks = _.map(a_hand, function(i,v) return string.sub(v,1,1) end)
local hsuits = _.map(a_hand, function(i,v) return string.sub(v,#v,#v) end)
--_.each(hranks, print)
--_.each(hsuits, print)
-- FLUSH
local is_flush = #(_.uniq(hsuits)) == 1
-- STRAIGHT; map ranks to numbers, Ace high or low for straights...
local nranks1 = _.map(hranks, function(i,v) return rankmap[v] end)
local nranks2 = _.map(hranks, function(i,v) return alt_rankmap[v] end)
local is_straight = false
if _.isEqual(_.sort(nranks1), _.range(_.min(nranks1), _.min(nranks1)+HLEN-1)) or
_.isEqual(_.sort(nranks2), _.range(_.min(nranks2), _.min(nranks2)+HLEN-1)) then
is_straight = true
end
-- N OF A KIND, Ace high only
local is_four_of_a_kind, is_three_of_a_kind, is_full_house, is_pair, is_two_pair = false, false, false, false, false
local rank_counts = _.map(ranks, function(i,v) return _.count(hranks, v) end)
local c = _.max(rank_counts)
-- main cards are in pairs or better; side_cards are the rest of the cards
local main_cards = {}
local side_cards = {}
if c == 4 then
is_four_of_a_kind = true
main_cards = {_.indexOf(rank_counts, 4)}
side_cards = {_.indexOf(rank_counts, 1)}
elseif c == 3 then
is_three_of_a_kind = true
main_cards = {_.indexOf(rank_counts, 3)}
rank_counts[_.indexOf(rank_counts, 3)] = 0
c = _.max(rank_counts)
if c == 2 then
is_full_house = true
is_three_of_a_kind = false
main_cards[2] = _.indexOf(rank_counts, 2)
else
local x = _.indexOf(rank_counts, 1)
side_cards[1] = x
rank_counts[x] = 0
side_cards[2] = _.indexOf(rank_counts, 1)
end
elseif c == 2 then
is_pair = true
main_cards = {_.indexOf(rank_counts, 2)}
rank_counts[_.indexOf(rank_counts, 2)] = 0
c = _.max(rank_counts)
if c == 2 then
is_two_pair = true
is_pair = false
main_cards[2] = _.indexOf(rank_counts, 2)
if main_cards[2] > main_cards[1] then main_cards = _.reverse(main_cards) end
side_cards = {_.indexOf(rank_counts, 1)}
else
local x = _.indexOf(rank_counts, 1)
side_cards[1] = x
rank_counts[x] = 0
x = _.indexOf(rank_counts, 1)
side_cards[2] = x
rank_counts[x] = 0
side_cards[3] = _.indexOf(rank_counts, 1)
end
else
side_cards = nranks1
end
side_cards = _.reverse(_.sort(side_cards))
local high_cards = _.reverse(_.sort(nranks1))
local score = nil
if is_flush and is_straight then -- straight flush, including royal
score = {ihand_map["Straight Flush"],
high_cards[1]}
-- HACK otherwise A2345 is a royal straight flush?
if ranks[high_cards[1]] == "A" and ranks[high_cards[2]] == "5" then
--native.showAlert("YES", "YES")
score[2] = high_cards[2]
end
elseif is_four_of_a_kind then
score = {ihand_map["Four of a Kind"],
main_cards[1],side_cards[1]}
elseif is_full_house then
score = {ihand_map["Full House"],
main_cards[1],main_cards[2]}
elseif is_flush then
score = {ihand_map["Flush"],
high_cards[1],high_cards[2],high_cards[3],high_cards[4],high_cards[5]}
elseif is_straight then
score = {ihand_map["Straight"],
high_cards[1]}
-- HACK otherwise A2345 is a royal straight
if ranks[high_cards[1]] == "A" and ranks[high_cards[2]] == "5" then
score[2] = high_cards[2]
end
elseif is_three_of_a_kind then
score = {ihand_map["Three of a Kind"],
main_cards[1],side_cards[1],side_cards[2]}
elseif is_two_pair then
score = {ihand_map["Two Pair"],
main_cards[1],main_cards[2],side_cards[1]}
elseif is_pair then
score = {ihand_map["Pair"],
main_cards[1],side_cards[1],side_cards[2],side_cards[3]}
else
score = {ihand_map["High Card"],
high_cards[1],high_cards[2],high_cards[3],high_cards[4],high_cards[5]}
end
local scorenum = score[1] * 1e13
for i=2,#score do
scorenum = scorenum + score[i] * math.pow(20,8-i)
end
return scorenum, score
end
compare = function(N)
level_cards = _.clone(cards)
for i=1,N do
_.shuffle(level_cards)
for i=1,TOTAL_HANDS do
local _hand = _.slice(level_cards, i, i+HLEN-1)
local _scorenum, _score = score_hand(_hand)
end
end
end
compare(1e5)
------------------------------------------------------------------------------------------
-- Just testing scoring
--
local function test_scoring()
local function test_score_hand(a_hand)
local scorenum, score = score_hand(a_hand)
return scorenum
end
-- straights and flushes
local h00 = {"AD", "KD", "QD", "JD", "TD"}
local h0b = {"KD", "QD", "JD", "TD", "9D"}
local h10 = {"TD", "9D", "8D", "7D", "6D"}
local h20 = {"TC", "9D", "8D", "7D", "6D"}
local h30 = {"TD", "9D", "8D", "7D", "JD"}
local h3b = {"AD", "2D", "3D", "4D", "5D"}
local h3c = {"6D", "2D", "3D", "4D", "5D"}
assert(test_score_hand(h00) > test_score_hand(h0b), "scoring error") -- straight flush ordering
assert(test_score_hand(h00) > test_score_hand(h10), "scoring error") -- straight flush ordering
assert(test_score_hand(h10) > test_score_hand(h20), "scoring error") -- straight flush vs straight
assert(test_score_hand(h30) > test_score_hand(h10), "scoring error") -- Ace-high
assert(test_score_hand(h00) > test_score_hand(h3b), "scoring error") -- Ace-high/low
assert(test_score_hand(h3c) > test_score_hand(h3b), "scoring error") -- Ace-high/low
-- four of a kind
local h40 = {"2D", "2C", "2S", "2D", "3D"}
-- three of a kind
local h4a = {"2D", "2C", "2S", "7D", "JD"}
-- full house
local h4b = {"2D", "2C", "2S", "3D", "3S"}
local h4c = {"2D", "2C", "2S", "AD", "AS"}
assert(test_score_hand(h3b) > test_score_hand(h4a), "scoring error") -- straight > three of a kind
assert(test_score_hand(h40) > test_score_hand(h4a), "scoring error") -- four > three of a kind
assert(test_score_hand(h4b) > test_score_hand(h4a), "scoring error") -- full house > three of a kind
assert(test_score_hand(h4c) > test_score_hand(h4b), "scoring error") -- full house 2/A > full house 2/3
-- pairs and two pairs
local h40 = {"AD", "AC", "8D", "7D", "JD"}
local h42 = {"2D", "2C", "8D", "7D", "JD"}
local h50 = {"AD", "AC", "8H", "7D", "KC"}
local h5b = {"AD", "AC", "8D", "KD", "KC"}
assert(test_score_hand(h40) > test_score_hand(h42), "scoring error") -- two A > two 2
assert(test_score_hand(h4a) > test_score_hand(h40), "scoring error") -- three > two A
assert(test_score_hand(h4a) > test_score_hand(h50), "scoring error") -- three > two A
assert(test_score_hand(h4a) > test_score_hand(h5b), "scoring error") -- three > two pair
assert(test_score_hand(h50) > test_score_hand(h40), "scoring error") -- two A+K > two A+J
assert(test_score_hand(h5b) > test_score_hand(h50), "scoring error") -- two A two K > two A+K
-- nothings / high-cards
local h60 = {"TH", "2C", "8D", "7S", "JD"}
local h70 = {"TD", "3D", "8S", "7D", "AC"}
local h80 = {"AS", "TD", "3C", "8D", "7H"}
local h90 = {"KC", "TD", "2C", "8D", "7D"}
assert(test_score_hand(h40) > test_score_hand(h60), "scoring error") -- two A > nothing
assert(test_score_hand(h70) > test_score_hand(h60), "scoring error") -- A > J
assert(test_score_hand(h80) > test_score_hand(h90), "scoring error") -- A > K
assert(test_score_hand(h70) == test_score_hand(h80), "scoring error") -- A etc == A etc
print("scoring ok")
return true
end
--test_scoring()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment