#!/usr/bin/env murgaLua -- slide puzzle for MurgaLua 0.6.4+ -- 2008-9 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 -- default directory to start in. Change to nil to start in current dir --img_dir="/home/shared/image/slide_puzzle" img_dir=nil function set_shortcuts() -- set arrow key shortcuts to the tiles surrounding the hidden tile -- If you have no use for keyboard control, this function can be safely removed as long -- as you also remove the two lines that call it (in the functions move_tile & scramble) for i=0,tc*tc-1 do tile[i]:shortcut(nil) if (tile[i]:x()==tile[hidden]:x() and math.abs(tile[i]:y()-tile[hidden]:y()) == ts) then if tile[i]:y() < tile[hidden]:y() then tile[i]:shortcut(fltk.FL_Down) else tile[i]:shortcut(fltk.FL_Up) end elseif (tile[i]:y()==tile[hidden]:y() and math.abs(tile[i]:x()-tile[hidden]:x()) == ts) then if tile[i]:x() < tile[hidden]:x() then tile[i]:shortcut(fltk.FL_Right) else tile[i]:shortcut(fltk.FL_Left) end end end end 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 img_dir=nil -- use previously selected dir from now on 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 -- prevents gameplay checks during scramble w:label(fltk.fl_filename_name(fileName)) 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) -- cut up the image 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 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 if start==0 then num_moves=num_moves+1 end 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 set_shortcuts() -- you can remove this if you use mouse only 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() if num_moves<100 then plize=firstplize elseif num_moves<200 then plize=secondplize elseif num_moves<300 then plize=thirdplize elseif num_moves<400 then plize=fourthplize else plize=insult end scrambutt:label(plize[math.random(1,table.getn(plize))].."\n"..num_moves.." moves") 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 set_shortcuts() -- you can remove this if you use mouse only num_moves=0 w:redraw() end firstplize={"GODLIKE!", "OWNAGE!"} secondplize={"Great Job!","Hooray for You!","WIN!", "CONGRATULATE YOU!","Super!","Flawless Victory!", "You rock!","Crazygonuts!"} thirdplize={"Not bad at all!","Yay!"} fourthplize={"You're not terrible!","Petty good."} insult={"You're kinda bad at this.","Is that your best?","Ho-hum.","a mediocre performance."} Fl:get_system_colors() 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:shortcut("l") -- 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) tog_prev=fltk:Fl_Button(-10,-10,0,0) tog_prev:shortcut("p") tog_prev:callback(function() if preview:visible()==1 then preview:hide() else preview:show() end end) w:callback(function() -- Esc/close hides the preview if it's visible if preview:visible()==1 and start==0 then preview:hide() else os.exit() end -- otherwise exit as normal end) start=1 w:show() Fl:run()