--!name Mancala
--!icon game
--!category Games
local aY,aV,aX="ABCDEFGHIJK","LMNOPQRSTUV","abcdefghijk"local f,k={},{}for a=1,14*24 do f[a]=0 end for a=0,13 do k[a]=0 end local aD,aZ=0,0 local function az(l,d,a)local h=l+14 for b=0,13 do f[h+b]=f[l+b]end local e=f[h+a]f[h+a]=0 local aR,al=13,6 if d==1 then aR,al=6,13 end local m=a while e>0 do m=m+1 if m==14 then m=0 end if m~=aR then f[h+m]=f[h+m]+1 e=e-1 end end local q,I=1-d,0 if m==al then q=d elseif f[h+m]==1 and(d==0 and m<6 or d==1 and m>6)then local aM=h+12-m local p=f[aM]if p>0 then I=p+1 f[h+al]=f[h+al]+I f[h+m]=0 f[aM]=0 end end local g,o=0,0 for b=h,h+5 do g=g+f[b]end for b=h+7,h+12 do o=o+f[b]end if g==0 or o==0 then aD,aZ=g,o f[h+6]=f[h+6]+g f[h+13]=f[h+13]+o for b=0,5 do f[h+b]=0;f[h+7+b]=0 end return-1,I,m end return q,I,m end local X,Z=1000000,100000 local af,aJ,M,V,aU=0,0,false,0,330 local function bb()af=af+1 if af>aJ then M=true end V=V+1 if V>=aU then V=0;coroutine.yield()end end local function a1(l,d)local g,o=0,0 for b=l,l+5 do g=g+f[b]end for b=l+7,l+12 do o=o+f[b]end local i=(f[l+6]-f[l+13])*4+g-o if d==1 then i=-i end return i end local function aG(l,d)local x=f[l+6]-f[l+13]if d==1 then x=-x end if x>0 then return Z+x elseif x<0 then return-Z+x end return 0 end local function aj(l,d,P,w,ap)bb()if M then return 0 end if P<=0 then return a1(l,d)end local s,T,h=-X,d*7,l+14 for a=T+5,T,-1 do if f[l+a]>0 then local q=az(l,d,a)local i if q<0 then i=aG(h,d)elseif q==d then i=aj(h,d,P-1,w,ap)else i=-aj(h,q,P-1,-ap,-w)end if M then return 0 end if i>s then s=i if i>w then w=i if i>=ap then break end end end end end return s end local aW={{1,100,10},{4,2500,3},{18,5000,0}}local ao={"Easy","Medium","Hard"}local n={}local function bc(ad,d)local aA=aW[ad]local F={}for a=1,#n do F[a]=n[a]end local e=#F if e==0 then return nil end if e==1 then return F[1]end if ad==1 and math.random(10)<=3 then return F[math.random(e)]end for b=0,13 do f[1+b]=k[b]end af,aJ,M,V=0,aA[2],false,0 local s,ag=F[1],aA[3]for P=1,aA[1]do local w,ac,aE=-X,nil,1 for a=1,e do local E=F[a]local q=az(1,d,E)local i if q<0 then i=aG(15,d)elseif q==d then i=aj(15,d,P-1,w-ag,X)else i=-aj(15,q,P-1,-X,ag-w)end if M then break end if ag>0 then i=i+math.random(0,ag)end if i>w then w,ac,aE=i,E,a end end if ac then s=ac table.remove(F,aE)table.insert(F,1,ac)end if M or w>Z//2 or w<-Z//2 then break end end return s end local v,L,Y,G={},{},{},{}local y,r,Q,aC=0,nil,"",-1 local j,J,t,C,ab,R,O=1,0,2,4,4,false,false local S={0,0,0,0,0,0,0,0,0}local ah,aI=false,-1 local function an(d)if j==1 then return d==0 and"You"or"Computer"end return d==0 and"Player 1"or"Player 2"end local function aw()for a=0,13 do k[a]=(a==6 or a==13)and 0 or ab end y=j==1 and J or 0 v,L,Y,G={},{},{},{}Q,r,aC,ah,aI="",nil,-1,false,-1 end local function a4(a)return a<6 and a+1 or a-6 end local function au(a)local d=y for b=0,13 do f[1+b]=k[b]end local e=k[a]local q,I,m=az(1,d,a)for b=0,13 do k[b]=f[15+b]end v[#v+1]=a L[#L+1]=d aI=m if aC~=d then G,Y,aC={},{},d end Y[a]=true local c="pit "..a4(a)if q==d then c=c.." - extra turn"elseif I>0 then c=c.." - captured "..I end G[#G+1]=c local U=an(d).." sowed "..table.concat(G,", then ")local b=1 while#U>95 and b<#G do b=b+1 U=an(d).." sowed ... "..table.concat(G,", then ",b)end Q=U if q<0 then ah=true local aF=aD>0 and 1 or 0 local a5=j==2 and an(aF).."'s"or(aF==0 and"Your"or"Computer's")Q=Q:sub(1,70)..". "..a5.." row is empty"else y=q end return e end local function aP(b)if j~=1 or O then return end O=true local a=(t-1)*3+b S[a]=S[a]+1 end local function K()n={}r=nil if ah then local g,o=k[6],k[13]local ax=math.max(g,o).."-"..math.min(g,o)if g==o then r="Draw "..ax aP(3)elseif j==1 then r=(g>o and"You win "or"Computer wins ")..ax aP(g>o and 1 or 2)else r=(g>o and"Player 1"or"Player 2").." wins "..ax end return end local T=y*7 for a=T,T+5 do if k[a]>0 then n[#n+1]=a end end end local function a8()local c={"K1",j,J,t,ab,O and 1 or 0,table.concat(S,","),":"}for a=1,#v do c[#c+1]=v[a]%7 end return table.concat(c)end local function aQ()snail.save(a8())end local function av(D,e)aw()K()for a=1,e do local ai=D[a]if ah or not ai or ai<0 or ai>5 then break end local aN=y*7+ai if k[aN]==0 then break end au(aN)K()end K()end local function a6()local d=snail.load()if type(d)~="string"then return false end local ae,aq,ad,a7,a0,a9,aL=d:match("^K1(%d)(%d)(%d)(%d)(%d)([%d,]+):(%d*)$")if not ae then return false end local a=0 for i in a9:gmatch("%d+")do a=a+1;S[a]=tonumber(i)end j,J,t,C=tonumber(ae),tonumber(aq),tonumber(ad),tonumber(a7)if j<1 or j>2 then j=1 end if J>1 then J=0 end if t<1 or t>3 then t=2 end if C<3 or C>6 then C=4 end ab=C local D={}for b=1,#aL do D[b]=aL:byte(b)-48 end O=true av(D,#D)O=a0=="1"R=true return true end local N,am=nil,false local B,u,z="menu",1,2 local function aB()N,am=nil,false snail.tick(0)end local ak local function aS()am=true local d=y N=coroutine.create(function()return bc(t,d)end)snail.after(ak)snail.tick(450)end local function ar()return not r and not am and(j==2 or y==0)end local function aa(a)return a<6 and a+1 or 13-a end local function as(a)for b=1,#n do if n[b]==a then return true end end return false end local function aH()if as(z)or#n==0 then return end local p,s,H=aa(z),nil,nil for b=1,#n do local x=math.abs(aa(n[b])-p)if not H or x<H then s,H=n[b],x end end z=s end local function _()aQ()if not r and j==1 and y==1 then aS()else aH()end end ak=function()if not N then return end local a3,E=coroutine.resume(N)if coroutine.status(N)~="dead"then return end aB()if not a3 or not E or not as(E)then av(v,#v)E=n[math.random(#n)]end if not E then return end au(E)K()_()end local function at(ae,aq)aB()j,J,ab,R,O=ae,aq,C,true,false aw()K()z=2 B="play"_()end local function aT()local e=#v if j==1 then while e>0 and L[e]~=0 do e=e-1 end end if e==0 then return nil end local d=L[e]while e>1 and L[e-1]==d do e=e-1 end return e-1 end local function bd()local e=aT()if not e then return end aB()local D={}for a=1,e do D[a]=v[a]%7 end av(D,e)B="play"_()end local function aK()local c={}if R then c[#c+1]={"Back to the game","resume"}end c[#c+1]={"New game, you go first","f"}c[#c+1]={"New game, computer first","c"}c[#c+1]={"New game, two players","2"}c[#c+1]={"Computer level: "..ao[t],"lvl"}c[#c+1]={"Seeds per pit: "..C,"seeds"}if R and aT()then c[#c+1]={"Take back a move","undo"}end return c end function key(b)if B=="menu"then local A=aK()if u>#A then u=#A end local g=A[u][2]if b=="up"then u=(u-2)%#A+1 elseif b=="down"then u=u%#A+1 elseif b=="ok"or((b=="left"or b=="right")and(g=="lvl"or g=="seeds"))then if g=="resume"then B="play"elseif g=="f"then at(1,0)elseif g=="c"then at(1,1)elseif g=="2"then at(2,0)elseif g=="lvl"then t=(t+(b=="left"and 1 or 0))%3+1 if R then aQ()end elseif g=="seeds"then C=(C-3+(b=="left"and 3 or 1))%4+3 elseif g=="undo"then bd()end end return end if b=="top"then B="menu";u=1;return end if r then if b=="ok"then B="menu";u=2 end return end if not ar()then return end if b=="ok"then if as(z)then au(z)K()_()end elseif b=="left"or b=="right"then local x=b=="left"and-1 or 1 local p=aa(z)local s,H for a=1,#n do local W=(aa(n[a])-p)*x if W<=0 then W=W+6 end if not H or W<H then s,H=n[a],W end end if s then z=s end end end function tick()ak()if N then snail.after(ak)end end local function aO(a)local e=k[a]if e>10 then e=10 end local ay=aY if a==z and ar()and B=="play"then ay=aV elseif Y[a]then ay=aX end return ay:sub(e+1,e+1)end local function a_()local c={" "}for p=1,6 do c[#c+1]="{"..k[13-p].."}"end c[#c+1]=" /W"for p=1,6 do c[#c+1]=aO(13-p)end c[#c+1]="W/{"..k[13].."}YYYYYY{"..k[6].."}/X"for p=1,6 do c[#c+1]=aO(p-1)end c[#c+1]="X/ "for p=1,6 do c[#c+1]="{"..k[p-1].."}"end c[#c+1]=" "return table.concat(c)end local function ba()local c if j==1 then c="You "..k[6].."  Computer "..k[13].." - "else c="P1 "..k[6].."  P2 "..k[13].." - "end if r then return c.."game over"end if am then return c.."thinking..."end if j==1 then return c.."your move"end return c..an(y).." to move"end function draw()if B=="menu"then snail.title("Mancala")local A=aK()if u>#A then u=#A end for a,a2 in ipairs(A)do snail.row(a2[1],a==u)end snail.gap()if R then local U=j==2 and"Two players"or("You go "..(J==0 and"first"or"second")..", "..ao[t])snail.small(U..(r and(". "..r..".")or(", "..#v..(#v==1 and" move"or" moves").." made.")))else snail.small("Sow seeds anticlockwise. Last seed in your store: go again; in an empty pit of yours: capture.")end local d=S snail.small("Won-lost-drawn against the computer:")snail.small("Easy "..d[1].."-"..d[2].."-"..d[3].."   Medium "..d[4].."-"..d[5].."-"..d[6].."   Hard "..d[7].."-"..d[8].."-"..d[9])snail.hint("BACK leave OK choose UP/DN move")return end snail.title(j==1 and("Mancala - "..ao[t])or"Mancala - two players")snail.status(ba())snail.text(Q~=""and Q or"Left and right pick a pit, OK sows it.")snail.board(a_(),nil,r)if j==1 then snail.small("Top row and left store: Computer. Bottom row and right store: you.")else snail.small("Player 1: bottom row, right store. Player 2: top row, left store.")end if r then snail.hint("BACK options OK new game")elseif not ar()then snail.hint("BACK options")else snail.hint("BACK options OK sow L/R pit")end end function start()math.randomseed(os.time())aw()K()if a6()then if not r then B="play"if j==1 and y==1 then aS()else aH()end end end end
