From b80297c45fa75ac36dd18969461336f9df5a3dd2 Mon Sep 17 00:00:00 2001 From: Simon Cambier Date: Sat, 28 May 2022 23:58:00 +0200 Subject: [PATCH] Playable board creation ok --- main.lua | 207 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 65 deletions(-) diff --git a/main.lua b/main.lua index 81cf09f..f704ef2 100644 --- a/main.lua +++ b/main.lua @@ -86,37 +86,28 @@ function equal(tbl1, tbl2) return true 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 -- local Board = {} function Board.new() + local debug = false 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 = [[ - 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,0,0,0,0,0,0,0,0 + local t = [[ +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 ]] + a = {foo = 3} local tiles = split(t) return { @@ -136,10 +127,25 @@ function Board.new() tiles = split(t) end, + getWidth = function() + return width + end, + getTile = function(self, idx) return tiles[idx] 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) return idx_xy(idx, width) end, @@ -178,22 +184,22 @@ function Board.new() isValid = function(self) local rows = self:getRows() - for row in all(rows) do + for y,row in ipairs(rows) do -- check count if count(row, BLUE) ~= count(row, YELLOW) then - printh("uneven count") + if (debug) printh("uneven count on row "..y) return false end -- check identical lines for k,other in ipairs(rows) do if equal(other, row) and other ~= row then - printh("equal rows "..k) + if (debug) printh("equal rows "..k) return false end end -- check triples if self:countConsecutives(row) > 2 then - printh("triples") + if (debug) printh("triples") return false end end @@ -202,19 +208,19 @@ function Board.new() for col in all(cols) do -- check count if count(col, BLUE) ~= count(col, YELLOW) then - printh("uneven count") + if (debug) printh("uneven count") return false end -- check identical lines for other in all(cols) do if equal(other, col) and other ~= col then - printh("equal cols") + if (debug) printh("equal cols") return false end end -- check triples if self:countConsecutives(col) > 2 then - printh("triples") + if (debug) printh("triples") return false end end @@ -235,8 +241,8 @@ function Board.new() return count end, - -- Returns the index of a random zero - getRandomZero = function(self, v) + -- Returns the index of a random zero tile + getRandomZero = function(self) assert(count(tiles, 0) > 0, "No zero left") local zeroes = filter(tiles, function(v) return v == 0 end, true) local z = {} @@ -246,6 +252,17 @@ function Board.new() return rnd(z) 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) local str = '' for v in all(tiles) do @@ -254,19 +271,24 @@ function Board.new() return str end, - solve = function(self, random) - local old = self:tostring() + -- Solves 1 step of the board + -- 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:splitTriples() self:fillLines() self:noIdenticalLines() - local changed = old ~= self:tostring() + local changed = zeroes ~= count(tiles, 0) if not changed and random and not self:isComplete() then -- Set a random color local z = self:getRandomZero() self:fill(z, rnd({BLUE, YELLOW})) - printh("!!!!!!!!!!!!!!!!! RANDOM FILL AT " .. z) + if (debug) printh("!!!!!!!!!!!!!!!!! RANDOM FILL AT " .. z) + return "invalid" end + return (changed or self:isComplete()) and "valid" or "invalid" end, surroundDoubles = function(self) @@ -297,7 +319,7 @@ function Board.new() -- do the surrounding for item in all(neighbors) do if item[1] then - printh("Surrounding at " .. item[1]) + if (debug) printh("Surrounding at " .. item[1]) self:fill(item[1], tiles[item[2]], true) end end @@ -315,7 +337,7 @@ function Board.new() local prev = tiles[idx-1] local next = tiles[idx+1] if prev ~= 0 and prev == next then - printh("Splitting at " .. idx) + if (debug) printh("Splitting at " .. idx) self:fill(idx, prev, true) end end @@ -325,7 +347,7 @@ function Board.new() local prev = tiles[idx-width] local next = tiles[idx+width] if prev ~= 0 and prev == next then - printh("Splitting at " .. idx) + if (debug) printh("Splitting at " .. idx) self:fill(idx, prev, true) end end @@ -359,7 +381,7 @@ function Board.new() end, 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) for i = idx, (idx+width-1) do if self:getTile(i) == 0 then @@ -369,7 +391,7 @@ function Board.new() end, 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) for i = idx, #tiles, width do if self:getTile(i) == 0 then @@ -389,16 +411,20 @@ function Board.new() -- Check if a dupe exists for x2,col in ipairs(cols) do if equal(col, ab) then - printh("No-dupe at col " .. x .. " from col " .. x2) - printh(" " .. self:xy_idx(x,y1) .. " in yellow") - printh(" " .. self:xy_idx(x,y2) .. " in blue") + if debug then + printh("No-dupe at col " .. x .. " from col " .. x2) + printh(" " .. self:xy_idx(x,y1) .. " in yellow") + printh(" " .. self:xy_idx(x,y2) .. " in blue") + end self:fill(self:xy_idx(x,y1), YELLOW) self:fill(self:xy_idx(x,y2), BLUE) goto continue elseif equal(col, ba) then - printh("No-dupe at col " .. x .. " from col " .. x2) - printh(" " .. self:xy_idx(x,y1) .. " in blue") - printh(" " .. self:xy_idx(x,y2) .. " in yellow") + if debug then + printh("No-dupe at col " .. x .. " from col " .. x2) + printh(" " .. self:xy_idx(x,y1) .. " in blue") + printh(" " .. self:xy_idx(x,y2) .. " in yellow") + end self:fill(self:xy_idx(x,y1), BLUE) self:fill(self:xy_idx(x,y2), YELLOW) goto continue @@ -418,16 +444,20 @@ function Board.new() -- Check if a dupe exists for y2,row in ipairs(rows) do if equal(row, ab) then - printh("No-dupe at row " .. y .. " from row " .. y2) - printh(" " .. self:xy_idx(x1,y) .. " in yellow") - printh(" " .. self:xy_idx(x2,y) .. " in blue") + if debug then + printh("No-dupe at row " .. y .. " from row " .. y2) + printh(" " .. self:xy_idx(x1,y) .. " in yellow") + printh(" " .. self:xy_idx(x2,y) .. " in blue") + end self:fill(self:xy_idx(x1,y), YELLOW) self:fill(self:xy_idx(x2,y), BLUE) goto continue elseif equal(row, ba) then - printh("No-dupe at row " .. y .. " from row " .. y2) - printh(" " .. self:xy_idx(x1,y) .. " in blue") - printh(" " .. self:xy_idx(x2,y) .. " in yellow") + if debug then + printh("No-dupe at row " .. y .. " from row " .. y2) + printh(" " .. self:xy_idx(x1,y) .. " in blue") + printh(" " .. self:xy_idx(x2,y) .. " in yellow") + end self:fill(self:xy_idx(x1,y), BLUE) self:fill(self:xy_idx(x2,y), YELLOW) goto continue @@ -439,13 +469,21 @@ function Board.new() end, draw = function(self) + local w = 10 + local padding = 1 + local margin = 4 for k,v in ipairs(tiles) do local x,y = self:idx_xy(k) local color = v == BLUE and 9 or v == YELLOW and 3 or 1 - local w = 10 - local p = 1 - rectfill((x-1)*w + (x-1)*(p+1), (y-1)*w + (y-1)*(p+1), w, w, color) - print(k, (x-1)*w + (x-1)*(p+1), (y-1)*w + (y-1)*(p+1), 8) + rectfill( + margin + (x-1)*w + (x-1)*(padding+1), + margin + (y-1)*w + (y-1)*(padding+1), + 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 } @@ -456,19 +494,58 @@ end -- local board = Board.new() +local create = true 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 function _update60() - board:solve(true) - -- if time() % .01 == 0 then - -- end - if board:isComplete() then - if not board:isValid() then - printh("NOT VALID") - board:reset() - end + if not create then + board:solveStep() end end