# 15puzzle_new.kbs - slide the tiles to get them back in order
# this is a conversion from the old gosub to the new function/subroutines
# 2016-11-02 j.m.reneau
# 2020-04-27 j.m.reneau rrays pass by value not ref unless specified in 2.0

fastgraphics

global zx, zy, bw, xw, yw

nx = 4 # number of boxes in a row
ny = 4 # number of boxes in a column
dim board(nx, ny)
zx = 0 # position of the empty tile
zy = 0

bw = 5 # border width
xw = (graphwidth - ((nx+1)*bw)) / nx # calculate size of a box
yw = (graphheight - ((ny+1)*bw)) / ny

print "slide puzzle"
print "click on tile to slide.  try to get all tiles in order."

call initialboard(ref(board))
call drawboard(board[])
call shuffle(ref(board))
call drawboard(board[])

clickclear
moves = 0

print "click tile to move"
do
   # wait for click
   while clickb = 0
      pause .01
   end while
   cx = int(clickx/(xw+bw))
   if cx >= nx then cx = nx-1
   cy = int(clicky/(yw+bw))
   if cy >= ny then cy = ny-1
   clickclear
   # if a real click then make move
   if (zx = cx) or (zy = cy) then
      call makemove(ref(board), cx, cy)
      moves = moves + 1
      call drawboard(board[])
   end if
until isdone(board[])

print "Game Over - You solved it in "+ moves +"."

end

subroutine shuffle(b[])
   #for t = 1 to nx * ny * 10
   for t = 1 to b[,?] * b[?,] * 10
      x = zx
      y = zy
      r = int(rand*4)
      if r = 0 and x > 0 then x--
      if r = 1 and x < b[?,]-1 then x++
      if r = 2 and y > 0 then y--
      if r = 3 and y < b[,?]-1 then y++
      if x<>zx or y<> zy then
         b[zx, zy] = b[x, y]
         b[x, y] = 0
         zx = x
         zy = y
      end if
      call drawboard(b[])
      pause .01
   next t
end subroutine

subroutine makemove(b[],x,y)
   # shift cells
   if zx<>x then
      # row shift
      if x>zx then
         dx = 1
         dy = 0
      else
         dx = -1
         dy = 0
      end if
   else
      # column shift
      if y>zy then
         dx = 0
         dy = 1
      else
         dx = 0
         dy = -1
      end if
   end if
   # do shift
   while zx <> x or zy <> y
      b[zx, zy] = b[zx+dx, zy+dy]
      b[zx+dx, zy+dy] = 0
      zx += dx
      zy += dy
   end while
end subroutine

subroutine initialboard(b[])
   # setup the initial board array
   for x= 0 to b[?,]-1
      for y = 0 to b[,?]-1
         b[x, y] = (y*b[?,]+x+1)
      next y
   next x
   zx = b[?,]-1
   zy = b[,?]-1
   b[zx, zy] = 0
end subroutine

subroutine drawboard(b[])
   font "Tahoma", 24, 100
   clg
   color black
   rect 0, 0, graphwidth, graphheight
   for y = 0 to b[,?]-1
      for x = 0 to b[?,]-1
         cell =  b[x, y]
         color white
         rect (x+1)*bw+x*xw, (y+1)*bw+y*yw ,xw, yw
         
         if cell<> 0 then
            if zx = x or zy = y then
               color blue
            else
               color darkblue
            endif
            text (x+1)*bw+x*xw, (y+1)*bw+y*yw, cell
         end if
      next x
   next y
   refresh
end subroutine

function isdone(b[])
   # return 1 if we have solved the puzzle
   for x= 0 to b[?,]-1
      for y = 0 to b[,?]-1
         if b[x, y] <>  (y*b[?,]+x+1)  and (x <> zx or y <> zy) then
            isdone = false
            return
         end if
      next y
   next x
   isdone = true
end function