#!/usr/bin/murgaLua
-- slide puzzle for MurgaLua 0.6.4+
-- 2008 mikshaw
-- window and image size are determined by these variables
ts=80 -- tile size
tc=4 -- number of tiles in one line
fr=5 -- frame size
--img_dir="/mnt/hda4/shared/image/slide_puzzle"
--img_dir="/home/mik/image/slide_puzzle"
if not Fl_Image.getTiles then
err="This program requires murgaLua 0.6.4 or newer.\n\n"..
"http://www.murga-projects.com/murgaLua/index.html"
if fltk then fltk.fl_alert(err) else print(err) end
os.exit(1)
end
function load_callback(object)
-- a stew of pieces from John Murga's functions
fileName = fltk.fl_file_chooser("Choose an RGB image", "Image Files (*.{jpg,png,bmp,xbm,xpm,gif})", img_dir, nil)
if fileName then
if image1 then image1:uncache() end -- don't know if this is needed
image1 = Fl_Shared_Image.get(fileName,ts*tc,ts*tc)
start=1 -- used for controlling window callback and scramble behavior
preview:image(image1); preview:redraw(); preview:show() -- load the preview
Fl:check() -- seems to keep fl_read_image from grabbing the file chooser
imageString=fltk.fl_read_image(fr,fr,ts*tc,ts*tc) -- grab the preview image
image2 = fltk:Fl_RGB_Image(imageString,ts*tc,ts*tc,3) -- create RGB image for tiling
myImages = image2:getTiles(ts,ts)
for key,value in ipairs(myImages) do
tile[key-1]:image(value)
-- make sure all tile locations are reset correctly
-- fixes a bug if image is changed while tiles are scrambled
tile[key-1]:position(pos[key-1].col,pos[key-1].row)
end
scramble()
scrambutt:label("load an image")
end
end
function move_tile(t)
if Fl:event_button() >1 then preview:show() elseif image2 then
local my_x,my_y,movex,movey=t:x(),t:y()
-- tile must be adjacent to the missing piece
if (my_x == tile[hidden]:x() and math.abs(my_y-tile[hidden]:y()) == ts)
or (my_y == tile[hidden]:y() and math.abs(my_x-tile[hidden]:x()) == ts)
then
-- swap selected tile with the hidden one
movex=tile[hidden]:x()
movey=tile[hidden]:y()
tile[hidden]:position(my_x,my_y)
t:position(movex,movey)
w:redraw()
end
-- check to see if puzzle is solved
-- "ok" is incremented each time a tile is found in its proper place
if start==0 then -- don't check puzzle during scramble
local ok=0
for i=0,tc^2-1 do
if tile[i]:x()==pos[i].col and tile[i]:y()==pos[i].row then
ok=ok+1
if ok==tc^2 then -- if ok == total number of tiles
fltk.fl_beep()
scrambutt:label(plize[math.random(1,table.getn(plize))])
preview:show()
start=1
break
end
end
end
end
end
end
function scramble()
-- this picks a random tile to attempt to move and
-- repeats the process many times. Simply placing
-- tiles in random locations could potentially make
-- the puzzle impossible to solve
preview:hide()
if hidden then -- reset hidden tile
tile[hidden]:box(fltk.FL_UP_BOX)
tile[hidden]:labeltype(fltk.FL_NORMAL_LABEL)
end
-- turn a random tile into the missing piece
hidden=math.random(0,tc^2-1)
tile[hidden]:labeltype(fltk.FL_NO_LABEL)
tile[hidden]:box(fltk.FL_DOWN_BOX)
local scram=0
while scram < 10000 do
move_tile(tile[math.random(0,tc^2-1)])
scram=scram+1
end
start=0
w:redraw()
end
plize={"Great Job!", "Hooray for You!", "You don't suck!", "WIN!", "GODLIKE!", "CONGRATULATE YOU!"}
fltk.fl_register_images()
math.randomseed(os.time())
Fl:visible_focus(0) -- get rid of the ants
Fl:set_boxtype(fltk.FL_UP_BOX,fltk.FL_THIN_UP_BOX) -- looks a little more like tiles
Fl:set_boxtype(fltk.FL_DOWN_BOX,fltk.FL_THIN_DOWN_BOX)
w=fltk:Fl_Double_Window(ts*tc+fr*2,ts*(tc+0.5)+fr*3,"slide puzzle")
scrambutt=fltk:Fl_Button(fr,ts*tc+fr*2,ts*tc,ts/2,"load an image")
scrambutt:callback(load_callback)
scrambutt:tooltip([[
Click this button at any time to load a new image.
** Puzzle Controls **
Left click: Move a tile.
Right or Middle click: Toggle image display.
Esc: Quit program, or close image display if it is visible.
]])
-- array of tiles, top left to right, then move down
tile={}; pos={}
-- allow space for the frame
row=fr; col=fr
-- subtract one is used because the number of tiles starts at one
-- but the table starts at zero (easier to position them from zero)
for i=0,tc^2-1 do
tile[i]=fltk:Fl_Button(col,row,ts,ts)
tile[i]:align(80)
tile[i]:callback(move_tile)
pos[i]={col=col,row=row}
-- next piece is ts pixels to the right
col=col+ts
-- start the next row
if col == ts*tc+fr then col=fr;row=row+ts end
end
-- image preview (cheat)
preview=fltk:Fl_Button(fr,fr,ts*tc,ts*tc)
preview:callback(function()
if start==1 then load_callback()
else preview:hide() end
end)
--preview:hide()
w:callback(function()
-- Esc just hides the preview if it's visible
if preview:visible()==1 and start==0 then preview:hide()
else os.exit() end
end)
start=1
w:show()
Fl:run()