This game is basically a picture slide puzzle, but just with numbers at the moment. Slide the numbers around the board to get it to show 1-24 in order. However, the check-for-win “Grid:checkWin()” method has a bug that causes the game to be solved early and I cannot figure out why/how.
--# Main
function setup()
grid = Grid()
win = Win()
for i = 1, 5 do
grid:randomMove()
end
parameter.watch("grid.usingCell")
parameter.watch("grid.value[grid.usingCell.x][grid.usingCell.y]")
parameter.watch("grid:getInitialValue(grid.usingCell.x, grid.usingCell.y)")
end
function update()
end
function draw()
update()
background(66, 66, 106, 255)
grid:draw()
if win.win == true then
win:draw()
end
end
function touched(touch)
--if win.win == false then
grid:touched(touch)
--end
end
--# Grid
Grid = class()
function Grid:init()
self.cells = vec2(5, 5)
self.cellSize = nil
self.padding = nil
self.usingCell = vec2(nil, nil)
self.startTouch = vec2(nil, nil)
self.value = {}
for i = 1, self.cells.x do
self.value[i] = {}
for k = 1, self.cells.y do
self.value[i][k] = self:getInitialValue(i, k)
end
end
self.value[self.cells.x][1] = 0
end
function Grid:getInitialValue(i, k)
return (((self.cells.y - k) + 1) * self.cells.x) - self.cells.x + i
end
function Grid:draw()
-- rezise grid
local size = vec2(WIDTH / self.cells.x, HEIGHT / self.cells.y)
if size.x < size.y then
self.cellSize = size.x
else
self.cellSize = size.y
end
strokeWidth(self.cellSize * 0.05)
-- draw grid
for i = 1, self.cells.x do
for k = 1, self.cells.y do
if self.usingCell.x == i and self.usingCell.y == k then
stroke(255, 255, 0, 255)
else
stroke(255, 255, 255, 255)
end
local x = ((i - 1) * self.cellSize) + self:getPadding().x
local y = ((k - 1) * self.cellSize) + self:getPadding().y
if self.value[i][k] ~= 0 then
fill(66, 66, 66, 255)
rect(x, y, self.cellSize, self.cellSize)
fill(255, 255, 255, 255)
text(self.value[i][k], x + (self.cellSize / 2), y + (self.cellSize / 2))
end
end
end
end
function Grid:touched(touch)
if touch.state == BEGAN then
self.startTouch = touch
local i = math.floor((touch.x - self:getPadding().x) / self.cellSize) + 1
local k = math.floor((touch.y - self:getPadding().y) / self.cellSize) + 1
self.usingCell = vec2(i, k)
-- out of bounds
if i < 1 or i > self.cells.x or k < 1 or k > self.cells.y then
self.usingCell = vec2(nil, nil)
return
end
-- empty cell
if self.value[i][k] == 0 then
self.usingCell = vec2(nil, nil)
end
end
-- no or end of touch
if touch.state == ENDED then
self:moveCell(touch)
self.usingCell = vec2(nil, nil)
end
end
function Grid:getPadding()
local padding = vec2(0, 0)
if WIDTH ~= self.cells.x * self.cellSize then
padding.x = (WIDTH - (self.cellSize * self.cells.x)) / 2
else
padding.y = (HEIGHT - (self.cellSize * self.cells.y)) / 2
end
return padding
end
function Grid:moveCell(touch, move)
-- move by touch
local delta = vec2(0, 0)
if touch ~= nil then
delta = vec2(touch.x - self.startTouch.x, touch.y - self.startTouch.y)
end
local i = self.usingCell.x
local k = self.usingCell.y
if math.abs(delta.x) > math.abs(delta.y) or move == "right" or move == "left" then
-- right
if delta.x > 0 or move == "right" then
if self:validMove(i + 1, k) == false then return end
self.value[i + 1][k] = self.value[i][k]
self.value[i][k] = 0
--end
-- left
elseif delta.x < 0 or move == "left" then
if self:validMove(i - 1, k) == false then return true end
self.value[i - 1][k] = self.value[i][k]
self.value[i][k] = 0
end
else
-- up
if delta.y > 0 or move == "up" then
if self:validMove(i, k + 1) == false then return end
self.value[i][k + 1] = self.value[i][k]
self.value[i][k] = 0
--end
-- down
elseif delta.y < 0 or move == "down" then
if self:validMove(i, k - 1) == false then return end
self.value[i][k - 1] = self.value[i][k]
self.value[i][k] = 0
end
end
-- check for win
if self:checkWin() == true then win.win = true end
end
function Grid:validMove(i, k)
-- out of bounds
if self:validCell(i, k) == false then return false end
-- cell not empty
if self.value[i][k] ~= 0 then return false end
return true
end
function Grid:validCell(i, k)
-- out of bounds
if i < 1 then
return false
elseif i > self.cells.x then
return false
elseif k < 1 then
return false
elseif k > self.cells.y then
return false
end
return true
end
function Grid:randomMove()
local index = vec2(nil, nil)
-- find empty cell
for i = 1, self.cells.x do
for k = 1, self.cells.y do
if self.value[i][k] == 0 then
index = vec2(i, k)
end
end
end
-- random move
while 1 do
local rand = math.random(1,4)
-- right
if rand == 1 and self:validCell(index.x - 1, index.y) == true then
self.usingCell = vec2(index.x - 1, index.y)
self:moveCell(nil, "right")
break
end
-- left
if rand == 2 and self:validCell(index.x + 1, index.y) == true then
self.usingCell = vec2(index.x + 1, index.y)
self:moveCell(nil, "left")
break
end
-- up
if rand == 3 and self:validCell(index.x, index.y - 1) == true then
self.usingCell = vec2(index.x, index.y - 1)
self:moveCell(nil, "up")
break
end
-- down
if rand == 4 and self:validCell(index.x, index.y + 1) == true then
self.usingCell = vec2(index.x, index.y + 1)
self:moveCell(nil, "down")
break
end
end
self.usingCell = vec2(nil, nil)
end
function Grid:checkWin()
for i = 1, self.cells.x do
for k = 1, self.cells.y do
if i == self.cells.x and k == 1 then
if self.value[i][k] ~= 0 then return false end
else
if self.value[i][k] ~= self:getInitialValue(i, k) then return false end
end
end
end
return true
end
--# Win
Win = class()
function Win:init()
self.win = false
end
function Win:draw()
local size = vec2(200, 100)
local position = vec2((WIDTH / 2) - (size.x / 2), (HEIGHT / 2) - (size.y / 2))
fill(66, 66, 106, 255)
rect(position.x, position.y, size.x, size.y)
fill(255, 255, 255, 255)
text("Solved!", WIDTH / 2, HEIGHT / 2)
end
function Win:touched(touch)
end