-- -- constants -- local BLUE = 1 local YELLOW = 2 -- -- Utils -- local a = BLUE function idx_xy(idx, width) return (idx - 1) % width + 1, (idx - 1) \ width + 1 end function xy_idx(x, y, width) return ((y - 1) * width) + x end function map(tbl, f) local t = {} for k, v in pairs(tbl) do t[k] = f(v) end return t end function filter(tbl, f, keepindex) local ret = {} for k, v in pairs(tbl) do if f(v) then if keepindex then ret[k] = v else add(ret, v) end end end return ret end function slice(tbl, first, last, step) local sliced = {} for i = (first or 1), (last or #tbl), (step or 1) do sliced[(#sliced + 1)] = tbl[i] end return sliced end local _rectfill = rectfill function rectfill(x, y, w, h, col) _rectfill(x, y, x+w, y+h, col) end local _count = count function count(tbl, p) if type(p) != "function" then return _count(tbl, p) end local c = 0 for v in all(tbl) do if p(v) then c+=1 end end return c end -- -- Board -- local Board = {} function Board.new() local width = 6 local t = [[ 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2 ]] local tiles = split(t) return { getTile = function(self, idx) return tiles[idx] end, idx_xy = function(self, idx) return idx_xy(idx, width) end, xy_idx = function(self, x, y) return xy_idx(x, y, width) end, fill = function(self, idx, color, invert) if invert then color = color == YELLOW and BLUE or YELLOW end tiles[idx] = color end, getRows = function(self) local ret = {} for i = 1, width do add(ret, slice(tiles, ((i - 1) * width) + 1, i * width)) end return ret end, getCols = function(self) local ret = {} local rows = self.getRows(self) for i = 1, width do add(ret, map(rows, function(v) return v[i] end)) end return ret end, solve = function(self) self:surroundDoubles() self:splitTriples() self:fillLines() self:noIdenticalLines() end, surroundDoubles = function(self) for idx,v in ipairs(tiles) do local x,y = self:idx_xy(idx) if v == 0 then local neighbors = {} -- 2 tiles on the left if x >= 3 then add(neighbors, {idx, idx-1, idx-2}) end -- 2 tiles on the right if x <= width-2 then add(neighbors, {idx, idx+1, idx+2}) end -- 2 tiles on top if y >= 3 then add(neighbors, {idx, idx-width, idx - width*2}) end -- 2 tiles under if y <= width-2 then add(neighbors, {idx, idx+width, idx + width*2}) end -- only keep pairs that are identical (and not 0) neighbors = filter(neighbors, function (o) return tiles[o[2]] == tiles[o[3]] and tiles[o[2]] ~= 0 end) -- do the surrounding for item in all(neighbors) do if item[1] then printh("Surrounding at " .. item[1]) self:fill(item[1], tiles[item[2]], true) end end end end end, splitTriples = function(self) for idx, col in ipairs(tiles) do local x,y = self:idx_xy(idx) if col == 0 then if x > 1 and x < width then -- check horizontal local prev = tiles[idx-1] local next = tiles[idx+1] if prev ~= 0 and prev == next then printh("Splitting at " .. idx) self:fill(idx, prev, true) end end if y>1 and y < width then -- check vertical local prev = tiles[idx-width] local next = tiles[idx+width] if prev ~= 0 and prev == next then printh("Splitting at " .. idx) self:fill(idx, prev, true) end end end end end, fillLines = function(self) local rows = self:getRows() local cols = self:getCols() -- rows for y,row in ipairs(rows) do local a = count(row, function (a) return a == BLUE end) local b = count(row, function (a) return a == YELLOW end) if a ~= b then if a == width/2 then self:fillRow(y, YELLOW) end if b == width/2 then self:fillRow(y, BLUE) end end end -- columns for x,col in ipairs(cols) do local a = count(col, function (a) return a == BLUE end) local b = count(col, function (a) return a == YELLOW end) if a ~= b then if a == width/2 then self:fillCol(x, YELLOW) end if b == width/2 then self:fillCol(x, BLUE) end end end end, fillRow = function(self, y, color) 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 self:fill(i, color) end end end, fillCol = function(self, x, color) 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 self:fill(i, color) end end end, noIdenticalLines = function(self) end, draw = function(self) for k,v in ipairs(tiles) do local x,y = self:idx_xy(k) local color = v == BLUE and 12 or v == YELLOW and 10 or 1 rectfill((x-1)*10 + x*8 + 4, (y-1)*10 + y*8 + 4, 12, 12, color) end end } end -- -- main loop -- local board = Board.new() function _init() end function _update() end function _draw() cls() if time() % 1 == 0 then board:solve() end board:draw() end