News : The level of daily SPAM has reached insane proportions, all registrations are now manual. I ask you to send me an e-mail (john (at) murga (dot) org), to confirm that you want me to create an account for you.

Post Reply  Post Thread 
slide puzzle
Author Message
Senior Member

Posts: 522
Group: Registered
Joined: Apr 2007
Status: Offline
Reputation: 5
Post: #1
slide puzzle

Dug out the slide puzzle I was working on a couple of years ago, and made a couple of changes. It will now accept commandline options to set the image width (-iw <num>) and tile count (-tc <num>). Tile count is the number of tiles along one edge, so it's image width divided by tile count equals tile width. If the tile count can't be divided evenly into the image width, something was messing up, so rather than try to figure out what was happening I made it so it will just shrink the image width to make it even.

You can also set keys to control tile movement. If they're not set they will default to arrows.

I don't know what else might be different from the last time i posted's been a while. One thing I did forget is that I wanted to make an option to disable setting the hotkeys if you only use the mouse, since it has to reset the hot buttons every time you move a tile.

EDIT 2011-01-09: replaced Fl_Image:getTiles() with a fl_read_image() loop

#!/usr/bin/env murgaLua

-- slide puzzle for MurgaLua 0.6.4+
-- 2008-2011 mikshaw

-- window and tile size are determined by these variables
-- tile size = iw/tc (image size will be adjusted if it doesn't divide evenly)
iw=600  -- image width
tc=5  -- number of tiles in one line
fr=5 -- frame size
-- Tile movement keys default to arrows, but can be changed here
-- Note: "l" and "p" are reserved (load and preview)

-- default directory to start in. Change to nil to start in current dir

if not Fl_Image.getTiles then
err="This program requires murgaLua 0.6.4 or newer.\n\n"..
if fltk then fltk.fl_alert(err) else print(err) end

-- check commandline options
for i,v in pairs(arg) do
if v=="-w" and type(tonumber(arg[i+1]))=="number" then iw=arg[i+1]
elseif string.find(v,"^%-w%d+$") then iw=string.gsub(v,"-w","")
elseif v=="-tc" and type(tonumber(arg[i+1]))=="number" then tc=arg[i+1]
elseif string.find(v,"^%-tc%d+$") then tc=string.gsub(v,"-tc","")

if iw/tc < 50 then
err="image size should be at least 50x the tile count"
if fltk then fltk.fl_alert(err) else print(err) end

-- fix to make iw evenly divisible by tc
if iw % tc ~= 0 then iw=tc*math.floor(iw/tc) end

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
      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(mv_Down) else tile[i]:shortcut(mv_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(mv_Right) else tile[i]:shortcut(mv_Left) 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,iw,iw)
  start=1 -- prevents gameplay checks during scramble
  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,iw,iw) -- grab the preview image
  image2 = fltk:Fl_RGB_Image(imageString,iw,iw,3) -- create RGB image for tiling
  for i,_ in pairs(tile) do -- create an image for each tile
    tileString = fltk.fl_read_image(pos[i].col, pos[i].row, ts, ts)
    tile[i]:image(fltk:Fl_RGB_Image(tileString, ts, ts, 3))
    -- make sure all tile locations are reset correctly
    -- fixes a bug if image is changed while tiles are scrambled
  scrambutt:label("&load an image")

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)
    -- swap selected tile with the hidden one
    if start==0 then num_moves=num_moves+1 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
    if ok==tc^2 then -- if ok == total number of tiles
      if num_moves<tc*25 then plize=firstplize
      elseif num_moves<tc*50 then plize=secondplize
      elseif num_moves<tc*75 then plize=thirdplize
      elseif num_moves<tc*100 then plize=fourthplize
      else plize=insult end
      scrambutt:label(plize[math.random(1,table.getn(plize))].."\n"..num_moves.." moves")

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
if hidden then -- reset hidden tile
-- turn a random tile into the missing piece
local scram=0
while scram < 10000*tc do
set_shortcuts() -- you can remove this if you use mouse only

firstplize={"GODLIKE!", "OWNAGE!", "TEH WINRAR!"}
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: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
mv_Up=up or fltk.FL_Up
mv_Down=down or fltk.FL_Down
mv_Left=left or fltk.FL_Left
mv_Right=right or fltk.FL_Right
ts=iw/tc -- set tile size
--w=fltk:Fl_Double_Window(iw+fr*2,ts*(tc+0.5)+fr*3,"slide puzzle")
w=fltk:Fl_Double_Window(iw+fr*2,iw+ts/2+fr*3,"slide puzzle")

scrambutt=fltk:Fl_Button(fr,iw+fr*2,iw,ts/2,"&load an image")

-- 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
  -- next piece is ts pixels to the right
  -- start the next row
  if col == iw+fr then col=fr;row=row+ts end

-- image preview (cheat)
if start==1 then load_callback()
else preview:hide() end
if preview:visible()==1 then preview:hide() else preview:show() end

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


This post was last modified: 01-10-2011 10:08 AM by mikshaw.

01-05-2011 01:53 PM
Find all posts by this user Quote this message in a reply
Post Reply  Post Thread 

Messages In This Thread
slide puzzle - mikshaw - 01-05-2011 01:53 PM

View a Printable Version
Send this Thread to a Friend
Subscribe to this Thread | Add Thread to Favorites

Forum Jump: