(Receive email notifications)
Yes! If you remember, back in January I had posted a code snippet that would let you play Minesweeper in the Picotron Playground. I later updated that snippet to have some comments describing the settings needed to recreate the three difficulty levels, but otherwise nothing changed. Well now, after months of (not that) hard (but still a little tricky) work, the third version of my Minesweeper game on Picotron is OUT! New features include:
- Easy windowed mode: Running the program will instantly switch to the desktop. No more faffing about with
run_program_inside_terminal
! Who wants to type that out every single time? - A help screen: Just click the handy little blue question mark (?) and you can reference the rules anytime. Also shows up the first time the program is run.
- In-game minefield customization: Nobody wants to edit the code every time just to change the difficulty. Nobody.
- Highscores: Though they can't be saved between sessions, they CAN be saved if you close the program and re-run it without refreshing the browser tab, and it should work on the executable version of Picotron when that's released.
- A screenshot button: Though it sucks and I wouldn't use it, since the BBS won't see colors #16-31 as anything other than black, so you can't post them here. :/
HOW TO GET STARTED
First, copy the following hidden block of code: (The -- end of program
line should be #702)
-- Minesweeper (v3) -- By: Kai -- Other things I might want to do: -- o Unique font for 7-seg displays? (Dunno how to use custom fonts on Picotron yet...) -- o Release to SPLORE. (When Picotron is released, obviously.) -- o Make the screenshot function return a PNG file instead? (If it's possible...) -- o Maybe online time submissions? (Again, if it's possible...) -- -- GFX decoder function decode(str) -- necessary so the forum doesn't screw up the code return userdata(chr(91,103,102,120,93)..str..chr(91,47,103,102,120,93)) end -- -- GFX: faces smile=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa00aa00aa065760aa00aa00aa065760aa00aa00aa065760aaaaaaaaaa065760aaaaaaaaaa065760aa0aaaa0aa0657660aa0000aa066576660aaaaaa06665766660000006666576666666666666656555555555555555" curious=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa00aa00aa065760aa00aa00aa065760aa00aa00aa065760aaaaaaaaaa065760aaaaaaaaaa065760aaaa00aaaa0657660aaa00aaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" frown=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760aa0aaaa0aa065760aaa0aa0aaa065760aa0aaaa0aa065760aaaaaaaaaa065760aaa0000aaa065760aa0aaaa0aa0657660aaaaaaaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" cool=decode"101077777777777777767666666666666665766660000006666576660aaaaaa066657660aaaaaaaa0665760a000aa000a0657600000000000065760a000aa000a065760aaaaaaaaaa065760aa0aaaa0aa065760aaa0000aaa0657660aaaaaaaa066576660aaaaaa06665766660000006666576666666666666656555555555555555" -- GFX: tiles boom=decode"08088888888m8686868m8855588m8656568m8855588m8686868m8888888mmmmmmmmm" block=decode"08087777776m7666665m7666665m7666665m7666665m7666665m6555555mmmmmmmmm" empty=decode"0808kkkkkkkmk444444mk444444mk444444mk444444mk444444mk444444mmmmmmmmm" flag=decode"08087777776m7668665m7688665m7888665m766i665m76iii65m6555555mmmmmmmmm" mine=decode"0808kkkkkkkmk646464mk455544mk656564mk455544mk646464mk444444mmmmmmmmm" falseflag=decode"08087777778m7662685m7622865m7228665m768i665m78iii65m8555555mmmmmmmmm" -- GFX: numbers numbercols={12,27,24,16,2,17,13,0} numbers={ decode"08080000000000770000000700000007000000070000007770000000000000000000", decode"08080000000000777000000070000077700000700000007770000000000000000000", decode"08080000000000777000000070000007700000007000007770000000000000000000", decode"08080000000000707000007070000077700000007000000070000000000000000000", decode"08080000000000777000007000000077700000007000007770000000000000000000", decode"08080000000000700000007000000077700000707000007770000000000000000000", decode"08080000000000777000000070000000700000007000000070000000000000000000", decode"08080000000000777000007070000077700000707000007770000000000000000000"} -- GFX: buttons wrench=decode"0808777777767666m6657666m665766mmmm576mmm6657m6m66657mm6666565555555" help=decode"08087777777676hhhh657hh6hhh57666hhh5766hh66576666665766hh66565555555" left=decode"0808777777767666mm65766mmm6576mmmm6576mmmm65766mmm657666mm6565555555" right=decode"08087777777676mm666576mmm66576mmmm6576mmmm6576mmm66576mm666565555555" pause=decode"08087777777676m66m6576m66m6576m66m6576m66m6576m66m6576m66m6565555555" fishhook=decode"08087777777676mmmm657m6666m5766666m576mm66m57m6mmm6576mm666565555555" unusable=decode"0808777777767o6666o576o66o65766oo665766oo66576o66o657o6666o565555555" cam=decode"080877777776766mm6657mmmmmm57mm66mm57mm66mm57mmmmmm57666666565555555" -- -- adjustables -- beginner: 9x9/10 -- intermediate: 16x16/40 -- expert: 30x16/99 -- WARNING!!! Setting the size of the minefield too high will cause Picotron to start -- flashing the screen, rendering the game virtually unplayable and pose a risk to those -- vulnerable to said flashing. User discretion is advised. -- DO NOT ADJUST as of v3. PLEASE keep these at 9x9/10 and -- use the in-game editor to change these. width=9 -- min: 9 | max: 59 height=9 -- min: 1 | max: 28 mines=10 -- idealy ~10-20% of total tiles -- -- other setup lmb=0 dead=false won=false start=true paused=false remainingmines=mines timer=0 set_window(width*8+1,height*8+20) cheatinput={} -- highscores setup highscores_txt=fetch"/best_minesweeper_times.txt" if not highscores_txt then highscores_txt="999,999,999\n999,999,999\n999,999,999" store("/best_minesweeper_times.txt",highscores_txt) first_time=true end highscores_arr=split(highscores_txt,"\n") for i=1,3 do this_diff=split(highscores_arr[i],",") for j=1,3 do this_diff[j]=tonumber(this_diff[j]) end highscores_arr[i]=this_diff end difficulty=1 -- -- data format: -- bit 0: mine -- bit 1: uncovered -- bit 2: flagged -- bit 3: UNUSED -- bit 4: UNUSED -- bit 5: UNUSED -- bit 6: UNUSED -- bit 7: UNUSED -- minefield=userdata("u8",width,height) -- -- debug: randomized test board --for x=0,width-1 do --for y=0,height-1 do --set(minefield,x,y,flr(rnd(2))) --end --end --dead=true -- /debug -- function place_mines(cx,cy) local goodcandidates={} local nearcandidates={} for x=0,width-1 do for y=0,height-1 do if abs(x-cx)>1 or abs(y-cy)>1 then add(goodcandidates,{x,y}) elseif x~=cx or y~=cy then add(nearcandidates,{x,y}) end end end for i=1,mines do --local position=candidates[flr(rnd(#candidates))+1] local position if #goodcandidates>0 then position=deli(goodcandidates,flr(rnd(#goodcandidates))+1) else position=deli(nearcandidates,flr(rnd(#nearcandidates))+1) end set(minefield,position[1],position[2],1) --del(candidates,position) end end -- function bit(n,b,c) if type(c)=="boolean" then return c and n|2^b or n&-1-2^b else return n&2^b>0 end end -- function uncover(tx,ty) if (bit(get(minefield,tx,ty),1)) return -- already uncovered if (bit(get(minefield,tx,ty),2)) return -- flagged if (tx<0 or tx>=width or ty<0 or ty>=height) return -- out of bounds set(minefield,tx,ty,get(minefield,tx,ty)+2) local nearbymine for xdelta=-1,1 do for ydelta=-1,1 do if (bit(get(minefield,tx+xdelta,ty+ydelta),0)) nearbymine=true end end if not nearbymine then for xdelta=-1,1 do for ydelta=-1,1 do local x=tx+xdelta local y=ty+ydelta if (x==mid(0,x,width-1) and y==mid(0,y,height-1) and not bit(get(minefield,x,y),1) and not bit(get(minefield,x,y),2)) uncover(x,y) end end elseif bit(get(minefield,tx,ty),0) then dead=true end end -- function checkwon() if (dead) return local coveredtiles=0 for x=0,width-1 do for y=0,height-1 do if (not bit(get(minefield,x,y),1)) coveredtiles+=1 end end if coveredtiles==mines then won=true remainingmines=0 local best_times=highscores_arr[difficulty] local score=flr(timer) rank=0 if cheatinput and difficulty>0 and score< best_times[3] then best_times[3]=score rank=3 if (best_times[3]< best_times[2]) best_times[3]=best_times[2] best_times[2]=score rank=2 if (best_times[2]< best_times[1]) best_times[2]=best_times[1] best_times[1]=score rank=1 --if (score< world_recoreds[difficulty]) rank="*" scoresub() -- world record! highscores_arr[difficulty]=best_times -- probably unnecessary highscores_txt=highscores_arr[1][1]..","..highscores_arr[1][2]..","..highscores_arr[1][3].."\n"..highscores_arr[2][1]..","..highscores_arr[2][2]..","..highscores_arr[2][3].."\n"..highscores_arr[3][1]..","..highscores_arr[3][2]..","..highscores_arr[3][3] rm"/best_minesweeper_times.txt" store("/best_minesweeper_times.txt",highscores_txt) end if (not cheatinput) rank="x" if (difficulty==0) rank="?" end end -- function draw_game() if (not (dead or won or start or paused)) timer=min(timer+1/60,999) local tx=(mx-1)\8 local ty=(my-20)\8 if tx==mid(0,tx,width-1) and ty==mid(0,ty,height-1) and not dead and not won and not paused then -- on grid if bit(mbp,0) and not bit(get(minefield,tx,ty),1) and not bit(get(minefield,tx,ty),2) then if (start) place_mines(tx,ty) start=false --set(minefield,tx,ty,bit(get(minefield,tx,ty),1,true)) uncover(tx,ty) checkwon() elseif bit(mbp,2) and not bit(get(minefield,tx,ty),1) and not start then set(minefield,tx,ty,get(minefield,tx,ty)^^4) remainingmines+=bit(get(minefield,tx,ty),2) and -1 or 1 elseif bit(mbp,1) and bit(get(minefield,tx,ty),1) then local closemines=0 local closeflags=0 for xdelta=-1,1 do for ydelta=-1,1 do if (bit(get(minefield,tx+xdelta,ty+ydelta),0)) closemines+=1 if (bit(get(minefield,tx+xdelta,ty+ydelta),2)) closeflags+=1 end end if closemines==closeflags then for xdelta=-1,1 do for ydelta=-1,1 do uncover(tx+xdelta,ty+ydelta) end end checkwon() end end elseif mx==mid(width*4-8,mx,width*4+7) and my==mid(2,my,17) and bit(mbp,0) then -- clicked on face -- reset puzzle dead=false won=false start=true paused=false remainingmines=mines timer=0 for x=0,width-1 do for y=0,height-1 do set(minefield,x,y,0) end end rank=nil elseif mx==mid(width*4+10,mx,width*4+17) and my==mid(6,my,13) and bit(mbp,0) then -- clicked on wrench if start then draw_function=draw_menu if (not (dead or won or start)) paused=true cheatinput={} elseif dead or won then -- screenshot function local screenshot=get_draw_target() local clipboard_txt=chr(91,103,102,120,93) local w,h=tww,twh local function to_p8scii_num(n) if n<10 then return tostr(flr(n)) else return chr(flr(n+87)) end end clipboard_txt..=to_p8scii_num(flr(w/16))..to_p8scii_num(w%16)..to_p8scii_num(flr(h/16))..to_p8scii_num(h%16) for i=0,w*h-1 do clipboard_txt..=to_p8scii_num(get(screenshot,i%w,i\w)) end clipboard_txt..=chr(91,47,103,102,120,93) set_clipboard_text(clipboard_txt) cls() return else paused=not paused end elseif mx==mid(width*4-18,mx,width*4-11) and my==mid(6,my,13) and bit(mbp,0) then -- clicked on help draw_function=draw_help if (not (dead or won or start)) paused=true end -- -- draw game cls() rectfill(0,0,width*8,19,22) rectfill(0,19,width*8,height*8+19,32) palt(0,false) local emote=dead and frown or won and cool or (bit(mb,0) or bit(mb,1)) and tx==mid(0,tx,width-1) and ty==mid(0,ty,height-1) and curious or smile spr(emote,width*4-8,2) spr(start and wrench or (dead or won) and cam or paused and right or pause,width*4+10,6) spr(help,width*4-18,6) palt(0,true) if paused then print("** PAUSED **",width*4-30,height*4+15,7) else for x=0,width-1 do for y=-0,height-1 do local tile local tdata=get(minefield,x,y) local showneighbors if bit(tdata,1) then -- uncovered if bit(tdata,0) then -- mine tile=boom else -- no mine tile=empty showneighbors=true end else -- covered if bit(tdata,2) or won then -- flag if bit(tdata,0) or not dead then -- correct or still playing tile=flag else -- game over corrections tile=falseflag end else -- no flag if bit(tdata,0) and dead then -- game over clairvoyance tile=mine else -- nothing special tile=block end end end spr(tile,x*8+1,y*8+20) if showneighbors then local closemines=0 for xdelta=-1,1 do for ydelta=-1,1 do if (bit(get(minefield,x+xdelta,y+ydelta),0)) closemines+=1 end end pal(7,numbercols[closemines]) spr(numbers[closemines],x*8+1,y*8+20) pal(7,7) end end end end --rect(0,0,width*8,19,1) rect(0,19,width*8,height*8+19,17) rectfill(1,5,16,13,2) local str=mid(-99,flr(remainingmines),999) if str<-9 then -- do nothing elseif str<0 then str="-0"..-str elseif str<10 then str="00"..str elseif str<100 then str="0"..str else -- do nothing end print(({[0]="non","1St","2nd","3rd",["*"]="tOP",["x"]="CHt",["!"]=str,["?"]="CUS"})[rank or "!"],2,6,8) --print("888\f8\-1"..({[0]="non","1St","2nd","3rd",["*"]="tOP",["x"]="CHt",["!"]=str,["?"]="CUS"})[rank or "!"],2,6,24) rectfill(width*8-16,5,width*8-1,13,2) local str=mid(-99,flr(timer),999) if str<-9 then -- do nothing elseif str<0 then str="-0"..-str elseif str<10 then str="00"..str elseif str<100 then str="0"..str else -- do nothing end print(str,width*8-15,6,8) --print("888\f8\-1"..str,width*8-15,6,24) if cheatinput then for i=97,122 do if (get_key_pressed(chr(i))) add(cheatinput,i) end while #cheatinput>5 do deli(cheatinput,1) end if (#cheatinput>=5 and cheatinput[1]..cheatinput[2]..cheatinput[3]..cheatinput[4]..cheatinput[5]=="120121122122121" and get_key_state"shift") cheatinput=nil else -- cheating!!! pset(0,0,(tx<0 or tx>=width or ty<0 or ty>=height) and 5 or bit(get(minefield,tx,ty),0) and 32 or 7) --pset(width*8,0) end -- debug: display mouse statistics --local ww,wh=window_size() --cursor(width*8+2,1) color(27) --?"mx: "..mx --?"my: "..my --?"mb: "..mb --?"mbp: "..mbp --?"tx: "..tx --?"ty: "..ty --?"ww: "..ww --?"wh: "..wh --?"b: "..highscores_arr[1] --?"i: "..highscores_arr[2] --?"e: "..highscores_arr[3] -- /debug -- tww=width*8+1 twh=height*8+20 end -- function draw_menu() if mbp%2==1 then if mx==mid(150,mx,157) and my==mid(70,my,77) then draw_function=draw_game remainingmines=mines minefield=userdata("u8",width,height) elseif mx==mid(0,mx,6) and my==mid(21,my,63) then for i=2,5 do -- check if we are close to the appropriate difficulty selector if abs(mx-3)^2+abs(my-i*12)^2<9 then difficulty=i-1 if difficulty==4 then difficulty=0 else width= ({09,16,30})[difficulty] height=({09,16,16})[difficulty] mines= ({10,40,99})[difficulty] end break end end elseif difficulty==0 and mx==mid(131,mx,157) and my==mid(13,my,44) then local change=get_key_state"ctrl" and get_key_state"shift" and 100 or get_key_state"ctrl" and 10 or get_key_state"shift" and 5 or 1 if (mx==mid(131,mx,138) and my==mid(13,my,20)) width-=change if (mx==mid(150,mx,157) and my==mid(13,my,20)) width+=change if (mx==mid(131,mx,138) and my==mid(25,my,32)) height-=change if (mx==mid(150,mx,157) and my==mid(25,my,32)) height+=change if (mx==mid(131,mx,138) and my==mid(37,my,44)) mines-=change if (mx==mid(150,mx,157) and my==mid(37,my,44)) mines+=change width=mid(9,width,30) height=mid(9,height,16) mines=mid(10,mines,min(99,width*height-1)) end end -- cls(22) ?"Minefield Customization Menu",1,1,23 spr(fishhook,150,70) ?"Beginner\nIntermediate\nExpert\nCustom",7,21,6 for i=2,5 do local y=i*12 if (i-1==difficulty or i==5 and difficulty==0) circfill(3,y,2,27) circ(3,y,2,6) end if difficulty==0 then ?" width:\nheight:\n mines:",96,13,6 for y=12,36,12 do rectfill(130,y,158,y+9,32) ?y==12 and (width<10 and "0"..width or width) or y==24 and (height<10 and "0"..height or height) or mines,140,y+1,6 end spr(width>9 and left or unusable,131,13) spr(width<30 and right or unusable,150,13) spr(height>9 and left or unusable,131,25) spr(height<16 and right or unusable,150,25) spr(mines>10 and left or unusable,131,37) spr(mines< min(99,width*height-1) and right or unusable,150,37) else local best_times=highscores_arr[difficulty] ?"1st: "..best_times[1].."\n2nd: "..best_times[2].."\n3rd: "..best_times[3],111,13,6 end -- tww=160 twh=80 end -- function draw_help() page=page or 1 local pages={{[[ Welcome to Picotron Minesweeper! Click the to continue reading. Click the to go back a page. Click the to exit this screen. ]], spr,right,49,25, spr,left,49,37, spr,fishhook,49,49}, {[[ Note that the game is paused in this menu, so don't worry about looking back here in the middle of a game when you need help. Click the to get back here. ]], spr,help,49,49 },{[[ Click a \0121tile\012s ( ) to uncover it. A number will be revealed. This number shows how many \0121mines\012s ( ) surround the tile. ]], rectfill,71,0,79,8,22, spr,block,72,1, rectfill,36,48,44,56,22, spr,boom,37,49, function() rectfill(1,24,73,32,22) for i=0,8 do local x=i*8+2 spr(empty,x,25) pal(7,numbercols[i]) spr(numbers[i],x,25) pal(7,7) end end}, {[[ \0121Uncovering a mine will end the game.\012s The goal is to uncover all non-mine tiles as \0121quickly as possible.\012s ]]},{[[ Right-click a tile to \0121flag\012s ( ) it as having a mine underneath. Use this to keep track of what you think is and isn't a mine. ]], rectfill,141,0,149,8,22, spr,flag,142,1}, {[[ The number in the upper-left displays \0121an approximation of how many mines are remaining.\012s The number in the upper-right displays your current \0121time.\012s ]]},{[[ If a tile with \0121zero\012s neighboring mines is uncovered, \0121all\012s nearby tiles will automatically be uncovered. Your first click is \0121guaranteed\012s to land on such a tile, if at all possible. ]]},{[[ To restart the game, click the \0121face\012s in the top-middle of the screen. Its face also \0121corres- ponds to the current game state.\012s ]], pal,0,0, spr,smile,35,50, spr,curious,60,50, spr,frown,85,50, spr,cool,110,50, palt,0,true}, {[[ If you middle-click a revealed tile, \0121all surrounding non- flagged tiles\012s will be opened \0121IF\012s the \0121number of the clicked tile is equal to the number of surrounding flags.\012s ]]}, {[[ To the left of the face is that that you can click to get back to this help screen, but you probably figured that out already. ]], spr,help,24,13}, {[[ To the \0121right\012s of the face, however, is a button that has multiple functions \0121depending on the game's state.\012s ]], spr,wrench,100,37, spr,pause,110,37, spr,right,120,37, spr,cam,130,37}, {[[ When the game ends (one way or another), the \0121camera button\012s ( ) shows up to let you get a \0121screenshot\012s as a \0121Picotron GFX string copied to your clipboard.\012s (experimental!) ]], spr,cam,7,25}, {[[ In the middle of a game, the \0121pause\012s ( ) and \0121unpause\012s ( ) buttons can be used if you need to take a break for whatever reason. ]], spr,pause,57,13, spr,right,142,13}, {[[ The most interesting option though is at the beginning of a round with the \0121Minefield Customization Menu.\012s ( ) ]], spr,wrench,107,37}, {[[ In this menu, you can switch to one of \0121three difficulty levels\012s and see your \0121top three scores\012s for each of them. ]]},{[[ You can also create a minefield with \0121custom parameters,\012s such as \0121width, height and mines\012s using the and buttons. ]], spr,left,19,37, spr,right,49,37}, {[[ After winning the game, the \0121estimated mine count\012s will switch to showing how well you did. \0121'non'\012s means no best time, while \0121'1St'\012s, \0121'2nd'\012s and \0121'3rd'\012s mean the appropriate place. ]]}, {[[ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \0121That's about all there is to Picotron Minesweeper. Have fun!\012s ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ]]} -- ...Aside from the hidden *CHEAT CODE*, that is... --,{[[ --\0121Push\012s button --Recieve \0121bacon\012s --]]} } -- if mbp%2==1 and my==mid(70,my,77) then if mx==mid(150,mx,157) and page<#pages then page+=1 first_time=nil elseif mx==mid(140,mx,147) and page>1 then page-=1 elseif mx==mid(120,mx,127) and not first_time then --page=nil -- reset current page number (I decided against this later) draw_function=draw_game --if (not page) return -- avoid a crash if we reset the page number end end -- cls(17) local to_draw=pages[page] local i=0 local text=to_draw[1] while i<#text do i+=1 if sub(text,i,i)=="\\" then text=sub(text,1,i-1)..chr(tonumber(sub(text,i+1,i+3)))..sub(text,i+4,#text) end end ?text,1,1,28 --palt(22,true) --for i=2,#to_draw,3 do --spr(to_draw[i],to_draw[i+1],to_draw[i+2]) --end --if page==3 then --pal(22,22) rectfill(1,24,73,32,22) palt(22,true) --for i=0,8 do --local x=i*8+2 --spr(empty,x,25) --pal(7,numbercols[i]) --spr(numbers[i],x,25) --pal(7,7) --end --end --pal(22,22) i=2 while i<=#to_draw do local func=to_draw[i] i+=1 local args={} while type(to_draw[i])~="function" and to_draw[i]~=nil do add(args,to_draw[i]) i+=1 end func(table.unpack(args)) end ?"Page: "..page.."/"..#pages,2,71,12 spr(first_time and unusable or fishhook,120,70) spr(page==1 and unusable or left,140,70) spr(page==#pages and unusable or right,150,70) -- tww=160 twh=80 end -- draw_function=first_time and draw_help or draw_game -- function _draw() -- mouse handling mx,my,mb=get_mouse() mbp=mb&~lmb -- mb pressed lmb=mb -- last mb -- draw_function() -- varies -- -- housekeeping stuff (their necessity is mostly Picotron's fault) rnd() -- sufficiently jumbles up the RNG seeds -- (necessary due to Picotron not randomizing the seed on startup) -- next up: a bunch of stuff to prevent you from resizing the window manually local ww,wh=window_size() if (tww~=ww or twh~=wh) set_window(tww,twh) -- more complicated than it needs to be because set_window() has WEEEEEIIIIIRRRRRD -- effects on how the drawing works. for example, sometimes it will prevent all -- future drawing actions from taking place. the solution would be to set the window -- last. HOWEVER, sometimes it will allow future drawing, but CLEAR THE SCREEN TOO. -- in that case, you would want to set the window first thing! long story short, -- to make thing easier we only fix the window size if we really, really have to. end -- end of program |
Then paste it into a blank codebase in Picotron Playground, hit Ctrl+R and... THAT'S IT.
By default, you will be booted into the help screen, but if you don't care for that, just click the 'next page' button, and then the back button will show up so you can skip straight to playing the game.
Technical notes
(Warning: Long wall of text follows)
Most of the streamlining goes to
set_window(w,h)
. With this function, the program will automatically make it's own window, set it's size, and flip to the desktop view, creating the desktop if it hasen't been booted up this session. If it's called multiple times, it will instead adjust the window it had already made earlier, though with some inconsistency as to how it treats anything already on the screen, and how it treats newly drawn stuff. (In my experience, one or the other will continue working, but never both, but which one works and which on doesen't seem to switch randomly whenever you do something like _draw=draw_game
and I have no idea why. Earlier in development I edited the _draw
function like this, but I decided against that when I needed some stuff like the mouse variables to always be updated, which inadvertently fixed the inconsistency issue, as it I just tested it now and it seem to be stuck on the 'lock future drawing, don't clear screen' mode, whereas before when I switched the _draw
function around it seemed to switch modes. Still, I don't want to risk anything going wrong, so I still do the check to make sure it's actually necessary to adjust the window, just in case.) Credit to @pancelor for their function-lister, as otherwise this would not have been possible.
I also changed the font to be smaller, because that old font looked waayyy too big, and didn't go well at ALL with the shading on the holes, particularly with some colors (for example, the purple of the 4 combined with the shading to make it look like an 'A').
Did you know that the original Minesweeper had a cheat code? This version has that cheat code implemented too, so if you know the code you can solve puzzles that would of otherwise been impossible without guessing. (Though, you won't be able to save your score if do so.) Want to know the code? Well... for that, you're gonna have to look in the game's code. You gotta EARN it, you know?
Pasting the program into PICO-8 shows that this program is consists of 2944 tokens, 24445 chars, and 7642 compressed bytes (48% of .p8.png capacity). Of course, the program won't work in PICO-8 - it crashes just from attempting to define the sprites - but it's still a good metric for how much work I put in. (Answer: Actually not that much, at least compared to some other people.)
If you have too many empty tiles onscreen at any one time, this happens:
Actually, it's even worse, as it constantly swaps between this and the normal desktop at sixty frames a second. So, uh, I suppose I should give out an epilepsy warning, I guess?
Also, posting this on here was... harder than you would think. For starters, there's that gosh-darned decode
function at the top of the codebase. Why is that? Well...
jelpi=userdata"
|
That looks horrible! And yes, that is what happens when you try to put a {gfx}..{/gfx} tag (imagine those as being square brackets and not curly ones) in a post, even in a section marked as code. The decode
function's job is to synthesize one of those tags without actually having one of them in the code. So to make that Jelpi sprite:
function decode(str) return userdata(chr(91,103,102,120,93)..str..chr(91,47,103,102,120,93)) end jelpi=decode"0808000000000f000f000ffffff00f1fff100effffe0002220000088800000f0f000" |
You can see that the chr
function is helping out greatly here by letting us encode the gfx
portion as a series of numbers, and then decoding them to feed them to userdata
.
The other issue I had when posting this code here was statements like blah< foo
. If you remove the space between <
and foo
, it will remove ALL code between that point and whenever it finally sees a >
. This doesn't seem to happen when a number or a space is immediatly following the <
however, so fortunately this was relatively easy to fix.
That's about all I had. Like others, I probably won't continue to work on anything major in Picotron until a new version comes out (particularly the 0.1 release), but I still enjoyed working on it nonetheless. Special thanks to @Liquidream, @dw817 and @merwok for the kind words spoken about this project that helped me motivate myself to continue working on it.
Very impressive! @dw817 may not be here anymore, but I'd say this deserves a gold star!
This is definitely a strong step forward for Picotron development!
[Please log in to post a comment]