local Y=require("yaru.core") local gfx=require("yaru.gfx") local ui=require("yaru.ui") local unicode=require("unicode") local M={} local BEST="/home/.local/share/2048.best" local TILE={[2]={0xF0F0F0,0x5A5A5A},[4]={0xFFDBBF,0x5A5A5A},[8]={0xFFB680,0xFFFFFF},[16]={0xFF9240,0xFFFFFF}, [32]={0xFF6D40,0xFFFFFF},[64]={0xFF4900,0xFFFFFF},[128]={0xFFDB80,0xFFFFFF},[256]={0xFFDB40,0xFFFFFF}, [512]={0xFFB600,0xFFFFFF},[1024]={0xCCB600,0xFFFFFF},[2048]={0xE95420,0xFFFFFF}} function M.open() local st={} local win=Y.newWindow{app="g2048",title="2048",w=52,h=26,fixed=true} local function readBest()local f=io.open(BEST)local v=f and tonumber(f:read("*a"))if f then f:close()end return v or 0 end local function spawn() local free={} for i=1,16 do if st.g[i]==0 then free[#free+1]=i end end if#free>0 then st.g[free[math.random(#free)]]=math.random()<0.9 and 2 or 4 end end local function new() st.g,st.score,st.over,st.won={},0,false,false for i=1,16 do st.g[i]=0 end spawn();spawn() st.best=readBest() end local function line(i,k,dir) if dir=="left"then return(i-1)*4+k elseif dir=="right"then return(i-1)*4+5-k elseif dir=="up"then return(k-1)*4+i else return(4-k)*4+i end end local function move(dir) if st.over then return end local moved=false for i=1,4 do local vals={} for k=1,4 do local v=st.g[line(i,k,dir)]if v>0 then vals[#vals+1]=v end end local out,k={},1 while k<=#vals do if vals[k]==vals[k+1]then local v=vals[k]*2 out[#out+1]=v st.score=st.score+v if v==2048 and not st.won then st.won=true;Y.notify("2048!","You made the 2048 tile")end k=k+2 else out[#out+1]=vals[k];k=k+1 end end for k2=1,4 do local idx=line(i,k2,dir) local v=out[k2]or 0 if st.g[idx]~=v then moved=true end st.g[idx]=v end end if moved then spawn()end local any=false for i=1,16 do local v=st.g[i] if v==0 or(i%4~=0 and st.g[i+1]==v)or(i<=12 and st.g[i+4]==v)then any=true break end end if not any then st.over=true end if st.score>st.best then st.best=st.score require("filesystem").makeDirectory("/home/.local/share") local f=io.open(BEST,"w")if f then f:write(tostring(st.best))f:close()end end end function win.header(w,hw)ui.button(w,2,1,"New Game",new,"suggested")end function win.draw(w,cw,ch) local t=Y.theme ui.round(3,1,20,2,t.dark and 0x383838 or 0xDEDDDA) gfx.text(5,1,"SCORE",t.dim,t.dark and 0x383838 or 0xDEDDDA);gfx.text(5,2,tostring(st.score),t.fg,t.dark and 0x383838 or 0xDEDDDA) ui.round(cw-21,1,20,2,t.dark and 0x383838 or 0xDEDDDA) gfx.text(cw-19,1,"BEST",t.dim,t.dark and 0x383838 or 0xDEDDDA);gfx.text(cw-19,2,tostring(st.best),t.fg,t.dark and 0x383838 or 0xDEDDDA) local TW,TH=11,8 local ox,oy=(cw-4*(TW+1))//2+1,9 gfx.prrect(ox-1,oy-1,4*(TW+1)+1,4*(TH+1)+1,0x969696) for i=1,16 do local x,y=ox+((i-1)%4)*(TW+1),oy+((i-1)//4)*(TH+1) local v=st.g[i] local c=TILE[v]or(v>0 and{0x2D2D2D,0xFFFFFF})or{0xB4B4B4,0} gfx.prrect(x,y,TW,TH,c[1]) if v>0 then local r=y+3 if r%2==0 then r=r+1 end local s=tostring(v) gfx.text(x+(TW-#s)//2,(r+1)//2,s,c[2],c[1]) end end if st.over then local s=" Game over ยท press Enter " ui.pill((cw-#s-2)//2,15,#s+2,t.danger) gfx.text((cw-#s)//2,15,s,0xFFFFFF,t.danger) end end function win.key(w,char,code) local K=Y.K local c=(char and char>0 and char<128)and string.char(char):lower()or"" if code==K.left or c=="a"then move("left")elseif code==K.right or c=="d"then move("right") elseif code==K.up or c=="w"then move("up")elseif code==K.down or c=="s"then move("down") elseif code==K.enter and st.over then new()end end new() return win end return M