Created
August 30, 2014 21:32
-
-
Save megafauna/6b9cac30982327f4406d to your computer and use it in GitHub Desktop.
Simulate poker chicken hands in lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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