2024-02-08 04:59:31 +00:00
|
|
|
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
|
|
|
|
|
2024-02-08 20:44:28 +00:00
|
|
|
local function find_home(card,allow_too_tall)
|
2024-02-08 04:59:31 +00:00
|
|
|
assert(card!=0)
|
|
|
|
local acceptors={}
|
|
|
|
|
|
|
|
for s=0,#slots do
|
|
|
|
local n=#slots[s]
|
2024-02-09 01:04:33 +00:00
|
|
|
if ((allow_too_tall and accepts(pek(slots[s]),card)) or n<max_height[s]) add(acceptors,s)
|
2024-02-08 04:59:31 +00:00
|
|
|
end
|
|
|
|
|
2024-02-09 01:04:33 +00:00
|
|
|
local a=rnd(acceptors)
|
|
|
|
assert(a)
|
|
|
|
add(slots[a],card)
|
2024-02-08 04:59:31 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local original_pops=#pops
|
|
|
|
while #pops>0 do
|
2024-02-08 20:44:28 +00:00
|
|
|
local w=pop(pops)
|
2024-02-08 04:59:31 +00:00
|
|
|
local card=pop(wells[w])
|
2024-02-08 20:44:28 +00:00
|
|
|
find_home(card,true)
|
2024-02-08 04:59:31 +00:00
|
|
|
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])
|
2024-02-09 01:04:33 +00:00
|
|
|
find_home(card,false)
|
2024-02-08 04:59:31 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- get rid of auxiliary slot
|
|
|
|
slots[0]=nil
|
2024-02-08 20:44:28 +00:00
|
|
|
local shuffles=1
|
|
|
|
local actual_shuffles=1
|
|
|
|
for s=1,#slots do
|
|
|
|
local extra_shuf=shuffles+1
|
|
|
|
while (ruleset.deck.instantly_accepted[pek(slots[s])]) do
|
|
|
|
shuf(slots[s])
|
|
|
|
shuffles=extra_shuf
|
|
|
|
actual_shuffles+=1
|
|
|
|
if (actual_shuffles>=5) return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for i=shuffles,2 do
|
|
|
|
shuf(rnd(slots))
|
|
|
|
end
|
2024-02-08 04:59:31 +00:00
|
|
|
for s=1,#slots do
|
|
|
|
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
|
2024-02-09 01:04:33 +00:00
|
|
|
print("retrying")
|
2024-02-08 04:59:31 +00:00
|
|
|
end
|
|
|
|
end
|