Port smart dealer 1
This commit is contained in:
parent
37d39b4521
commit
dbd9c600c8
156
dealer.lua
Normal file
156
dealer.lua
Normal file
@ -0,0 +1,156 @@
|
||||
function deal(ruleset)
|
||||
local n_usable_cards=ruleset.n_usable_cards
|
||||
local n_final_slots=ruleset.n_slots-1
|
||||
local n_usable_slots=n_final_slots+1
|
||||
local tower_height = n_usable_cards\n_final_slots
|
||||
|
||||
-- prototype
|
||||
local deal1,generate_wells,generate_pops,accepts
|
||||
local deal1=function()
|
||||
local slots,max_height={},{}
|
||||
for i=0,n_final_slots do
|
||||
slots[i]={}
|
||||
max_height[i]=tower_height
|
||||
end
|
||||
max_height[0]=1
|
||||
|
||||
local wells=generate_wells()
|
||||
local pops=generate_pops(wells)
|
||||
|
||||
local function pek(lst)
|
||||
return lst[#lst]
|
||||
end
|
||||
|
||||
local function pop(lst)
|
||||
return deli(lst,#lst)
|
||||
end
|
||||
|
||||
local function pop_accepted_card(lst)
|
||||
local card=lst[#lst]
|
||||
if (card and accepts(lst[#lst-1],card)) return pop(lst)
|
||||
end
|
||||
|
||||
local function find_home(odds,card,source,exclude)
|
||||
assert(card!=0)
|
||||
local acceptors={}
|
||||
local start_points={}
|
||||
|
||||
for s=0,#slots do
|
||||
local n=#slots[s]
|
||||
if s==exclude then
|
||||
-- don't place it here ever
|
||||
elseif ruleset.deck.instantly_accepted[card] and n==max_height[s]-1 then
|
||||
-- can't place an instantly accepted card at the bottom of a slot
|
||||
else
|
||||
if (accepts(pek(slots[s]),card)) add(acceptors,s)
|
||||
if (n<max_height[s]) add(start_points,s)
|
||||
end
|
||||
end
|
||||
|
||||
local acceptor=rnd(acceptors)
|
||||
local start_point=rnd(start_points)
|
||||
if (acceptor and rnd()>odds) acceptor=nil
|
||||
|
||||
local a=acceptor or start_point or source
|
||||
if (a) add(slots[a],card) return true
|
||||
end
|
||||
|
||||
local original_pops=#pops
|
||||
while #pops>0 do
|
||||
local w=deli(pops)
|
||||
assert(w!=0)
|
||||
local exclude
|
||||
|
||||
-- unblock aux slot if this is not arcana
|
||||
if w <= ruleset.n_suits then
|
||||
local c=pop(slots[0])
|
||||
assert(c!=0)
|
||||
if (c and not find_home(1.0,c,nil,0)) return
|
||||
exclude = 0
|
||||
end
|
||||
|
||||
local card=pop(wells[w])
|
||||
assert(card!=0)
|
||||
if (not find_home(1.0,card,nil,exclude)) return
|
||||
|
||||
local n_moves=48
|
||||
for i=1,n_moves do
|
||||
local src=flr(rnd()*(#slots+1))
|
||||
local card=pop_accepted_card(slots[src])
|
||||
if card then
|
||||
local odds=0.0
|
||||
if (not find_home(odds,card,src,nil)) return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- fix any stacks that are too tall
|
||||
max_height[0]=0 -- auxiliary slot must be empty
|
||||
for i=0,#slots do
|
||||
while #slots[i]>max_height[i] do
|
||||
local card=pop(slots[i])
|
||||
if (not find_home(0.0,card,nil,nil)) return
|
||||
end
|
||||
end
|
||||
|
||||
-- get rid of auxiliary slot
|
||||
slots[0]=nil
|
||||
for s=1,#slots do
|
||||
if (ruleset.deck.instantly_accepted[pek(slots[s])]) return
|
||||
assert(#slots[s]==tower_height)
|
||||
end
|
||||
|
||||
return slots
|
||||
end
|
||||
generate_wells=function()
|
||||
local split_point=flr(rnd()*(ruleset.n_arcana+1))
|
||||
local wells={}
|
||||
for i=1,ruleset.n_suits+2 do
|
||||
wells[i]={}
|
||||
end
|
||||
for r=2,ruleset.n_cards_per_suit do
|
||||
for s=1,ruleset.n_suits do
|
||||
local card=ruleset.n_cards_per_suit * (s - 1) + (r - 1) + 1
|
||||
assert(card!=0)
|
||||
add(wells[s],card)
|
||||
end
|
||||
end
|
||||
|
||||
local first_arcana=ruleset.n_suits*ruleset.n_cards_per_suit+1
|
||||
local arcana0=ruleset.n_suits
|
||||
local arcana1=arcana0+1
|
||||
for r=0,split_point-1 do
|
||||
assert(first_arcana+r!=0)
|
||||
add(wells[arcana0],first_arcana+r)
|
||||
end
|
||||
for r=ruleset.n_arcana-1,split_point,-1 do
|
||||
assert(first_arcana+r!=0)
|
||||
add(wells[arcana1],first_arcana+r)
|
||||
end
|
||||
return wells
|
||||
end
|
||||
generate_pops=function(wells)
|
||||
local pops={}
|
||||
for w=1,#wells do
|
||||
for _=1,#wells[w] do
|
||||
add(pops,w)
|
||||
end
|
||||
end
|
||||
shuf(pops)
|
||||
return pops
|
||||
end
|
||||
accepts=function(c0,c1)
|
||||
assert(c0!=0)
|
||||
assert(c1!=0)
|
||||
assert(c1!=nil)
|
||||
if (c0==nil) return true
|
||||
c0=ruleset.deck.cards[c0]
|
||||
c1=ruleset.deck.cards[c1]
|
||||
return c0.suit==c1.suit and (c1.rank == c0.rank+1 or c0.rank==c1.rank+1)
|
||||
end
|
||||
|
||||
while true do
|
||||
local d=deal1()
|
||||
if (d) return d
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user