Compare commits

..

3 Commits

Author SHA1 Message Date
3508072c0e Card rotation 2024-02-09 22:17:57 -08:00
6a92341695 Remove shadows as a feature 2024-02-09 21:43:01 -08:00
94a410a587 Support multiple seed pools 2024-02-09 21:05:24 -08:00
24 changed files with 56837 additions and 170 deletions

2
.gitignore vendored
View File

@ -0,0 +1,2 @@
*.pyc
__pycache__/

View File

@ -18,11 +18,13 @@ function board:init(ruleset)
-- wells: -- wells:
-- ...n_suits: wands, cups, swords, pentacles, etc -- ...n_suits: wands, cups, swords, pentacles, etc
local function add_suit(_self,suit) local function add_suit(_self,suit)
add(_self.wells,well:new(_self.ruleset, function(lst,new) local w=well:new(_self.ruleset, function(lst,new)
assert(lst) -- the ace is always present initially assert(lst) -- the ace is always present initially
if (new.suit!=suit) return if (new.suit!=suit) return
return new.suit==suit and new.rank==lst.rank+1 return new.suit==suit and new.rank==lst.rank+1
end)) end)
w.obscured_by_extra_slot=true
add(_self.wells, w)
end end
for suit in all(self.ruleset.deck.suits) do for suit in all(self.ruleset.deck.suits) do
add_suit(self,suit) add_suit(self,suit)
@ -105,13 +107,19 @@ function board:update()
end end
function board:draw() function board:draw()
local extra_slot_full=self.slots[self.ruleset.n_slots+1]:peek()!=nil
for w_ix=1,#self.wells do for w_ix=1,#self.wells do
local w=self.wells[w_ix] local w=self.wells[w_ix]
local l=self.ruleset.layouts:well(w_ix) local l=self.ruleset.layouts:well(w_ix)
local shadowed=nil
if w.obscured_by_extra_slot and extra_slot_full then
shadowed=true
end
for i=1,#w.contents do for i=1,#w.contents do
local x,y=l:place_card(i) local x,y=l:place_card(i)
self.ruleset.deck:draw_card(x,y,w.contents[i],i<#w.contents) self.ruleset.deck:draw_card(x,y,w.contents[i],{shadowed=shadowed})
end end
end end
@ -130,7 +138,7 @@ function board:draw()
forall_slots(function(x,y,s_ix,s,l,n) forall_slots(function(x,y,s_ix,s,l,n)
for i=1,n do for i=1,n do
local x,y=l:place_card(i) local x,y=l:place_card(i)
self.ruleset.deck:draw_card(x,y,s.contents[i],i<n) self.ruleset.deck:draw_card(x,y,s.contents[i],{rotate=l.rotated})
end end
end) end)
@ -141,7 +149,7 @@ function board:draw()
forall_slots(function(x,y,s_ix,s,l,n) forall_slots(function(x,y,s_ix,s,l,n)
if hover_slot==s_ix then if hover_slot==s_ix then
local x,y=l:place_card(n+1) local x,y=l:place_card(n+1)
self.cursor:draw_at(x,y) self.cursor:draw_at(l,x,y)
end end
end) end)
end end

View File

@ -61,7 +61,7 @@ function board:_animate_move_card(card,on_end,start_x,start_y,compute_end)
function anim_obj:draw() function anim_obj:draw()
local x=start_x+(end_x-start_x)*progress local x=start_x+(end_x-start_x)*progress
local y=start_y+(end_y-start_y)*progress local y=start_y+(end_y-start_y)*progress
_self.ruleset.deck:draw_card(x,y,card,false) _self.ruleset.deck:draw_card(x,y,card,{})
end end
self.animator:add(anim_obj) self.animator:add(anim_obj)

View File

@ -72,7 +72,7 @@ function cursor:grabbed_card()
return nil return nil
end end
function cursor:draw_at(x,y) function cursor:draw_at(l,x,y)
local card=self:grabbed_card() local card=self:grabbed_card()
local acc=self:acceptance_state() local acc=self:acceptance_state()
@ -80,13 +80,34 @@ function cursor:draw_at(x,y)
x+=sin(time()/2)*2+0.5 x+=sin(time()/2)*2+0.5
y+=sin(time()/4)+0.5+1 y+=sin(time()/4)+0.5+1
end end
x=flr(x)
y=flr(y)
local function draw_surround_box(fg)
if (not fg) return
if l.rotated then
rect(x-4,y+6,x+13,y+16,fg)
else
rect(x-1,y-1,x+9,y+16,fg)
end
end
local function draw_overlapping_box(fg)
if (l.obscured) draw_surround_box(fg) return
if l.rotated then
rectfill(x-3,y+7,x+12,y+15,fg)
else
rectfill(x,y,x+8,y+15,fg)
end
end
if card then if card then
local card_fg=self.ruleset.deck:draw_card(x,y,card,false) local card_fg=self.ruleset.deck:draw_card(x,y,card,{rotate=l.rotated})
local fg=card_fg local fg=card_fg
if (acc==acceptance_state.would_accept) fg=9 if (acc==acceptance_state.would_accept) fg=9
if (fg) rect(x-1,y-1,x+9,y+16,fg) draw_surround_box(fg)
else else
rectfill(x,y,x+8,y+15,9) draw_overlapping_box(9)
end end
end end

View File

@ -1,6 +1,7 @@
layout_mode={ layout_mode={
obscured=0, -- for wells obscured=0, -- for wells
vertical=1, -- for conventional slots vertical=1, -- for conventional slots
rotated=2,
-- todo: sideways -- todo: sideways
} }
@ -9,10 +10,13 @@ function layout:init(x,y,mode)
self.x=x self.x=x
self.y=y self.y=y
self.mode=mode self.mode=mode
if (mode==layout_mode.rotated) self.rotated=true
if (mode!=layout_mode.vertical) self.obscured=true
end end
function layout:place_card(i) function layout:place_card(i)
if (self.mode==layout_mode.obscured) return self.x,self.y if (self.mode==layout_mode.obscured) return self.x,self.y
if (self.mode==layout_mode.rotated) return self.x,self.y
if (self.mode==layout_mode.vertical) return self.x,self.y+(i-1)*6 if (self.mode==layout_mode.vertical) return self.x,self.y+(i-1)*6
assert(false,"unexpected mode: "..self.mode) assert(false,"unexpected mode: "..self.mode)
end end

169
main.p8
View File

@ -85,86 +85,91 @@ __gfx__
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
a45b403c0aa0360f5944347b0018170a1312011307511c2075829964331301088305c86241754c071719a68aa302a962944fa20393c3e726a6308b36804a7013 c9311100fc009820e4509a50ca603c90a3a009a0d5b00dd055f027215d21a531e531d6319831e8317931277132a5120a007276821161320416d14631d331e862
505043247423215f30f77413244003620624034405a12c02347070330103b0d524535c21cbd1187013311316c161583180b01250f8a92308652817329c220125 7462511341324319b5779502eb05d82194423941818023885111644669aa2a169110a1561bb28201632467214103762f4812302241975603a9799117a3111c31
51c2746157071abd696554091183b5453222346324005c7a502274729035031320a54610a134145270606923d2624887d45601017bcf92a570c08002538065a3 54224678216131332299517613113822a1a81b2191451b9d4a12444e2146331121146b18a623a1212143b4414461930716662c10145931ca52421046d1d46453
7722d440060430371f7796b901314fc00040caa73b9d670a016c26305a67795c32f67a3c48bd372e664136e003442a036e6a48009d460a8413333005a15c1221 e285625e10d0416a445310369c1d2d7a2210b4211365372a523145221379e432bc1f2343132211370354624605c7135214298212a65197288711ef6c10155410
25feb24a024641a930649018e06af40613c6df323df0922136c0b3a628a9704887eb465f103eb312113a71d6132681ec5314660112a592500a7332050b110022 2c023d63b2113522c6311131a711c2a23d1225273cc7c29b131364b26426e319811152a15f72b15a1c968691342059612724f532114262315793231026100223
2133bf841ad2e08531151212008b1b93269808f6e7084bf509645c4d17e5381030d09a21374097e7205833281b4968b2d257805070cb23f660123a8961d02217 e71b1831203ac658400341618db534033046726b64398c48116104050184601409453c11302421261347612b1131431a21385ba8204483115178622001227391
99c4a3543235608e61c082461387e3a08112422243124c95b80527b4c70297bb53111112ae012101701d57021a33baa5320a75220703e67316450a470811222f 12161520248c8131276695811852091625941e250592543263163b098e7033340202485337d4c474719812a1e151946ff9354a543261203d82811352d0750ff4
2407132570675cad8466b089c6ae8b1cd63445254321211112211225171902cc2f52b3431a96e0621a0b320810118847210217302c829172a9142e81471a1222 62e13078413345221a4093473d592e235275d2f067b11349521811063506406626048503b21f19932271e447917243136a9118433c0c1b1b00126c523d552811
151012109139251e01535f3f60d066309689f475500ac31f0c51550fb2c040636116072bb95c3c20623312d15802729e11a7863610235565041e05d811102790 b3b090a138154420832f1c2b359214132417364e4b602d7684137112b0190343a05954d117631421672111324410805550316535815351443515515512135301
2303bb6766a35d19634125255536468126950ed0511d2004a869600b03606008402c423631430234c82143b431911ad813080730a56952dff8d930c0710f9c59 85032431522303a45b403c0aa0360f5944347b0018170a1312011307511c2075829964331301088305c86241754c071719a68aa302a962944fa20393c3e726a6
1560411e195885ab12a47046a513355330834851127111b0b01223b425a03700713fd455012919b962ea2204803297512905048b60e0070b10db28d95d041334 308b36804a7013505043247423215f30f77413244003620624034405a12c02347070330103b0d524535c21cbd1187013311316c161583180b01250f8a9230865
6413616371255f16bc72123662020571218053d29a0a08d5614cb03218e4202307a3331121072003208b5216380484d071152504157a34646b93320421067bfd 2817329c22012551c2746157071abd696554091183b5453222346324005c7a502274729035031320a54610a134145270606923d2624887d45601017bcf92a570
71328140448aa00003916fb823a42960baf06050bbbc50802215d3247720e254ada00e824740640b1d220134900a865163575c651d12fb3a5142e10402804018 c08002538065a37722d440060430371f7796b901314fc00040caa73b9d670a016c26305a67795c32f67a3c48bd372e664136e003442a036e6a48009d460a8413
d34432745132241ea1144102343936850621e24e38478403732882714b6095a00a8bc12563fb29a95124622b191e132d71031028233188cff2b6054c5a500220 333005a15c122125feb24a024641a930649018e06af40613c6df323df0922136c0b3a628a9704887eb465f103eb312113a71d6132681ec5314660112a592500a
06461bb07141bd203519449c4a7b81059519e186332206a601080782219753433271d3f7a60bb0325500dcd0320a4f425263a0635103119131a6c114220d483c 7332050b1100222133bf841ad2e08531151212008b1b93269808f6e7084bf509645c4d17e5381030d09a21374097e7205833281b4968b2d257805070cb23f660
22692c1f36d0a4e4b650a574d52035129d6043a71416f190d044201e640d9361a28795850d841420008330235203565132f09c1062b314c01100130214826079 123a8961d0221799c4a3543235608e61c082461387e3a08112422243124c95b80527b4c70297bb53111112ae012101701d57021a33baa5320a75220703e67316
4433210066db20e7d4243c00363044503221a9a248028275163032437db731156197323b110083556bc6882b62120145932723c410141720502110607096341b 450a470811222f2407132570675cad8466b089c6ae8b1cd63445254321211112211225171902cc2f52b3431a96e0621a0b320810118847210217302c829172a9
040253269c334a9ad729304c593a6541c8512542d252305530103c61142f64d7d884937139a6082c8af4436d472012b2a520dc2401b055ce7472750d2a334f50 142e81471a1222151012109139251e01535f3f60d066309689f475500ac31f0c51550fb2c040636116072bb95c3c20623312d15802729e11a786361023556504
02c529bd7c0950635919c19f7b339d700061121604392031118b4550112932e89603008cd0fb931925c5c25b110a43460d23941436924a202077044914a618d2 1e05d8111027902303bb6766a35d19634125255536468126950ed0511d2004a869600b03606008402c423631430234c82143b431911ad813080730a56952dff8
411e3341031101c5e0f0127719125212545515771b9b1db33070001903110033333c01032c3265162f30010b00d3232022416e5a6625a391e0736112b0030131 d930c0710f9c591560411e195885ab12a47046a513355330834851127111b0b01223b425a03700713fd455012919b962ea2204803297512905048b60e0070b10
a33e106330c444a849058741a02733922393921f0230f2e645234d441b84f20ae452222723d363f2c0a0230136181d550c1054542190004072371d4e13069153 db28d95d0413346413616371255f16bc72123662020571218053d29a0a08d5614cb03218e4202307a3331121072003208b5216380484d071152504157a34646b
0b905062ea1b1831348050161007723cbf05e0122080c4030533b1396114221153345021058405d139924e92ad06010105e0452a8c0b703116f0342005c66451 93320421067bfd71328140448aa00003916fb823a42960baf06050bbbc50802215d3247720e254ada00e824740640b1d220134900a865163575c651d12fb3a51
62110200c314070a144300ca63855bc1be01cb9326008aeb0a2bc12e0fcb2120d13c806494815a00b2a2048007195e54f49f9a1bda72163953e4b55516013e01 42e10402804018d34432745132241ea1144102343936850621e24e38478403732882714b6095a00a8bc12563fb29a95124622b191e132d71031028233188cff2
17a030e8e9009dc461a41017a8de92072403ff12724200356739323429133a3131030ae919a118c38268a569e604609027e6d12511e1d1005f235661d08a6642 b6054c5a50022006461bb07141bd203519449c4a7b81059519e186332206a601080782219753433271d3f7a60bb0325500dcd0320a4f425263a0635103119131
0101913aeb58522a65c9ab7108b412d5315940519305310d5e83a39a0621605902354212014ab3ce24e0276205201da9d25322db8158e0e533501c733deb2b65 a6c114220d483c22692c1f36d0a4e4b650a574d52035129d6043a71416f190d044201e640d9361a28795850d841420008330235203565132f09c1062b314c011
82032123367845157b8203031329616024114326763031c67207e61b1489f1114603909b3c320200775856471002965c31007f4393c033910433505033001c59 001302148260794433210066db20e7d4243c00363044503221a9a248028275163032437db731156197323b110083556bc6882b62120145932723c41014172050
84070b4404312f550d8caa4271887618b24c141401141266c2277005a2483e931a24844542112793c3321009f7657185617119015e7030049021154661a246d5 2110607096341b040253269c334a9ad729304c593a6541c8512542d252305530103c61142f64d7d884937139a6082c8af4436d472012b2a520dc2401b055ce74
66a51123ec45154031a14727580101433190b05309382063244766e0c0226217503bc02064936f032241d81650511057171f2150044f213b2e0015a38c243680 72750d2a334f5002c529bd7c0950635919c19f7b339d700061121604392031118b4550112932e89603008cd0fb931925c5c25b110a43460d23941436924a2020
ab3010b466481db267510761c2073003b10640243926b0d90ad4600429f4134323130114132d435c4793621a6823fa402629e1806045135b3f5818112091025a 77044914a618d2411e3341031101c5e0f0127719125212545515771b9b1db33070001903110033333c01032c3265162f30010b00d3232022416e5a6625a391e0
1cf83438cf042533381708106085ca79020210f55003c06020c49848d20503c6363f7c9c22b32c7b3b1878752222a40235c1c2b14211647f20fd51b5b067c267 736112b0030131a33e106330c444a849058741a02733922393921f0230f2e645234d441b84f20ae452222723d363f2c0a0230136181d550c1054542190004072
2604670f173da221902fc232269007651016f335274e02e3117ca6b341230d75011062b2318619531730a6117d0373b36509292c054189450968133141c11625 371d4e130691530b905062ea1b1831348050161007723cbf05e0122080c4030533b1396114221153345021058405d139924e92ad06010105e0452a8c0b703116
19883316235530007105f02314791a01789012050c740b010649696124b1d9032b0c0720002a065c9005105f018d4038a177510069544180311c470624701819 f0342005c6645162110200c314070a144300ca63855bc1be01cb9326008aeb0a2bc12e0fcb2120d13c806494815a00b2a2048007195e54f49f9a1bda72163953
7059d63554287564a047bd9950e732c14f54a6000529070b24850d07200bd70c41b910c31d47a516d353e06f179262831975015958350d3673088f55721440f3 e4b55516013e0117a030e8e9009dc461a41017a8de92072403ff12724200356739323429133a3131030ae919a118c38268a569e604609027e6d12511e1d1005f
7026505f3ad2527235bafc335b0098035d138016c174031131100f445e48359829326a09225332136c105f455032720f3d44419d36a1992113032eec61831447 235661d08a66420101913aeb58522a65c9ab7108b412d5315940519305310d5e83a39a0621605902354212014ab3ce24e0276205201da9d25322db8158e0e533
772809a792545913677b4371a877796c6889264a50119462f21f812291e2014390815078140047a9947008e0c04056628323530064650372a61457c623857aa9 501c733deb2b6582032123367845157b8203031329616024114326763031c67207e61b1489f1114603909b3c320200775856471002965c31007f4393c0339104
53a9204033200112353841122a6e302401a32f15432d4013abf436474330056605c404c203724428e5674062403d34112f18010bd0e592916c903dc856037950 33505033001c5984070b4404312f550d8caa4271887618b24c141401141266c2277005a2483e931a24844542112793c3321009f7657185617119015e70300490
0963008c803f0293932a5e51c20b072148c512262b43313104d25024589451b058802c1841a0b8270b5e26631812671c11c112d10e036b54265454171427a062 21154661a246d566a51123ec45154031a14727580101433190b05309382063244766e0c0226217503bc02064936f032241d81650511057171f2150044f213b2e
7542720a0601caaf273804730a30522111a952078e747641627573704c2a5400e01056145a2e32f78676232d26450b251e0122e41f23405c958804600d104554 0015a38c243680ab3010b466481db267510761c2073003b10640243926b0d90ad4600429f4134323130114132d435c4793621a6823fa402629e1806045135b3f
91625709a60196f0c064058d9e08493d8235ba39651a2270531a2488a78f8b64a2231744a5d602a151e3570080513385731e0e111381713211d0a3b419c6a5b3 5818112091025a1cf83438cf042533381708106085ca79020210f55003c06020c49848d20503c6363f7c9c22b32c7b3b1878752222a40235c1c2b14211647f20
21960bf53736235130011060a60b6130cf0740d02623371061122b0b534203b0e25ea1142535276f95a104a1215e30d9a986f06cc1a102940f2650208b0cd047 fd51b5b067c2672604670f173da221902fc232269007651016f335274e02e3117ca6b341230d75011062b2318619531730a6117d0373b36509292c0541894509
12478de7de3090c730504d10602c021027703a2ca90517d200a010910530952ae7016861d4771215c179b4415d75011800242382101763d38100140010653204 68133141c1162519883316235530007105f02314791a01789012050c740b010649696124b1d9032b0c0720002a065c9005105f018d4038a17751006954418031
7336e0035a17802eb329002522210400747e76730e6c90450450e3a13da5620322c2222b0132a810451c9c25f7030278f24830113651ea14360862331d411164 1c4706247018197059d63554287564a047bd9950e732c14f54a6000529070b24850d07200bd70c41b910c31d47a516d353e06f179262831975015958350d3673
f4d3295a634022c3aba1357001210e97a22e92278142a024f428351f32101f756a317403268d31755712811374d5122834b921b3c40d10241fee0a126a645818 088f55721440f37026505f3ad2527235bafc335b0098035d138016c174031131100f445e48359829326a09225332136c105f455032720f3d44419d36a1992113
25a1d55000186c218507281030124af1277320570775768c19d3472120ed02354318d105e4006d5009e5ff413b83e92008b04a28028075bf3ac3e4f850c13962 032eec61831447772809a792545913677b4371a877796c6889264a50119462f21f812291e2014390815078140047a9947008e0c04056628323530064650372a6
4f5f50ea324fb344364186a4353a218a0b92031555100b3220b223cd363370400077d3317921a42e21618b4b80641e904b11703b8153b0620ab00247d001403a 1457c623857aa953a9204033200112353841122a6e302401a32f15432d4013abf436474330056605c404c203724428e5674062403d34112f18010bd0e592916c
ba700a3b007243401f64164418a02304d6b03e394d601060f751614681301c8487413905019331570124d500c91833315f025be0707208e706a4a37409bb540c 903dc8560379500963008c803f0293932a5e51c20b072148c512262b43313104d25024589451b058802c1841a0b8270b5e26631812671c11c112d10e036b5426
40000c320db304c953f1176063aa48613172e632832a049452806011b07054d23e09b340d032110c557a0c29247e191298c4770d43044224115053864571060e 5454171427a0627542720a0601caaf273804730a30522111a952078e747641627573704c2a5400e01056145a2e32f78676232d26450b251e0122e41f23405c95
00766473701905322a148177154ce13230963323000062502063e891168081a7911003750054042a745834a70b80d1147ad551a37c14465a54fa1da3a42c1430 8804600d10455491625709a60196f0c064058d9e08493d8235ba39651a2270531a2488a78f8b64a2231744a5d602a151e3570080513385731e0e111381713211
0b02d04505c8f103471874735968bb1cd203743347342fd27240c1b613504750648c426c016021707720c683d21133a05c241204591407134403ae02b36c8c51 d0a3b419c6a5b321960bf53736235130011060a60b6130cf0740d02623371061122b0b534203b0e25ea1142535276f95a104a1215e30d9a986f06cc1a102940f
4251261327004c729e0c3b328012e5011d6b854332683d0910a0002639144b901b0300211a613433c05b4630153bf3e30b23172d2023440a059c01b3275426f0 2650208b0cd04712478de7de3090c730504d10602c021027703a2ca90517d200a010910530952ae7016861d4771215c179b4415d75011800242382101763d381
23383a370375496c0760039d00f8d25101f4809032302198261111202ace6ac100543264641289340f1634390cac2f204ad300548641a5086d11333409b44840 001400106532047336e0035a17802eb329002522210400747e76730e6c90450450e3a13da5620322c2222b0132a810451c9c25f7030278f24830113651ea1436
0d3111694b3d464b62e17460311442855d05cd3704923e9d0770707c0132109b399428a8146012d7a5043207d64e03fd1126742b016745603500113043464471 0862331d411164f4d3295a634022c3aba1357001210e97a22e92278142a024f428351f32101f756a317403268d31755712811374d5122834b921b3c40d10241f
777326217676060195001268be8381430c862a1c2b0265a4234a69635140318597cb49370643550c2a314e33781b490095f73245600a00de12041497c80550a4 ee0a126a64581825a1d55000186c218507281030124af1277320570775768c19d3472120ed02354318d105e4006d5009e5ff413b83e92008b04a28028075bf3a
701604144259018e4314582680b0bb8a28b4061216010d3063521c666031d4460d1412012e2547030e2389252b19e9da341623912035220923220d61f5d10673 c3e4f850c139624f5f50ea324fb344364186a4353a218a0b92031555100b3220b223cd363370400077d3317921a42e21618b4b80641e904b11703b8153b0620a
575950d15619fb7355715a214d604411ab425c28017fa0069204b0663402432027a2205515603021b5012178664215329112a53b219206035f3c10116e562c1b b00247d001403aba700a3b007243401f64164418a02304d6b03e394d601060f751614681301c8487413905019331570124d500c91833315f025be0707208e706
810f50bb51811900008920109036a46044a566fa5c3d75f2930d101b41033e6e718450e5f32d36072531f1022065d01546295b20f09900200b200f125f060105 a4a37409bb540c40000c320db304c953f1176063aa48613172e632832a049452806011b07054d23e09b340d032110c557a0c29247e191298c4770d4304422411
320bd2021354bd12376d4391020cb46909a21392d066d219e072259f0c554057d6f02b893514531a4a873080f05063001516435231229200a15d50aab311e82b 5053864571060e00766473701905322a148177154ce13230963323000062502063e891168081a7911003750054042a745834a70b80d1147ad551a37c14465a54
2f4c3353942ab36526425316135b3894161e224530243321900532352125720229f25b6e63272685339f70b62724ac734dfb9539aa81104f7c43c6125303a0b0 fa1da3a42c14300b02d04505c8f103471874735968bb1cd203743347342fd27240c1b613504750648c426c016021707720c683d21133a05c2412045914071344
26c576b4123535e13346510610016436b311015422250811770250d4a3f86291acde02513d9541811164981402046f2351d5331390f538664452a09411464591 03ae02b36c8c514251261327004c729e0c3b328012e5011d6b854332683d0910a0002639144b901b0300211a613433c05b4630153bf3e30b23172d2023440a05
1923e750019b705151701c1633b06eb064015121181cb6b1414b1120e03d715118259963471fa8151bb5a2502492222a910611365306ee6fa1a43015d227e65b 9c01b3275426f023383a370375496c0760039d00f8d25101f4809032302198261111202ace6ac100543264641289340f1634390cac2f204ad300548641a5086d
407033404721f0c019292341e5e8206104601ed1574d21e8ca05171a04320ed862140210590a090430985c1289011804206a049a71f054016463335440135936 11333409b448400d3111694b3d464b62e17460311442855d05cd3704923e9d0770707c0132109b399428a8146012d7a5043207d64e03fd1126742b0167456035
02c6202303351c50f3406fb0a1004610142f161400b481df8b740f3617bafb033c64f26562057017c58400d5a13a2320210631b361f2a1029211268166226207 00113043464471777326217676060195001268be8381430c862a1c2b0265a4234a69635140318597cb49370643550c2a314e33781b490095f73245600a00de12
013285caa12003604001110f152c7671a80f8e743406d0505156083235037931dd020107a700781e2bf6dc081266341019e61cee2698eb259d0759c481710139 041497c80550a4701604144259018e4314582680b0bb8a28b4061216010d3063521c666031d4460d1412012e2547030e2389252b19e9da341623912035220923
255c14601869861492306742b03a2f060513a1211130042a0575301102220c20d30a5458c01554312484223950410b463035e232a58773710174065266239d2a 220d61f5d10673575950d15619fb7355715a214d604411ab425c28017fa0069204b0663402432027a2205515603021b5012178664215329112a53b219206035f
__map__ __map__
12272711306328d47551b51b4c8610acf67a11171810339055e1331841200028a2611a977291bc0633572201044ba2d638db0dc860213021c3d112540c847a3d2b88693720504c31e4c2a055431ea47602f804e4f405ea10be68d639ab9642a1a0f9744232be8b125319405159f512649d3402d0f79b242cc8070585421956f1 c30111e665c2b118f005bb151891000098020109634a06445a66afc5d3572f39d001b11430e3e61748055e3fd2637052131f2002560d516492b5020f990002b002f021f560105023b02d203145db2173d6341920c04b96902a31290d662d910e2752f9c05504756d0fb298534135a1a47803080f05360051613425132229001a
0584116d681c448868019160838b3092e51133c11263b7e4a313b74352a3a46110ad32d144b302e26975019463487231002d09c89c9840767c1233002a63a4119274ca950163625513502e12302efaa1f0da9bd420612524a1633109a700f00006686083c205503d7474030070402a080b771442d79631632280e071b7d0fbb7 d505aa3b118eb2f2c4333549a23b566224356131b5834961e12254034233120950235312522720922fb5e63672625833f9076b7242ca37d4bf5993aa1801f4c7346c2135300a0b625c674b2153531e33641560011046633b111045225280117720054d3a8f2619caed2015d3591418114689412040f632155d3331095f836644
412f13543919c4033e083182299b4330060551235013a835620e5a550325022a2d7b6250b34740163bde22730861f407910271937553c120b5c744206292856e00177230131e46015d219b307ea03d1374224f339b0332ac1d305462d2072b67cc2b2c719fd41b6d7055c4034638560aa482d0b4174a44155203a5f26b03e1c4 250a491164541991327e0510b907151507c161330be60b4610151281c16b1b14b411020ed317158152993674f18a51b15b2a05422922a2196011633560eef61a4a03512d726eb50407330474120f0c919232145e8e02164006e11d75d4128eac5071a14023e08d2641200195a090400389c5219810814002a640a9170f451046
050a061bb02125530606752302412b605a53d7031508303520ee7358104b094101782e0da82aa965130b220f5118784700058771bb09c1848a84e32894119c8c830111590f933415202a40e60104443520d85821d00105399c0423922c8a8c60c600a333716c6097531112330c7bb050227f550833742371ac8e2e2312dd34e0 36334504319563206c02323053c1053f04f60b1a00640141f26141004b18fdb847f06371abbf30c3462f56265007715c48005d1aa332021260133b162f1a202911621866222670102358ac1a023006041011f051c267178af0e84743600d051565802353309713dd2010707a0087e1b26fcd8021664301916ec1ee6289be52d9
95107d34612049251a3deb6208401203151a43a27a118cf1a03f760708847432034f246608904943930431780a3ed102d070346a8180e40001b5fba3451b167353e0ab21fec20653f18161b035200815132041a5511b50c80cb8ec658516319143950f05932c71460162439bb00c35530113be243271389c083c73c731106070 70954c1817109352c5410681966841290376240ba3f26050311a12110340a2505703112022c0023da045850c514513424822930514b06403532e235a783717104760256632d9a212272711306328d47551b51b4c8610acf67a11171810339055e1331841200028a2611a977291bc0633572201044ba2d638db0dc860213021c3
335009dd0051113622908990265b11472516044a777d4707da0a9053504030942690db86053408221540300221a1b223d201403440048d1f484031617635e060621524e87647400b86740349c001590791270282f1305f32609b70132269a2e523f29108033096e310074312114a134e52922a29092b23421793346149671bd4 d112540c847a3d2b88693720504c31e4c2a055431ea47602f804e4f405ea10be68d639ab9642a1a0f9744232be8b125319405159f512649d3402d0f79b242cc8070585421956f10584116d681c448868019160838b3092e51133c11263b7e4a313b74352a3a46110ad32d144b302e26975019463487231002d09c89c9840767c
91176025541256501109144457253663a3041a394b173931169515f337ae26330c801902d2354d51a0d502f19a68088df41a38841f83044202165400107b081e045b2d911211a8712289a63102323b2a767022341116b34c639c0304052bc382e21905427000630d0344c8516c4665925034920b9e82e6539039736e02064780 1233002a63a4119274ca950163625513502e12302efaa1f0da9bd420612524a1633109a700f00006686083c205503d7474030070402a080b771442d79631632280e071b7d0fbb7412f13543919c4033e083182299b4330060551235013a835620e5a550325022a2d7b6250b34740163bde22730861f407910271937553c120b5
1142321b12b421352743f871c100440b6f531b020113e6371140020437a921126a05779678c4402151412281754c4778ca02ac432553e12607330d3b1af86533a032400724969268734f760a27f45001fc40174422188a161d2b20289007145394e66022a840575b320200f8407e833275018515844490ad0274093119b1a801 c744206292856e00177230131e46015d219b307ea03d1374224f339b0332ac1d305462d2072b67cc2b2c719fd41b6d7055c4034638560aa482d0b4174a44155203a5f26b03e1c4050a061bb02125530606752302412b605a53d7031508303520ee7358104b094101782e0da82aa965130b220f5118784700058771bb09c1848a
0367323f2135ad8338806974bdcf944424070b0100c95446014320023a08347f77b21f31872f09139552112c417007140f63fcb520a41120160295260120027224b5b87554902044101506154406128150c06446423260ca5002317a18f37405043057165158a6084708c515050021be292a811208283572c826a2810977302e 84e32894119c8c830111590f933415202a40e60104443520d85821d00105399c0423922c8a8c60c600a333716c6097531112330c7bb050227f550833742371ac8e2e2312dd34e095107d34612049251a3deb6208401203151a43a27a118cf1a03f760708847432034f246608904943930431780a3ed102d070346a8180e40001
c94a55ff919502b2a33442144b74715544716219300212f37011e813c08fd56608a386131e44f220902515151bc569b305210218c1e545826c4d34323500a9431391130198127276500440b220a1422b6b58b6a6367635e10b61808b7002313e52053a146635275f70118a2339ba62046d760b5000d3bd0012687814013f87a2 b5fba3451b167353e0ab21fec20653f18161b035200815132041a5511b50c80cb8ec658516319143950f05932c71460162439bb00c35530113be243271389c083c73c731106070335009dd0051113622908990265b11472516044a777d4707da0a9053504030942690db86053408221540300221a1b223d201403440048d1f48
a306831030325632662132df101a5135900a7f1b3300e00860033081ec4010c00204b14440037253060c2451d45409e76d349560b2593b336532459905b00864008c262420078270533013221a930d612db04c05a42fb620419293885f24e59110d0005c320075cd4841a019089c63f521d6b8c92babf6430b48030084324d00 4031617635e060621524e87647400b86740349c001590791270282f1305f32609b70132269a2e523f29108033096e310074312114a134e52922a29092b23421793346149671bd491176025541256501109144457253663a3041a394b173931169515f337ae26330c801902d2354d51a0d502f19a68088df41a38841f83044202
25af206b02e0300bf8854a07666b0423108028201456180b4216287129020549401639a610ba03231030662131c41543d3b070208d0a12323071431b689680b02410030f304bfb6684a31fc6017605041745581335b0749863260429ad11e061ed6e25a287895137ef20b21260418041d2a04408aa5b960a230a1b522000b325 165400107b081e045b2d911211a8712289a63102323b2a767022341116b34c639c0304052bc382e21905427000630d0344c8516c4665925034920b9e82e6539039736e020647801142321b12b421352743f871c100440b6f531b020113e6371140020437a921126a05779678c4402151412281754c4778ca02ac432553e12607
e270a090811741436d45572801621c4496bd57895524875309220b5187209a1b20519b253842509224b56812a2910935501f1d040a008a2460155508248600254795b5b16ea19227d1778a7880d91843084837f450a85c0013035505588001e0718000312c7340025143107c3f1e39c5515151621712018f7700112d81170956 330d3b1af86533a032400724969268734f760a27f45001fc40174422188a161d2b20289007145394e66022a840575b320200f8407e833275018515844490ad0274093119b1a8010367323f2135ad8338806974bdcf944424070b0100c95446014320023a08347f77b21f31872f09139552112c417007140f63fcb520a4112016
13020005794534d3241ab897b0d1bd287c0020012b01f0008d4b05418a400af2271362259c660a090391020222c0df12e86b3440000584050c5637072006bf05e801b465c2621967083d0b0398115119a8a3035b04210310cba70b9aa852730f100d307b00062fb003b20767442823f233303082432338c029c70e761c381418 0295260120027224b5b87554902044101506154406128150c06446423260ca5002317a18f37405043057165158a6084708c515050021be292a811208283572c826a2810977302ec94a55ff919502b2a33442144b74715544716219300212f37011e813c08fd56608a386131e44f220902515151bc569b305210218c1e545826c
0802150300df070980c19b3745ea37f075717622a530a08765450627000082080a0054706b6695b73832b009290054e7001c98404c2be41203aa5d07675526e306a49c50e220e7350148d085070623116528350f05003090f21400007d0047c035240273124800700339218809070000b43005252e00371000840c048e01ea20 4d34323500a9431391130198127276500440b220a1422b6b58b6a6367635e10b61808b7002313e52053a146635275f70118a2339ba62046d760b5000d3bd0012687814013f87a2a306831030325632662132df101a5135900a7f1b3300e00860033081ec4010c00204b14440037253060c2451d45409e76d349560b2593b3365
84000d5530c12756ac1d93d0d5c060c70004d0106720b8c800b0d8e0038000504108d78577810481533ba0f0c804000c07005205760000b85002f76081e1020f00d0d01e9a14224e1e4078186105860002404003070950000090001f430910009b0300290de050d6d02077c01400f00400048d00e050060c500c87060000020d 32459905b00864008c262420078270533013221a930d612db04c05a42fb620419293885f24e59110d0005c320075cd4841a019089c63f521d6b8c92babf6430b48030084324d0025af206b02e0300bf8854a07666b0423108028201456180b4216287129020549401639a610ba03231030662131c41543d3b070208d0a123230
00c0006540d290002100586000a0d00d00b14a00000a00f044f9002800600003a0400af00b0409580d040070670c0005000009e805000000200000070000080678000300600009000b00d06000000f0d77e0000000000400c000009610d00000000000a050000000000000080000a0d0000a60d805000000080000026000b000 71431b689680b02410030f304bfb6684a31fc6017605041745581335b0749863260429ad11e061ed6e25a287895137ef20b21260418041d2a04408aa5b960a230a1b522000b325e270a090811741436d45572801621c4496bd57895524875309220b5187209a1b20519b253842509224b56812a2910935501f1d040a008a2460
00000060c0e000000000000080500004000009e0000306000000000000000000000706700000000050d0600000906000b00000900c0000000000030d00c0050000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 155508248600254795b5b16ea19227d1778a7880d91843084837f450a85c0013035505588001e0718000312c7340025143107c3f1e39c5515151621712018f7700112d8117095613020005794534d3241ab897b0d1bd287c0020012b01f0008d4b05418a400af2271362259c660a090391020222c0df12e86b3440000584050c
5637072006bf05e801b465c2621967083d0b0398115119a8a3035b04210310cba70b9aa852730f100d307b00062fb003b20767442823f233303082432338c029c70e761c3814180802150300df070980c19b3745ea37f075717622a530a08765450627000082080a0054706b6695b73832b009290054e7001c98404c2be41203
aa5d07675526e306a49c50e220e7350148d085070623116528350f05003090f21400007d0047c035240273124800700339218809070000b43005252e00371000840c048e01ea2084000d5530c12756ac1d93d0d5c060c70004d0106720b8c800b0d8e0038000504108d78577810481533ba0f0c804000c07005205760000b850
02f76081e1020f00d0d01e9a14224e1e4078186105860002404003070950000090001f430910009b0300290de050d6d02077c01400f00400048d00e050060c500c87060000020d00c0006540d290002100586000a0d00d00b14a00000a00f044f9002800600003a0400af00b0409580d040070670c0005000009e80500000020
0000070000080678000300600009000b00d06000000f0d77e0000000000400c000009610d00000000000a050000000000000080000a0d0000a60d805000000080000026000b00000000060c0e000000000000080500004000009e0000306000000000000000000000706700000000050d0600000906000b00000900c00000000
00030d00c0050000090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

View File

@ -1,16 +1,17 @@
progression={ progression={
ruleset:new(11,5,10,25),
-- level 1 -- level 1
-- ruleset:new(5,1,9,0), ruleset:new(5,1,9,0), -- by test: always winnable
-- level 2 -- level 2
-- ruleset:new(5,2,9,0), ruleset:new(5,2,9,0), -- by test: always winnable
-- level 3 -- level 3
-- ruleset:new(7,2,9,8), ruleset:new(7,2,9,8), -- by test: always winnable
-- level 4 (first challenging) -- level 4 (first challenging)
-- ruleset:new(9,3,9,16), ruleset:new(9,3,9,16, "l4"),
-- level 5 -- level 5
-- ruleset:new(9,3,11,18), ruleset:new(9,3,11,18, "l5"),
-- fortune's foundation -- fortune's foundation
ruleset:new(11,4,13,22,"seeds_ff") ruleset:new(11,4,13,22,"ff"),
-- harder than fortune's foundation -- harder than fortune's foundation
-- ruleset:new(11,5,10,25) ruleset:new(11,5,10,25)
} }

View File

@ -83,24 +83,32 @@ function ruleset:generate_deck()
if (rank==0 or rank==self.n_arcana-1) deck.instantly_accepted[#deck.cards]=true if (rank==0 or rank==self.n_arcana-1) deck.instantly_accepted[#deck.cards]=true
end end
function deck:draw_card(x,y,c,shadow) function deck:draw_card(x,y,c,special)
if special.rotate then
camera(0,-64)
poke(0x5f55,0x00)
else
camera(-x,-y)
end
local meta=deck.cards[c] local meta=deck.cards[c]
local is_extreme=meta.rank==0 or meta.rank==ruleset.n_arcana-1 local is_extreme=meta.rank==0 or meta.rank==ruleset.n_arcana-1
local s,fg local s,fg
local bg,shadowbg local bg
if meta.suit=='a' or meta.suit=='b' then if meta.suit=='a' or meta.suit=='b' then
bg,shadowbg=1,1 bg=1
if (shadow) bg,shadowbg=1,1 if (is_extreme) bg=15
if (is_extreme) bg,shadowbg=15,15
else else
bg,shadowbg=7,7 bg=7
--if (shadow) bg,shadowbg=7,6 end
if special.shadowed then
if (bg==1) bg=4
if (bg==7) bg=6
end end
rectfill(x,y,x+8,y+4,bg) rectfill(0,0,8,15,bg)
rectfill(x,y+5,x+8,y+15,shadowbg)
if (meta.suit=='p') s,fg=0,4 if (meta.suit=='p') s,fg=0,4
if (meta.suit=='s') s,fg=1,12 if (meta.suit=='s') s,fg=1,12
@ -113,23 +121,38 @@ function ruleset:generate_deck()
local rank=""..meta.rank local rank=""..meta.rank
pal(7,15) pal(7,15)
if (is_extreme) pal(7,1) if (is_extreme) pal(7,1)
print(meta.rank,x+5-#rank*2,y+1,7) print(meta.rank,5-#rank*2,1,7)
spr(5,x,y+8) spr(5,0,8)
pal() pal()
else else
local name=sub(deck.rank_name,meta.rank,meta.rank) local name=sub(deck.rank_name,meta.rank,meta.rank)
local x2=x local x2=0
if (meta.suit=='b') x2+=1 if (meta.suit=='b') x2+=1
rectfill(x,y,x+3,y+6,fg) rectfill(0,0,3,6,fg)
print(name,x2,y+1,bg) print(name,x2,1,bg)
pal(7,fg) pal(7,fg)
spr(s,x+4,y) spr(s,4,0)
if not shadow then spr(15+meta.rank,0,8)
spr(15+meta.rank,x,y+8)
end
pal() pal()
end end
camera()
if special.rotate then
poke(0x5f55,0x60)
mset(0,0,128)
mset(1,0,129)
mset(0,1,144)
mset(1,1,145)
x-=3
y+=7
for sx=0,8 do
for sy=0,15 do
tline(x+sy,y+sx,x+sy,y,(0)/8,sy/8,1/8,0)
end
end
tline()
end
return fg return fg
end end
end end
@ -158,7 +181,7 @@ function ruleset:generate_layouts()
local sx=(i-1)*10 local sx=(i-1)*10
return layout:new(x+sx,18,layout_mode.vertical) return layout:new(x+sx,18,layout_mode.vertical)
end end
if (i==ruleset.n_slots+1) return layout:new(x+width-ruleset.n_suits*5-5,1,layout_mode.obscured) if (i==ruleset.n_slots+1) return layout:new(x+width-ruleset.n_suits*5-5,1,layout_mode.rotated)
assert(false, "unknown slot") assert(false, "unknown slot")
end end
end end

View File

@ -3,14 +3,42 @@ import struct
import zlib import zlib
def main(): def main():
# No need to store any seeds for level 2 or 3: all 5000 of the first 5000 seeds are fine
# We could use negencode_delta_4b, which is pretty uneventful
# level_1 = load_seeds("input/level_1.txt")[:5000]
# analyze(level_1)
# level_2 = load_seeds("input/level_2.txt")[:5000]
# analyze(level_2)
# level_3 = load_seeds("input/level_3.txt")[:5000]
# analyze(level_3)
level_4 = load_seeds("input/level_4.txt")[:5000]
# analyze(level_4)
level_5 = load_seeds("input/level_5.txt")[:5000]
# analyze(level_5)
ff = load_seeds("input/fortunes_foundation.txt") ff = load_seeds("input/fortunes_foundation.txt")
# analyze(ff)
ffdata = delta_4b(ff) # level_7 = load_seeds("input/level_7.txt")[:5000]
# analyze(level_7)
augment_map("../main.p8", "../seed_constants.lua", ffdata, { level_4_data = negencode_16b(level_4)
"ffdata_start": 0, level_5_data = negencode_delta_4b(level_5)
"ffdata_end": len(ffdata), ff_data = delta_4b(ff)
})
all_data = b""
offsets = {}
for block, data in [
("l4", level_4_data),
("l5", level_5_data),
("ff", ff_data)
]:
offsets[f"{block}_start"] = len(all_data)
all_data += data
offsets[f"{block}_end"] = len(all_data)
augment_map("../main.p8", "../seed_constants.lua", all_data, offsets)
def augment_map(target, constants_file, binary, offsets): def augment_map(target, constants_file, binary, offsets):
@ -58,13 +86,21 @@ def analyze(seeds):
print("{} seeds".format(len(seeds))) print("{} seeds".format(len(seeds)))
for encoding in [ for encoding in [
naive, delta_8b, delta_3b, delta_4b, delta_5b, zlib_delta_4b, zlib_delta_8b naive, bitfield, delta_8b, delta_2b, delta_3b, delta_4b, delta_5b, zlib_delta_4b, zlib_delta_8b,
negencode_delta_4b, negencode_16b,
]: ]:
print("{} encoding: {} bytes".format(encoding.__name__, len(encoding(seeds)))) print("{} encoding: {} bytes".format(encoding.__name__, len(encoding(seeds))))
def naive(seeds): def naive(seeds):
return b"".join(struct.pack("<I", s) for s in seeds) return b"".join(struct.pack("<I", s) for s in seeds)
def bitfield(seeds):
mx = max(seeds)
out = bytearray((mx+7)//8)
for s in seeds:
out[s // 8] |= 1 << (s % 8)
return bytes(out)
def delta_8b(seeds): def delta_8b(seeds):
out = b"" out = b""
acc = 0 acc = 0
@ -110,6 +146,9 @@ def delta_4b(seeds):
def zlib_delta_4b(seeds): def zlib_delta_4b(seeds):
return zlib.compress(delta_4b(seeds)) return zlib.compress(delta_4b(seeds))
def delta_2b(seeds):
return delta_nb(seeds, 2)
def delta_3b(seeds): def delta_3b(seeds):
return delta_nb(seeds, 3) return delta_nb(seeds, 3)
@ -151,6 +190,26 @@ def delta_nb(seeds, n):
out += bytes(chunk_bytes) out += bytes(chunk_bytes)
return out return out
def negencode_delta_4b(seeds):
mx, new = negencode(seeds)
return struct.pack("<H", mx) + delta_4b(new)
def negencode_16b(seeds):
mx, new = negencode(seeds)
out = b""
out += struct.pack("<H", mx)
for i in new:
out += struct.pack("<H", i)
return out
def negencode(seeds):
mn = 0
mx = max(seeds) + 1
everyone = set(range(mn, mx))
for i in seeds:
everyone.remove(i)
return mx, sorted(everyone)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,8 @@
seed_constants={ seed_constants={
ffdata_start=4096, l4_start=4096,
ffdata_end=10434 l4_end=4138,
l5_start=4138,
l5_end=4679,
ff_start=4679,
ff_end=11017
} }

View File

@ -1,25 +1,54 @@
seeds={} seeds={}
add(modules,seeds) add(modules,seeds)
function seeds:init() function seeds:init()
self.seeds_ff=seed_pool:new(seed_constants.ffdata_start,seed_constants.ffdata_end) self.l4=seed_pool:new(seed_constants.l4_start,seed_constants.l4_end,_naive_16b,true)
self.l5=seed_pool:new(seed_constants.l5_start,seed_constants.l5_end,_delta_4b,true)
self.ff=seed_pool:new(seed_constants.ff_start,seed_constants.ff_end,_delta_4b)
end end
function seeds:choose(pool) function seeds:choose(pool)
if (pool) return rnd(self[pool].seeds) if (pool) return self[pool]:choose()
return rnd(0xffff.ffff) return rnd(5000>>16)
end end
seed_pool=klass() seed_pool=klass()
function seed_pool:init(addr_start,addr_end,routine,negencode)
function seed_pool:init(addr_start,addr_end) if (negencode) self.neg_max=(%addr_start)>>16 addr_start+=2
local seeds={} local seeds={}
routine(seeds,addr_start,addr_end)
self.seeds=seeds
self.is_seed={}
for s in all(seeds) do
self.is_seed[s] = true
end
end
function seed_pool:choose()
if self.neg_max then
while true do
local r = rnd(self.neg_max)
if (not self.is_seed[r]) return r
end
end
return rnd(self.seeds)
end
function _delta_4b(seeds,s,e)
local acc=0 local acc=0
while addr_start < addr_end do while s < e do
local byte=@addr_start local byte=@s
local nb0=byte>>20 local nb0=byte>>20
local nb1=(byte&0xf)>>16 local nb1=(byte&0xf)>>16
if nb0==0 then acc+=0x0.000f else acc+=nb0 add(seeds,acc) end if nb0==0 then acc+=0x0.000f else acc+=nb0 add(seeds,acc) end
if nb1==0 then acc+=0x0.000f else acc+=nb1 add(seeds,acc) end if nb1==0 then acc+=0x0.000f else acc+=nb1 add(seeds,acc) end
addr_start+=1 s+=1
end
end
function _naive_16b(seeds,s,e)
while s < e do
add(seeds,%s)
s+=2
end end
self.seeds=seeds
end end

854
simulator/level_7.txt Normal file
View File

@ -0,0 +1,854 @@
81
11
124
76
10
111
128
63
106
136
50
150
6
152
74
27
113
91
171
18
167
16
125
51
148
198
93
146
200
219
196
83
177
14
237
36
262
239
276
169
285
138
242
241
259
299
302
279
182
166
191
159
306
255
320
309
295
328
313
373
269
348
340
388
286
354
428
382
398
322
441
343
469
319
453
488
456
520
525
414
508
361
529
527
521
494
569
563
417
580
589
594
614
605
422
596
505
593
676
511
682
660
413
512
483
716
722
731
629
696
741
445
743
683
688
706
771
734
773
647
778
789
752
612
764
820
622
689
814
833
793
797
863
737
767
742
738
795
816
772
897
928
879
940
949
882
934
960
957
968
973
780
864
962
976
899
982
1019
919
931
936
1009
1033
905
1034
1026
1068
1014
1015
1029
1097
975
1104
1032
1059
1040
1089
1125
1147
1126
1061
1167
1062
1148
1055
1145
1094
1215
817
1098
1186
1211
1177
1196
1239
1235
1245
1225
1263
1237
955
1163
1217
1194
1202
1276
1334
1252
1150
1191
1285
1368
1336
1328
1332
1370
1384
1376
1400
1341
1244
1288
1379
1262
1427
1236
1457
1248
1473
1466
1475
1472
1436
1428
1495
1286
1504
1509
1483
1453
1476
1317
1479
1511
1350
1535
1357
1529
1505
1555
1542
1559
1563
1576
1581
1525
1577
1603
1607
1630
1619
1546
1450
1524
1435
1669
1647
1597
1689
1629
1566
1677
1705
1701
1624
1402
1676
1642
1723
1719
1743
1611
1711
1679
1745
1782
1627
1779
1765
1716
1750
1807
1812
1653
1776
1728
1831
1731
1801
1784
1848
1832
1783
1826
1878
1706
1790
1791
1746
1862
1896
1828
1872
1903
1915
1921
1906
1947
1931
1919
1930
1936
1833
1841
1968
1645
1994
1997
1954
1970
1979
2016
1913
1957
2034
1898
2004
1927
2061
2044
1834
2068
2079
1987
1870
1953
2096
2078
2101
2106
1965
1958
2134
1969
2029
2139
2092
1961
2128
2123
2140
2064
2062
2071
2067
2195
2102
2200
2148
2111
2023
2138
2223
2165
2232
2115
2247
2112
2157
2257
2118
2206
2229
2191
2171
2268
2302
2283
2221
2331
2094
2318
2289
2186
2250
2350
2170
2243
2366
2337
2193
2286
2303
2400
2377
2332
2358
2227
2336
2253
2166
2404
2262
2093
2413
2202
2440
2371
2457
2379
2429
2491
2402
2238
2405
2315
2502
2431
2465
2531
2326
2519
2419
2430
2569
2533
2596
2602
2471
2616
2554
2590
2517
2560
2548
2407
2643
2580
2618
2498
2619
2617
2650
2334
2641
2689
2706
2685
2585
2717
2658
2644
2695
2744
2578
2687
2672
2768
2661
2651
2772
2669
2620
2795
2770
2787
2761
2629
2813
2851
2854
2725
2800
2888
2900
2844
2625
2897
2815
2934
2940
2942
2937
2947
2834
2846
2825
2830
2624
2777
2980
2747
2906
2871
3006
2956
3051
3090
3048
3065
3088
2977
2941
2912
3025
3062
3103
3133
3086
2960
3153
3127
3165
3137
3147
3008
3177
3123
3110
2976
3197
3015
3164
3144
3035
3221
3225
3207
3224
3237
2982
3239
3240
3248
3097
3182
3186
3161
3099
2966
3264
3091
3256
3202
3293
3265
3272
3252
3298
3310
3228
3227
3297
3322
3320
3365
3234
3350
3332
3187
3307
3409
3226
3413
3418
3391
3430
3294
3397
3323
3438
3436
3315
3433
3398
3449
3302
3480
3530
3481
3304
3493
3541
3511
3574
3479
3576
3412
3411
3231
3510
3598
3572
3437
3335
3374
3582
3593
3619
3620
3590
3609
3667
3683
3607
3669
3484
3497
3546
3725
3628
3726
3738
3514
3723
3526
3727
3766
3748
3767
3779
3785
3661
3761
3824
3729
3812
3708
3854
3808
3595
3835
3827
3801
3858
3823
3886
3883
3512
3861
3860
3897
3863
3874
3876
3912
3906
3901
3909
3744
3895
3869
3787
3962
3934
3961
3960
3993
3859
3942
3917
3976
3868
4010
3923
4031
3935
4058
3978
4062
3956
3933
4028
4013
4018
3952
4083
4089
4066
4116
4132
4021
3815
4006
4153
4093
3924
4047
4024
4057
4001
4165
4180
4072
3926
4172
4161
4197
4192
4098
4052
4157
4224
3982
4202
4191
4080
4234
4252
4228
4048
4269
4272
4243
3991
4214
4246
4245
4271
4050
4320
4336
4285
4355
4357
4262
4248
4338
4315
4302
4343
4291
4385
4388
4280
3990
4389
4342
4383
4353
4423
4288
4427
4365
4409
4459
4467
4421
4477
4151
4370
4502
4511
4481
4528
4494
4446
4547
4533
4537
4323
4554
4555
4491
4593
4538
4562
4536
4603
4619
4553
4639
4573
4514
4646
4664
4665
4581
4655
4673
4647
4405
4683
4731
4607
4703
4699
4745
4742
4739
4755
4782
4557
4776
4800
4766
4701
4762
4829
4852
4738
4773
4788
4728
4756
4862
4859
4860
4718
4877
4689
4903
4879
4865
4925
4844
4888
4770
4929
4956
4957
4858
4961
4857
4924
4861
4878
4962
4909
4883
4993
4967
4991
5004
5021
5039
4893
4975
5019
4936
5060
5002
5046
5015

View File

@ -1,4 +1,4 @@
use std::{borrow::Borrow, fs::File, io::Write, sync::{Arc, Mutex}}; use std::{fs::File, io::Write, sync::{Arc, Mutex}};
use board::Board; use board::Board;
use ruleset::Ruleset; use ruleset::Ruleset;
@ -16,28 +16,7 @@ mod zobrist;
fn main() { fn main() {
/* /*
let mut rng = PicoRng::srand(0x20000); let filename = "level_1.txt";
for _ in 0..10 {
println!("{}", rng.rnd(0x10000));
}
return;
*/
/*
let ruleset = Ruleset {
n_slots: 11,
n_suits: 5,
n_cards_per_suit: 10,
n_arcana: 25
};
*/
let ruleset = Ruleset {
n_slots: 11,
n_suits: 4,
n_cards_per_suit: 13,
n_arcana: 22
};
/*
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 5, n_slots: 5,
n_suits: 1, n_suits: 1,
@ -46,6 +25,16 @@ fn main() {
}; };
*/ */
/* /*
let filename = "level_2.txt";
let ruleset = Ruleset {
n_slots: 5,
n_suits: 2,
n_cards_per_suit: 9,
n_arcana: 0
};
*/
/*
let filename = "level_3.txt";
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 7, n_slots: 7,
n_suits: 2, n_suits: 2,
@ -54,37 +43,61 @@ fn main() {
}; };
*/ */
/* /*
let filename = "level_4.txt";
let ruleset = Ruleset {
n_slots: 9,
n_suits: 3,
n_cards_per_suit: 9,
n_arcana: 16
};
*/
/*
let filename = "level_5.txt";
let ruleset = Ruleset { let ruleset = Ruleset {
n_slots: 9, n_slots: 9,
n_suits: 3, n_suits: 3,
n_cards_per_suit: 11, n_cards_per_suit: 11,
n_arcana: 18 n_arcana: 18
};
*/
/*
let filename = "fortunes_foundation.txt";
let ruleset = Ruleset {
n_slots: 11,
n_suits: 4,
n_cards_per_suit: 13,
n_arcana: 22
}; };
*/ */
let filename = "level_7.txt";
let ruleset = Ruleset {
n_slots: 11,
n_suits: 5,
n_cards_per_suit: 10,
n_arcana: 25
};
let setup = ruleset.compile().expect("compilation should succeed"); let setup = ruleset.compile().expect("compilation should succeed");
/*
for _ in 0..10000 {
Deal::deal(&setup, &mut rand::thread_rng());
}
*/
const THREADS: usize = 28; const THREADS: usize = 28;
let winnable_seeds_file = Arc::new(Mutex::new(File::create("winnable_seeds_multithreaded.txt").expect("should be able to create"))); let work_source: WorkSource = WorkSource::new(0);
let winnable_seeds_file = Arc::new(Mutex::new(File::create(filename).expect("should be able to create")));
let mut threads = Vec::new(); let mut threads = Vec::new();
for i in 0..THREADS { for _ in 0..THREADS {
let setup2 = setup.clone(); let setup2 = setup.clone();
let source = work_source.clone();
let wsf = winnable_seeds_file.clone(); let wsf = winnable_seeds_file.clone();
threads.push(std::thread::spawn(move || { threads.push(std::thread::spawn(move || {
winnable_seeds_thread( winnable_seeds_thread(
&setup2, &setup2,
source,
|seed| { |seed| {
let mut f = wsf.lock().expect("must be able to lock"); let mut f = wsf.lock().expect("must be able to lock");
write!(f, "{}\n", seed).expect("write should succeed"); write!(f, "{}\n", seed).expect("write should succeed");
f.flush().expect("flush should succeed"); f.flush().expect("flush should succeed");
}, },
i as u32,
THREADS as u32
); );
})); }));
} }
@ -95,11 +108,31 @@ fn main() {
} }
fn winnable_seeds_thread(setup: &ruleset::Setup, mut cb: impl FnMut(u32), start: u32, step: u32) { #[derive(Clone)]
struct WorkSource {
seed: Arc<Mutex<Option<u32>>>
}
impl WorkSource {
fn new(seed: u32) -> Self {
return WorkSource { seed: Arc::new(Mutex::new(Some(seed))) }
}
fn take(&self) -> Option<u32> {
let mut self_seed = self.seed.lock().expect("shouldn't have panicked");
if let Some(seed) = *self_seed {
*self_seed = seed.checked_add(1);
return Some(seed);
}
return None
}
}
fn winnable_seeds_thread(setup: &ruleset::Setup, source: WorkSource, mut cb: impl FnMut(u32)) {
let mut winnable = 0; let mut winnable = 0;
let mut total = 0; let mut total = 0;
for seed in (start..0xffffffff).step_by(step as usize) { while let Some(seed) = source.take() {
let mut board = Board::new(&setup); let mut board = Board::new(&setup);
board.deal(Deal::deal(&setup, seed)); board.deal(Deal::deal(&setup, seed));
board.display(); board.display();

View File

@ -10832,3 +10832,109 @@
85247 85247
92829 92829
91669 91669
97597
85443
84931
91729
88458
92969
95686
86653
88570
86989
79762
87578
90767
89826
86559
90667
89319
89598
85609
89626
89416
88794
90134
87662
97716
91243
92688
86171
96000
93473
79902
86671
87690
97877
86923
89767
86057
93557
92638
90891
90919
89823
90883
89822
89878
92881
84476
92722
92513
92716
84588
94005
98017
89836
90088
94145
90172
90995
92597
97884
90312
80182
88850
80294
81556
84840
96140
91753
80434
90974
91087
91809
94453
98024
87129
81948
82004
91271
86197
91311
90718
85323
87157
92793
92905
91977
94789
94817
85407
96224
98248
91479
88082
85631
91535
91591
85064
82200
98500
89102
98640
80518
82312
82480
89158
96308

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff