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
mikshaw
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 it...it'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

Code:
#!/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)
--[[
up="w"
down="s"
left="a"
right="d"
--]]

-- default directory to start in. Change to nil to start in current dir
--img_dir="/home/shared/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

-- 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","")
end
end

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
os.exit()
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
    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(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
      end
  end
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
  w:make_current()
  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
  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,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
    tile[i]:position(pos[i].col,pos[i].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<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")
      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*tc 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!", "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: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)
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")
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 == iw+fr then col=fr;row=row+ts end
end

-- image preview (cheat)
preview=fltk:Fl_Button(fr,fr,iw,iw)
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()

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: