-- 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