fortunes_foundation/board.lua

206 lines
4.1 KiB
Lua
Raw Normal View History

2024-02-05 04:55:56 +00:00
board=klass()
function board:init()
self.cursor=cursor:new(self)
self.slots={}
self.wells={}
-- board slots
-- 1,11: normal
for i=1,11 do
add(self.slots,slot:new())
end
-- 12: special
add(self.slots,slot:new(1))
assert(#self.slots==12)
-- wells:
-- 1,2,3,4: wands, cups, swords, pentacles
local function add_suit(_self,suit)
add(_self.wells,well:new(function(lst,new)
assert(lst) -- the ace is always present initially
if (new.suit!=suit) return
return new.suit==suit and new.rank==lst.rank+1
end))
end
for suit in all(deck.suits) do
add_suit(self,suit)
end
-- 5: arcana ascending
add(self.wells,well:new(function(lst,new)
if (new.suit!='a') return
if (not lst) return new.rank==0
return new.rank==lst.rank+1
end))
-- 6: arcana descending
add(self.wells,well:new(function(lst,new)
if (new.suit!='a') return
if (not lst) return new.rank==21
return new.rank==lst.rank-1
end))
self:deal()
end
function board:deal()
local n_conventional_wells=4
local n_slots=10
-- first, pull the aces
assert(#deck.aces==n_conventional_wells)
assert(#self.wells==n_conventional_wells+2)
local available={}
for card=1,#deck.cards do
available[card]=true
end
for i=1,n_conventional_wells do
local well=self.wells[i]
local ace=deck.aces[i]
well:add(ace)
available[ace]=false
end
local eligible_bottom_row={}
for card=1,#deck.cards do
local skip
if not available[card] then
skip=true
else
for w in all(self.wells) do
if (w:would_accept(card)) skip=true break
end
end
if (not skip) add(eligible_bottom_row,card)
end
function i_to_slot(i)
if (i<n_slots\2) return i+1
return i+2
end
local bottom_row={}
shuf(eligible_bottom_row)
for i=1,n_slots do
local card=eligible_bottom_row[i]
add(bottom_row,card)
available[card]=false
end
eligible={}
for card=1,#deck.cards do
if (available[card]) add(eligible,card)
end
shuf(eligible)
for card in all(bottom_row) do
add(eligible,card)
end
for i=1,#eligible do
local ix=i_to_slot((i-1)%n_slots)
local slot=self.slots[ix]
slot:add(eligible[i])
end
end
function board:on_move()
-- TODO: Make checkpoint
while true do
if (not self:_on_move_1()) break
end
end
function board:_on_move_1()
for s=1,#self.slots do
local top=self.slots[s]:peek()
if top then
for w=1,#self.wells do
if w<=4 and self.slots[12]:peek()!=nil then
-- the top wells are blocked
elseif self.wells[w]:would_accept(top) then
self.wells[w]:add(self.slots[s]:pop())
return true
end
end
end
end
end
function board:draw()
for w_ix=1,#self.wells do
local w=self.wells[w_ix]
local l=layouts:well(w_ix)
for i=1,#w.contents do
local x,y=l:place_card(i)
deck:draw_card(x,y,w.contents[i],i<#w.contents)
end
end
local function forall_slots(cb)
for s_ix=1,#self.slots do
local s=self.slots[s_ix]
local l=layouts:slot(s_ix)
local n=#s.contents
if (self.cursor.grabbed==s_ix) n-=1
cb(x,y,s_ix,s,l,n)
end
end
forall_slots(function(x,y,s_ix,s,l,n)
for i=1,n do
local x,y=l:place_card(i)
deck:draw_card(x,y,s.contents[i],i<n)
end
end)
local hover_slot=self.cursor:hover_slot()
forall_slots(function(x,y,s_ix,s,l,n)
if hover_slot==s_ix then
local x,y=l:place_card(n+1)
self.cursor:draw_at(x,y)
end
end)
end
slot=klass()
function slot:init(max_n)
self.contents={}
self.max_n=max_n
end
function slot:would_accept(new)
local n=#self.contents
if (n==self.max_n) return
local lst=self.contents[n]
if (not lst) return true
lst=deck.cards[lst]
new=deck.cards[new]
return lst.suit==new.suit and (lst.rank==new.rank-1 or lst.rank==new.rank+1)
end
function slot:add(card)
add(self.contents,card)
end
function slot:peek()
return self.contents[#self.contents]
end
function slot:pop()
return deli(self.contents,#self.contents)
end
well=klass()
function well:init(accept_cb)
self.accept_cb=accept_cb
self.contents={}
end
function well:would_accept(new)
local lst=self.contents[#self.contents]
if (lst) lst=deck.cards[lst]
assert(new,"must be populated")
new=deck.cards[new]
assert(new,"must be populated")
return self.accept_cb(lst,new)
end
function well:add(card)
add(self.contents,card)
end