diff --git a/main.lua b/main.lua index 3733b7b..c9a0d5b 100644 --- a/main.lua +++ b/main.lua @@ -1,4 +1,4 @@ -require "sudoku.utils" +sudoku = require "sudoku.sudoku" uiUtils = require "ui.utils" config = require "config" SudokuCanvas = require "ui.sudokucanvas" @@ -11,10 +11,10 @@ function love.load() love.mouse.setGrabbed(false) love.keyboard.setKeyRepeat(true) math.randomseed(os.time()) - local board = loadBoard(config.board.filePath) + board = sudoku.loadBoard(config.board.filePath) local width, height = love.graphics.getDimensions() sudokuCanvas = SudokuCanvas:new(200, 100, height/1.5, config.SudokuCanvas) - sudokuCanvas:setBoard(board) + sudokuCanvas:setBoard(board[1]) myFont = love.graphics.newFont(24) end diff --git a/sudoku/check.lua b/sudoku/check.lua deleted file mode 100644 index 3c9b381..0000000 --- a/sudoku/check.lua +++ /dev/null @@ -1,132 +0,0 @@ -local function checkCT(ct) - local r = {} - for i = 1, 8 do - for j = i+1, 9 do - if ct[i] == ct[j] and ct[i] ~= 0 then - table.insert(r, {i, j}) - end - end - end - if #r > 0 then return false, r end - return true -end - -local function findThisTable(this, that) - for i = 1, #that do - if #that[i] == #this then - local flag = true - for j = 1, #this do - if this[j] ~= that[i][j] then flag = false; break end - end - if flag then return true, i end - end - end - return false -end - -function check(board) - local rr = {} - for x = 1, 9 do - local ct = {} - for y = 1, 9 do - ct[y] = board[x][y] - end - local ok, r = checkCT(ct) - if not ok then - for _, p in ipairs(r) do - local t = {x, p[1], x, p[2], board[x][p[1]]} - if not findThisTable(t, rr) then - table.insert(rr, t) - end - end - end - end - for y = 1, 9 do - local ct = {} - for x = 1, 9 do - ct[x] = board[x][y] - end - local ok, r = checkCT(ct) - if not ok then - for _, p in ipairs(r) do - local t = {p[1], y, p[2], y, board[p[1]][y]} - if not findThisTable(t, rr) then - table.insert(rr, t) - end - end - end - end - for i = 0, 2 do - for j = 0, 2 do - local ct = {} - for x = 1, 3 do - for y = 1, 3 do - ct[(x-1)*3+y] = board[x+i*3][y+j*3] - end - end - local ok, r = checkCT(ct) - if not ok then - for _, p in ipairs(r) do - -- local x1 = ((p[1] - 1) // 3 + 1) + i * 3 - local x1 = math.floor((p[1] - 1) / 3 + 1) + i * 3 - local y1 = ((p[1] - 1) % 3 + 1) + j * 3 - -- local x2 = ((p[2] - 1) // 3 + 1) + i * 3 - local x2 = math.floor((p[2] - 1) / 3 + 1) + i * 3 - local y2 = ((p[2] - 1) % 3 + 1) + j * 3 - local t = {x1, y1, x2, y2, board[x1][y1]} - if not findThisTable(t, rr) then - table.insert(rr, t) - end - end - end - end - end - if #rr > 0 then - return false, rr - end - return true -end - -function checkSolved(board) - local r = {} - for i = 1, 9 do - for j = 1, 9 do - if board[i][j] < 1 or board[i][j] > 9 then - table.insert(r, {i, j, board[i][j]}) - end - end - end - local ok, rr = check(board) - if #r > 0 or (rr and #rr > 0) then - return false, r, rr - end - return true -end - -function pcheck(board) - local ok, r, rr = checkSolved(board) - if ok then - print("Board is solved!") - return - end - for _, p in ipairs(r) do - print(S("(%d, %d) = %d", unpack(p))) - end - for _, p in ipairs(rr) do - print(S("(%d, %d) = (%d, %d) = %d", unpack(p))) - end -end - -function scheck(board) - local msg = {} - local ok, r = check(board) - if ok then - return {"No Error!"} - end - for _, p in ipairs(r) do - local s = string.format("(%d, %d) = (%d, %d) = %d", unpack(p)) - print(s) - table.insert(msg, s) - end - return msg -end diff --git a/sudoku/sudoku.lua b/sudoku/sudoku.lua index ad40765..e2077a6 100644 --- a/sudoku/sudoku.lua +++ b/sudoku/sudoku.lua @@ -1,47 +1,85 @@ -require "sudoku.utils" -require "sudoku.check" +local utils = require "sudoku.utils" -function calValidOptions(b, x, y) - if b[x][y] ~= 0 then return {} end - local elm - local u = {} - local v = {} - for i = 1, 9 do - elm = b[x][i] - if elm ~= 0 and find(u, elm) == 0 then - table.insert(u, elm) +local sudoku = {} + +function sudoku.iterZones(board) + local row = 0 + local column = 0 + local block = 0 + return function() + local a = {} + local p = {} + if row < 9 then + row = row + 1 + for i = 1, 9 do + a[i] = board[row][i] + p[i] = {row, i} + end + return a, p end - elm = b[i][y] - if elm ~= 0 and find(u, elm) == 0 then - table.insert(u, elm) + if column < 9 then + column = column + 1 + for i = 1, 9 do + a[i] = board[i][column] + p[i] = {i, column} + end + return a, p + end + if block < 9 then + block = block + 1 + local dx = math.floor((block - 1) / 3) + local dy = (block - 1) % 3 + local n = 0 + for i = 1, 3 do + for j = 1, 3 do + local x = i + 3 * dx + local y = j + 3 * dy + n = n + 1 + a[n] = board[x][y] + p[n] = {x, y} + end + end + return a, p end end - -- local xc = ((x - 1) // 3) * 3 - -- local yc = ((y - 1) // 3) * 3 - local xc = math.floor((x - 1) / 3) * 3 - local yc = math.floor((y - 1) / 3) * 3 - for i = 1, 3 do - for j = 1, 3 do - elm = b[i+xc][j+yc] - if elm ~= 0 and find(u, elm) == 0 then - table.insert(u, elm) +end + +local function checkAUX(zone, pos) + local isComplete = true + local ok = true + local conflictList = {} + local n = 0 + for i = 1, 8 do + for j = i+1, 9 do + if zone[i] == 0 then + isComplete = false + elseif zone[i] == zone[j] then + ok = false + n = n + 1 + conflictList[n] = {x1=pos[i][1], y1=pos[i][2], x2=pos[j][1], y2=pos[j][2]} end end end - for i = 1, 9 do - if find(u, i) == 0 then table.insert(v, i) end - end - return v + return ok, isComplete, conflictList end -function buildSearchSpace(b) - local s = {} - for i = 1, 9 do - s[i] = {} - for j = 1, 9 do - s[i][j] = calValidOptions(b, i, j) +function sudoku.checkBoard(board) + local ok = true + local isComplete = true + local conflictList = {} + for zone, pos in sudoku.iterZones(board) do + local tOk, tIsComplete, tConflictList = checkAUX(zone, pos) + if not tOk then ok = false end + if not tIsComplete then isComplete = false end + for _, conflict in ipairs(tConflictList) do + table.insert(conflictList, conflict) end end - return s + return ok, isComplete, conflictList end +sudoku.cloneBoard = utils.cloneBoard +sudoku.createEmptyBoard = utils.createEmptyBoard +sudoku.loadBoard = utils.loadBoard +return sudoku + diff --git a/sudoku/utils.lua b/sudoku/utils.lua index c1516da..e9937b6 100644 --- a/sudoku/utils.lua +++ b/sudoku/utils.lua @@ -1,4 +1,21 @@ -function find(array, element) +local function table2string(t) + local myself = table2string + local l = {} + local n = 0 + for k, v in pairs(t) do + n = n + 1 + if type(v) == "table" then + l[n] = k .. ': ' .. myself(v) + elseif type(v) == "string" then + l[n] = k .. ': ' .. '"' .. v .. '"' + else + l[n] = k .. ': ' .. v + end + end + return "{" .. table.concat(l, ", ") .. "}" +end + +local function find(array, element) local index = 0 for i = 1, #array do if array[i] == element then @@ -9,13 +26,18 @@ function find(array, element) return index end -function showBoard(board) - for row = 1, 9 do - print(table.concat(board[row], " ")) +local function createEmptyBoard() + local b = {} + for i = 1, 9 do + b[i] = {} + for j = 1, 9 do + b[i][j] = 0 + end end + return b end -function cloneBoard(b) +local function cloneBoard(b) local c = {} for i = 1, 9 do c[i] = {} @@ -26,14 +48,14 @@ function cloneBoard(b) return c end -function loadBoard(fn) - local problem = {} - local solution = {} - local board = problem +local function loadBoard(fn) + local boards = {} local r = 0 + local board = {} for line in io.lines(fn) do if line:gsub("%s+", "") == "" then - board = solution + table.insert(boards, board) + board = {} r = 0 else r = r + 1 @@ -45,5 +67,18 @@ function loadBoard(fn) end end end - return problem, solution + table.insert(boards, board) + return boards end + +local function showBoard(board) + for row = 1, 9 do + print(table.concat(board[row], " ")) + end +end + +return { + createEmptyBoard = createEmptyBoard, + cloneBoard = cloneBoard, + loadBoard = loadBoard, +} diff --git a/sudokuGUI b/sudokuGUI new file mode 100755 index 0000000..1003ed0 --- /dev/null +++ b/sudokuGUI @@ -0,0 +1,3 @@ +#! /bin/sh + +love . diff --git a/ui/sudokucanvas.lua b/ui/sudokucanvas.lua index 073f319..26e5c33 100644 --- a/ui/sudokucanvas.lua +++ b/ui/sudokucanvas.lua @@ -1,20 +1,3 @@ -function table2string(t) - local myself = table2string - local l = {} - local n = 0 - for k, v in pairs(t) do - n = n + 1 - if type(v) == "table" then - l[n] = k .. ': ' .. myself(v) - elseif type(v) == "string" then - l[n] = k .. ': ' .. '"' .. v .. '"' - else - l[n] = k .. ': ' .. v - end - end - return "{" .. table.concat(l, ", ") .. "}" -end - SudokuCanvas = {} SudokuCanvas.__index = SudokuCanvas @@ -187,9 +170,11 @@ end function SudokuCanvas:setBoard(board, board2) local board2 = board2 or board self.board = {} - self.board[1] = cloneBoard(board) - self.board[2] = cloneBoard(board2) - self.board[3] = cloneBoard(board2) + self.board[1] = sudoku.cloneBoard(board) + self.board[2] = sudoku.cloneBoard(board2) + self.board[3] = sudoku.cloneBoard(board2) + -- self.board[4] = createEmptyBoard() + self:checkBoard() end function SudokuCanvas:new(x, y, size, options) @@ -225,6 +210,15 @@ end function SudokuCanvas:focus() end +function SudokuCanvas:checkBoard() + local ok, isComplete, conflictList = sudoku.checkBoard(self.board[2]) + self.board[4] = sudoku.createEmptyBoard() + for _, c in ipairs(conflictList) do + self.board[4][c.x1][c.y1] = 1 + self.board[4][c.x2][c.y2] = 1 + end +end + function SudokuCanvas:draw() local grid = self.grid @@ -270,14 +264,22 @@ function SudokuCanvas:draw() local px = self.bigNumbers[x][y][num].typed.x local py = self.bigNumbers[x][y][num].typed.y love.graphics.setFont(self.bigNumbers.typedFont) - uiUtils.setColor(self.colors.bigNumbersTyped) + if self.board[4][y][x] ~= 0 then + uiUtils.setColor(self.colors.bigNumbersError) + else + uiUtils.setColor(self.colors.bigNumbersTyped) + end love.graphics.print(tostring(num), px, py) elseif self.board[2][y][x] ~= 0 then local num = self.board[2][y][x] local px = self.bigNumbers[x][y][num].handWritten.x local py = self.bigNumbers[x][y][num].handWritten.y love.graphics.setFont(self.bigNumbers.handWrittenFont) - uiUtils.setColor(self.colors.bigNumbersHandWritten) + if self.board[4][y][x] ~= 0 then + uiUtils.setColor(self.colors.bigNumbersError) + else + uiUtils.setColor(self.colors.bigNumbersHandWritten) + end love.graphics.print(tostring(num), px, py) end end @@ -315,17 +317,25 @@ function SudokuCanvas:keypressed(key) local num = key:byte() - 48 if self.board[1][y][x] == 0 then if mode == "big" then - self.board[2][y][x] = num - self.board[3][y][x] = num + if self.board[2][y][x] == num then + self.board[2][y][x] = 0 + self.board[3][y][x] = 0 + else + self.board[2][y][x] = num + self.board[3][y][x] = num + end + self:checkBoard() else self.smallNumbers[x][y][num].enabled = not self.smallNumbers[x][y][num].enabled end + self:checkBoard() end elseif key == "delete" or key == "0" then if self.board[1][y][x] == 0 then if mode == "big" then self.board[2][y][x] = 0 self.board[3][y][x] = 0 + self:checkBoard() else for num = 1, 9 do self.smallNumbers[x][y][num].enabled = false