Playable board creation ok

This commit is contained in:
Simon Cambier 2022-05-28 23:58:00 +02:00
parent f47ed840cf
commit b80297c45f

181
main.lua
View File

@ -86,37 +86,28 @@ function equal(tbl1, tbl2)
return true return true
end end
function tostring(any)
if (type(any)~="table") return tostr(any)
local str = "{"
for k,v in pairs(any) do
if (str~="{") str=str..","
str=str..tostring(k).."="..tostring(v)
end
return str.."}"
end
-- --
-- Board -- Board
-- --
local Board = {} local Board = {}
function Board.new() function Board.new()
local debug = false
local width = 10 local width = 10
-- local t = [[
-- 2,0,2,0,0,2,1,0,1,2,
-- 0,0,0,0,0,0,0,0,0,1,
-- 0,1,0,0,0,0,0,0,0,0,
-- 0,2,0,0,0,0,0,1,0,2,
-- 0,0,1,0,0,2,0,1,0,1,
-- 0,0,0,0,1,1,0,0,0,0,
-- 0,2,2,0,0,0,0,0,0,2,
-- 0,0,0,0,2,0,0,0,0,0,
-- 0,0,2,0,0,1,0,0,0,0,
-- 0,2,0,0,2,0,2,0,0,0
-- ]]
local t = [[ local t = [[
0,0,0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0
]] ]]
a = {foo = 3}
local tiles = split(t) local tiles = split(t)
return { return {
@ -136,10 +127,25 @@ function Board.new()
tiles = split(t) tiles = split(t)
end, end,
getWidth = function()
return width
end,
getTile = function(self, idx) getTile = function(self, idx)
return tiles[idx] return tiles[idx]
end, end,
-- returns a COPY of the tiles array
getTilesCopy = function(self)
return copy(tiles)
end,
-- overwrites the whole tiles array
setTiles = function(self, newtiles)
assert(#newtiles == #tiles, "New tiles array must have a length of " .. #tiles)
tiles = copy(newtiles)
end,
idx_xy = function(self, idx) idx_xy = function(self, idx)
return idx_xy(idx, width) return idx_xy(idx, width)
end, end,
@ -178,22 +184,22 @@ function Board.new()
isValid = function(self) isValid = function(self)
local rows = self:getRows() local rows = self:getRows()
for row in all(rows) do for y,row in ipairs(rows) do
-- check count -- check count
if count(row, BLUE) ~= count(row, YELLOW) then if count(row, BLUE) ~= count(row, YELLOW) then
printh("uneven count") if (debug) printh("uneven count on row "..y)
return false return false
end end
-- check identical lines -- check identical lines
for k,other in ipairs(rows) do for k,other in ipairs(rows) do
if equal(other, row) and other ~= row then if equal(other, row) and other ~= row then
printh("equal rows "..k) if (debug) printh("equal rows "..k)
return false return false
end end
end end
-- check triples -- check triples
if self:countConsecutives(row) > 2 then if self:countConsecutives(row) > 2 then
printh("triples") if (debug) printh("triples")
return false return false
end end
end end
@ -202,19 +208,19 @@ function Board.new()
for col in all(cols) do for col in all(cols) do
-- check count -- check count
if count(col, BLUE) ~= count(col, YELLOW) then if count(col, BLUE) ~= count(col, YELLOW) then
printh("uneven count") if (debug) printh("uneven count")
return false return false
end end
-- check identical lines -- check identical lines
for other in all(cols) do for other in all(cols) do
if equal(other, col) and other ~= col then if equal(other, col) and other ~= col then
printh("equal cols") if (debug) printh("equal cols")
return false return false
end end
end end
-- check triples -- check triples
if self:countConsecutives(col) > 2 then if self:countConsecutives(col) > 2 then
printh("triples") if (debug) printh("triples")
return false return false
end end
end end
@ -235,8 +241,8 @@ function Board.new()
return count return count
end, end,
-- Returns the index of a random zero -- Returns the index of a random zero tile
getRandomZero = function(self, v) getRandomZero = function(self)
assert(count(tiles, 0) > 0, "No zero left") assert(count(tiles, 0) > 0, "No zero left")
local zeroes = filter(tiles, function(v) return v == 0 end, true) local zeroes = filter(tiles, function(v) return v == 0 end, true)
local z = {} local z = {}
@ -246,6 +252,17 @@ function Board.new()
return rnd(z) return rnd(z)
end, end,
-- Returns the index of a random non-zero tile
getRandomNonZero = function(self)
assert(count(tiles, 0) < #tiles, "All zeroes")
local numbers = filter(tiles, function(v) return v ~= 0 end, true)
local z = {}
for k,v in pairs(numbers) do
add(z, k)
end
return rnd(z)
end,
tostring = function(self) tostring = function(self)
local str = '' local str = ''
for v in all(tiles) do for v in all(tiles) do
@ -254,19 +271,24 @@ function Board.new()
return str return str
end, end,
solve = function(self, random) -- Solves 1 step of the board
local old = self:tostring() -- Returns "valid" if it solved it without guessing
-- Returns "invalid" if the board cannot be solved
solveStep = function(self, random)
local zeroes = count(tiles, 0)
self:surroundDoubles() self:surroundDoubles()
self:splitTriples() self:splitTriples()
self:fillLines() self:fillLines()
self:noIdenticalLines() self:noIdenticalLines()
local changed = old ~= self:tostring() local changed = zeroes ~= count(tiles, 0)
if not changed and random and not self:isComplete() then if not changed and random and not self:isComplete() then
-- Set a random color -- Set a random color
local z = self:getRandomZero() local z = self:getRandomZero()
self:fill(z, rnd({BLUE, YELLOW})) self:fill(z, rnd({BLUE, YELLOW}))
printh("!!!!!!!!!!!!!!!!! RANDOM FILL AT " .. z) if (debug) printh("!!!!!!!!!!!!!!!!! RANDOM FILL AT " .. z)
return "invalid"
end end
return (changed or self:isComplete()) and "valid" or "invalid"
end, end,
surroundDoubles = function(self) surroundDoubles = function(self)
@ -297,7 +319,7 @@ function Board.new()
-- do the surrounding -- do the surrounding
for item in all(neighbors) do for item in all(neighbors) do
if item[1] then if item[1] then
printh("Surrounding at " .. item[1]) if (debug) printh("Surrounding at " .. item[1])
self:fill(item[1], tiles[item[2]], true) self:fill(item[1], tiles[item[2]], true)
end end
end end
@ -315,7 +337,7 @@ function Board.new()
local prev = tiles[idx-1] local prev = tiles[idx-1]
local next = tiles[idx+1] local next = tiles[idx+1]
if prev ~= 0 and prev == next then if prev ~= 0 and prev == next then
printh("Splitting at " .. idx) if (debug) printh("Splitting at " .. idx)
self:fill(idx, prev, true) self:fill(idx, prev, true)
end end
end end
@ -325,7 +347,7 @@ function Board.new()
local prev = tiles[idx-width] local prev = tiles[idx-width]
local next = tiles[idx+width] local next = tiles[idx+width]
if prev ~= 0 and prev == next then if prev ~= 0 and prev == next then
printh("Splitting at " .. idx) if (debug) printh("Splitting at " .. idx)
self:fill(idx, prev, true) self:fill(idx, prev, true)
end end
end end
@ -359,7 +381,7 @@ function Board.new()
end, end,
fillRow = function(self, y, color) fillRow = function(self, y, color)
printh("Filling line " .. y .. " in " .. (color == BLUE and "blue" or "yellow")) if (debug) printh("Filling line " .. y .. " in " .. (color == BLUE and "blue" or "yellow"))
local idx = self:xy_idx(1, y) local idx = self:xy_idx(1, y)
for i = idx, (idx+width-1) do for i = idx, (idx+width-1) do
if self:getTile(i) == 0 then if self:getTile(i) == 0 then
@ -369,7 +391,7 @@ function Board.new()
end, end,
fillCol = function(self, x, color) fillCol = function(self, x, color)
printh("Filling column " .. x .. " in " .. (color == BLUE and "blue" or "yellow")) if (debug) printh("Filling column " .. x .. " in " .. (color == BLUE and "blue" or "yellow"))
local idx = self:xy_idx(x, 1) local idx = self:xy_idx(x, 1)
for i = idx, #tiles, width do for i = idx, #tiles, width do
if self:getTile(i) == 0 then if self:getTile(i) == 0 then
@ -389,16 +411,20 @@ function Board.new()
-- Check if a dupe exists -- Check if a dupe exists
for x2,col in ipairs(cols) do for x2,col in ipairs(cols) do
if equal(col, ab) then if equal(col, ab) then
if debug then
printh("No-dupe at col " .. x .. " from col " .. x2) printh("No-dupe at col " .. x .. " from col " .. x2)
printh(" " .. self:xy_idx(x,y1) .. " in yellow") printh(" " .. self:xy_idx(x,y1) .. " in yellow")
printh(" " .. self:xy_idx(x,y2) .. " in blue") printh(" " .. self:xy_idx(x,y2) .. " in blue")
end
self:fill(self:xy_idx(x,y1), YELLOW) self:fill(self:xy_idx(x,y1), YELLOW)
self:fill(self:xy_idx(x,y2), BLUE) self:fill(self:xy_idx(x,y2), BLUE)
goto continue goto continue
elseif equal(col, ba) then elseif equal(col, ba) then
if debug then
printh("No-dupe at col " .. x .. " from col " .. x2) printh("No-dupe at col " .. x .. " from col " .. x2)
printh(" " .. self:xy_idx(x,y1) .. " in blue") printh(" " .. self:xy_idx(x,y1) .. " in blue")
printh(" " .. self:xy_idx(x,y2) .. " in yellow") printh(" " .. self:xy_idx(x,y2) .. " in yellow")
end
self:fill(self:xy_idx(x,y1), BLUE) self:fill(self:xy_idx(x,y1), BLUE)
self:fill(self:xy_idx(x,y2), YELLOW) self:fill(self:xy_idx(x,y2), YELLOW)
goto continue goto continue
@ -418,16 +444,20 @@ function Board.new()
-- Check if a dupe exists -- Check if a dupe exists
for y2,row in ipairs(rows) do for y2,row in ipairs(rows) do
if equal(row, ab) then if equal(row, ab) then
if debug then
printh("No-dupe at row " .. y .. " from row " .. y2) printh("No-dupe at row " .. y .. " from row " .. y2)
printh(" " .. self:xy_idx(x1,y) .. " in yellow") printh(" " .. self:xy_idx(x1,y) .. " in yellow")
printh(" " .. self:xy_idx(x2,y) .. " in blue") printh(" " .. self:xy_idx(x2,y) .. " in blue")
end
self:fill(self:xy_idx(x1,y), YELLOW) self:fill(self:xy_idx(x1,y), YELLOW)
self:fill(self:xy_idx(x2,y), BLUE) self:fill(self:xy_idx(x2,y), BLUE)
goto continue goto continue
elseif equal(row, ba) then elseif equal(row, ba) then
if debug then
printh("No-dupe at row " .. y .. " from row " .. y2) printh("No-dupe at row " .. y .. " from row " .. y2)
printh(" " .. self:xy_idx(x1,y) .. " in blue") printh(" " .. self:xy_idx(x1,y) .. " in blue")
printh(" " .. self:xy_idx(x2,y) .. " in yellow") printh(" " .. self:xy_idx(x2,y) .. " in yellow")
end
self:fill(self:xy_idx(x1,y), BLUE) self:fill(self:xy_idx(x1,y), BLUE)
self:fill(self:xy_idx(x2,y), YELLOW) self:fill(self:xy_idx(x2,y), YELLOW)
goto continue goto continue
@ -439,13 +469,21 @@ function Board.new()
end, end,
draw = function(self) draw = function(self)
local w = 10
local padding = 1
local margin = 4
for k,v in ipairs(tiles) do for k,v in ipairs(tiles) do
local x,y = self:idx_xy(k) local x,y = self:idx_xy(k)
local color = v == BLUE and 9 or v == YELLOW and 3 or 1 local color = v == BLUE and 9 or v == YELLOW and 3 or 1
local w = 10 rectfill(
local p = 1 margin + (x-1)*w + (x-1)*(padding+1),
rectfill((x-1)*w + (x-1)*(p+1), (y-1)*w + (y-1)*(p+1), w, w, color) margin + (y-1)*w + (y-1)*(padding+1),
print(k, (x-1)*w + (x-1)*(p+1), (y-1)*w + (y-1)*(p+1), 8) w, w, color)
if debug then
print(k,
margin + (x-1)*w + (x-1)*(padding+1),
margin + (y-1)*w + (y-1)*(padding+1), 8)
end
end end
end end
} }
@ -456,19 +494,58 @@ end
-- --
local board = Board.new() local board = Board.new()
local create = true
function _init() function _init()
cls()
printh(" ")
printh(" ")
-- srand(42)
if create then
-- Create a board
repeat
board:reset()
repeat
board:solveStep(true)
until board:isComplete()
until board:isValid()
-- Remove tiles until randomness is unavoidable
local previous = {board:getTilesCopy()} -- initial state
local invalidcount = 0
while true do
-- remove a random tile
board:setTiles(previous[#previous])
local i = board:getRandomNonZero()
board:fill(i, 0)
add(previous, board:getTilesCopy())
-- try to solve the board
local solved = ""
repeat
solved = board:solveStep()
until board:isComplete() or solved == "invalid"
if board:isComplete() then
invalidcount = 0
end
if solved == "invalid" then
deli(previous)
invalidcount += 1
end
if invalidcount == 100 then
break
end
end -- end while
board:setTiles(previous[#previous])
printh(board:tostring())
end
end end
function _update60() function _update60()
board:solve(true) if not create then
-- if time() % .01 == 0 then board:solveStep()
-- end
if board:isComplete() then
if not board:isValid() then
printh("NOT VALID")
board:reset()
end
end end
end end