440 lines
14 KiB
Lua
440 lines
14 KiB
Lua
SudokuCanvas = {}
|
|
SudokuCanvas.__index = SudokuCanvas
|
|
|
|
function showValidOptionsForCurrentCell(self, x, y)
|
|
local s = sudoku.calCellValidOptions(self.board[2], y, x)
|
|
for num = 1, 9 do
|
|
self.smallNumbers[x][y][num].enabled = false
|
|
end
|
|
for _, num in ipairs(s) do
|
|
self.smallNumbers[x][y][num].enabled = true
|
|
end
|
|
end
|
|
|
|
function showValidOptionsForAllCells(self)
|
|
for x = 1, 9 do
|
|
for y = 1, 9 do
|
|
showValidOptionsForCurrentCell(self, x, y)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function selectSmallNumbersFont(cellSize)
|
|
local fntSize = 65
|
|
local margin = 0
|
|
while fntSize >= 5 do
|
|
fntSize = fntSize - 1
|
|
local fnt = love.graphics.newFont(fntSize)
|
|
-- margin = math.floor((cellSize - math.floor(fnt:getWidth("123") / 3) * 5) / 2)
|
|
margin = math.floor((cellSize - (fnt:getHeight() * 3 + 6)) / 2)
|
|
if margin >= 5 then return fnt, margin end
|
|
end
|
|
end
|
|
|
|
local function createSNumTable()
|
|
local smallNumbers = {}
|
|
for x = 1, 9 do
|
|
smallNumbers[x] = {}
|
|
for y = 1, 9 do
|
|
smallNumbers[x][y] = {}
|
|
for num = 1, 9 do
|
|
smallNumbers[x][y][num] = {x=0, y=0, enabled=false}
|
|
end
|
|
end
|
|
end
|
|
return smallNumbers
|
|
end
|
|
|
|
local function calSmallNumbersCoordinates(grid, smallNumbers)
|
|
local smallNumbers = smallNumbers or createSNumTable()
|
|
local cellSize = grid[1][1].x2 - grid[1][1].x1
|
|
local font, my = selectSmallNumbersFont(cellSize)
|
|
local mx = math.floor((cellSize - math.floor(font:getWidth("123") / 3) * 5) / 2)
|
|
-- local my = math.floor(mx / 2)
|
|
local dx = math.floor((cellSize - 2 * mx) / 3) + 2
|
|
local dy = math.floor((cellSize - 2 * my) / 3) + 2
|
|
for x = 1, 9 do
|
|
for y = 1, 9 do
|
|
local x1 = grid.x1 + (x - 1) * cellSize
|
|
local y1 = grid.y1 + (y - 1) * cellSize
|
|
local n = 1
|
|
for j = 1, 3 do
|
|
for i = 1, 3 do
|
|
local x2 = x1 + mx + (i-1) * dx
|
|
local y2 = y1 + my + (j-1) * dy
|
|
smallNumbers[x][y][n].x = x2
|
|
smallNumbers[x][y][n].y = y2
|
|
n = n + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
smallNumbers.font = font
|
|
return smallNumbers
|
|
end
|
|
|
|
local function buildBigNumbers(grid, fonts)
|
|
local cellSize = grid[1][1].x2 - grid[1][1].x1
|
|
local fntSize = math.floor(cellSize * 0.9)
|
|
local bigNumbers = {}
|
|
|
|
if fonts.typedBig and fonts.typedBig ~= "" then
|
|
bigNumbers.typedFont = love.graphics.newFont(fonts.typedBig, fntSize)
|
|
else
|
|
bigNumbers.typedFont = love.graphics.newFont(fntSize)
|
|
end
|
|
if fonts.handWrittenBig and fonts.handWrittenBig ~= "" then
|
|
bigNumbers.handWrittenFont = love.graphics.newFont(fonts.handWrittenBig, fntSize)
|
|
else
|
|
bigNumbers.handWrittenFont = love.graphics.newFont(fntSize)
|
|
end
|
|
|
|
local typedHeight = bigNumbers.typedFont:getHeight()
|
|
local handWrittenHeight = bigNumbers.handWrittenFont:getHeight()
|
|
local typedWidth = {}
|
|
local handWrittenWidth = {}
|
|
for i = 1, 9 do
|
|
local c = tostring(i)
|
|
typedWidth[i] = bigNumbers.typedFont:getWidth(c)
|
|
handWrittenWidth[i] = bigNumbers.handWrittenFont:getWidth(c)
|
|
end
|
|
|
|
for x = 1, 9 do
|
|
bigNumbers[x] = {}
|
|
for y = 1, 9 do
|
|
bigNumbers[x][y] = {}
|
|
local half = math.floor(cellSize / 2)
|
|
for num = 1, 9 do
|
|
bigNumbers[x][y][num] = {
|
|
typed = {
|
|
x = grid[x][y].x1 + half - math.floor(typedWidth[num] / 2),
|
|
y = grid[x][y].y1 + half - math.floor(typedHeight / 2),
|
|
},
|
|
handWritten = {
|
|
x = grid[x][y].x1 + half - math.floor(handWrittenWidth[num] / 2),
|
|
y = grid[x][y].y1 + half - math.floor(handWrittenHeight / 2),
|
|
},
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
return bigNumbers
|
|
end
|
|
|
|
local function buildGrid(x, y, cellSize)
|
|
local grid = {}
|
|
grid.x1 = x
|
|
grid.y1 = y
|
|
grid.x2 = x + 9 * cellSize
|
|
grid.y2 = y + 9 * cellSize
|
|
for i = 1, 9 do
|
|
grid[i] = {}
|
|
for j = 1, 9 do
|
|
local x = grid.x1 + (i - 1) * cellSize
|
|
local y = grid.y1 + (j - 1) * cellSize
|
|
grid[i][j] = {x1=x, y1=y, x2=x+cellSize, y2=y+cellSize}
|
|
end
|
|
end
|
|
local n = 0
|
|
local m = 0
|
|
grid.vline = {}
|
|
for x = grid.x1, grid.x2, cellSize do
|
|
n = n + 1
|
|
if n % 3 ~= 1 then
|
|
m = m + 1
|
|
grid.vline[m] = {x1=x, y1=grid.y1, x2=x, y2=grid.y1+9*cellSize}
|
|
end
|
|
end
|
|
n = 0
|
|
m = 0
|
|
grid.hline = {}
|
|
for y = grid.y1, grid.y2, cellSize do
|
|
n = n + 1
|
|
if n % 3 ~= 1 then
|
|
m = m + 1
|
|
grid.hline[m] = {x1=grid.x1, y1=y, x2=grid.x1+9*cellSize, y2=y}
|
|
end
|
|
end
|
|
n = 0
|
|
grid.vbline = {}
|
|
for x = grid.x1, grid.x2, cellSize * 3 do
|
|
n = n + 1
|
|
grid.vbline[n] = {x1=x, y1=grid.y1, x2=x, y2=grid.y1+9*cellSize}
|
|
end
|
|
n = 0
|
|
grid.hbline = {}
|
|
for y = grid.y1, grid.y2, cellSize * 3 do
|
|
n = n + 1
|
|
grid.hbline[n] = {x1=grid.x1, y1=y, x2=grid.x1+9*cellSize, y2=y}
|
|
end
|
|
return grid
|
|
end
|
|
|
|
function SudokuCanvas:resize(size, x, y)
|
|
x = x or self.x1
|
|
y = y or self.y1
|
|
self.cellSize = math.floor(size / 9)
|
|
self.size = self.cellSize * 9
|
|
self.x1 = x
|
|
self.y1 = y
|
|
self.x2 = x + size
|
|
self.y2 = y + size
|
|
self.grid = buildGrid(x, y, self.cellSize)
|
|
self.smallNumbers = calSmallNumbersCoordinates(self.grid, self.smallNumbers)
|
|
self.bigNumbers = buildBigNumbers(self.grid, self.fonts)
|
|
end
|
|
|
|
function SudokuCanvas:setBoard(board, board2)
|
|
local board2 = board2 or board
|
|
self.board = {}
|
|
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)
|
|
local options = options or {}
|
|
local cellSize = math.floor(size / 9)
|
|
local size = cellSize * 9
|
|
local o = {
|
|
x1 = x,
|
|
y1 = y,
|
|
x2 = x + size,
|
|
y2 = y + size,
|
|
size = size,
|
|
cellSize = cellSize,
|
|
cursor = {x=1, y=1, mode="big"},
|
|
fonts = options.fonts,
|
|
colors = options.colors,
|
|
enabled = true,
|
|
focused = true,
|
|
}
|
|
o.grid = buildGrid(x, y, cellSize)
|
|
o.smallNumbers = calSmallNumbersCoordinates(o.grid)
|
|
o.bigNumbers = buildBigNumbers(o.grid, o.fonts)
|
|
if options.enabled == false then o.enabled = false end
|
|
if options.focused == false then o.focused = false end
|
|
if not o.enabled then o.cursorOn = false; o.focused = false end
|
|
setmetatable(o, SudokuCanvas)
|
|
return o
|
|
end
|
|
|
|
function SudokuCanvas:enable()
|
|
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
|
|
|
|
-- grid
|
|
love.graphics.setLineWidth(1)
|
|
uiUtils.setColor(self.colors.thinLines)
|
|
for i = 1, 6 do
|
|
love.graphics.line(grid.vline[i].x1, grid.vline[i].y1, grid.vline[i].x2, grid.vline[i].y2)
|
|
love.graphics.line(grid.hline[i].x1, grid.hline[i].y1, grid.hline[i].x2, grid.hline[i].y2)
|
|
end
|
|
love.graphics.setLineWidth(2)
|
|
uiUtils.setColor(self.colors.thickLines)
|
|
for i = 1, 4 do
|
|
love.graphics.line(grid.vbline[i].x1, grid.vbline[i].y1, grid.vbline[i].x2, grid.vbline[i].y2)
|
|
love.graphics.line(grid.hbline[i].x1, grid.hbline[i].y1, grid.hbline[i].x2, grid.hbline[i].y2)
|
|
end
|
|
|
|
-- smallNumbers
|
|
love.graphics.setFont(self.smallNumbers.font)
|
|
for x = 1, 9 do
|
|
for y = 1, 9 do
|
|
for i = 1, 9 do
|
|
if self.board[2][y][x] == 0 then
|
|
local x1 = self.smallNumbers[x][y][i].x
|
|
local y1 = self.smallNumbers[x][y][i].y
|
|
if self.smallNumbers[x][y][i].enabled then
|
|
uiUtils.setColor(self.colors.smallNumbersEnabled)
|
|
else
|
|
uiUtils.setColor(self.colors.smallNumbersDisabled)
|
|
end
|
|
love.graphics.print(tostring(i), x1, y1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- bigNumbers
|
|
for x = 1, 9 do
|
|
for y = 1, 9 do
|
|
if self.board[1][y][x] ~= 0 then
|
|
-- print(y, x, self.board[1][y][x])
|
|
local num = self.board[1][y][x]
|
|
local px = self.bigNumbers[x][y][num].typed.x
|
|
local py = self.bigNumbers[x][y][num].typed.y
|
|
love.graphics.setFont(self.bigNumbers.typedFont)
|
|
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)
|
|
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
|
|
end
|
|
|
|
-- cursor
|
|
local x = grid[self.cursor.x][self.cursor.y].x1
|
|
local y = grid[self.cursor.x][self.cursor.y].y1
|
|
if self.board[1][self.cursor.y][self.cursor.x] == 0 then
|
|
if self.cursor.mode == "big" then
|
|
uiUtils.setColor(self.colors.cursorEditBig)
|
|
else
|
|
uiUtils.setColor(self.colors.cursorEditSmall)
|
|
end
|
|
else
|
|
uiUtils.setColor(self.colors.cursorNoEdit)
|
|
end
|
|
love.graphics.setLineWidth(3)
|
|
love.graphics.rectangle("line", x+3, y+3, self.cellSize-6, self.cellSize-6, 10, 10)
|
|
end
|
|
|
|
function SudokuCanvas:keypressed(key)
|
|
local x = self.cursor.x
|
|
local y = self.cursor.y
|
|
local mode = self.cursor.mode
|
|
if key == "-" then
|
|
local size = self.size - math.floor(self.size * .05)
|
|
if size >= 300 then
|
|
self:resize(size)
|
|
end
|
|
elseif key == "=" then
|
|
size = self.size + math.floor(self.size * .05)
|
|
self:resize(size)
|
|
elseif key:match("[1-9]") then
|
|
local num = key:byte() - 48
|
|
if self.board[1][y][x] == 0 then
|
|
if mode == "big" then
|
|
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
|
|
end
|
|
end
|
|
end
|
|
elseif key == "right" or key == "l" then
|
|
x = x + 1
|
|
if x > 9 then x = 1 end
|
|
elseif key == "left" or key == "h" then
|
|
x = x - 1
|
|
if x < 1 then x = 9 end
|
|
elseif key == "down" or key == "j" then
|
|
y = y + 1
|
|
if y > 9 then y = 1 end
|
|
elseif key == "up" or key == "k" then
|
|
y = y - 1
|
|
if y < 1 then y = 9 end
|
|
elseif key == "tab" then
|
|
if mode == "big" then
|
|
self.board[3][y][x] = self.board[2][y][x]
|
|
self.board[2][y][x] = 0
|
|
mode = "small"
|
|
else
|
|
self.board[2][y][x] = self.board[3][y][x]
|
|
mode = "big"
|
|
end
|
|
elseif key == "s" then
|
|
showValidOptionsForCurrentCell(self, x, y)
|
|
elseif key == "a" then
|
|
showValidOptionsForAllCells(self)
|
|
end
|
|
self.cursor.x = x
|
|
self.cursor.y = y
|
|
self.cursor.mode = mode
|
|
end
|
|
|
|
function SudokuCanvas:mousepressed(x, y, button, istouch)
|
|
local grid = self.grid
|
|
local inBoard = false
|
|
local canChange = false
|
|
local isSameCell = false
|
|
local dx = math.floor(self.cellSize / 3)
|
|
local cx = 0
|
|
local cy = 0
|
|
local mode = self.cursor.mode
|
|
local mx = 0
|
|
local my = 0
|
|
|
|
local n = 0
|
|
if x > grid.x1 and x < grid.x2 and y > grid.y1 and y < grid.y2 then
|
|
inBoard = true
|
|
cx = math.floor((x - grid.x1) / self.cellSize) + 1
|
|
cy = math.floor((y - grid.y1) / self.cellSize) + 1
|
|
mx = math.floor((x - grid[cx][cy].x1) / dx) + 1
|
|
my = math.floor((y - grid[cx][cy].y1) / dx) + 1
|
|
num = mx + 3 * (my - 1)
|
|
if self.board[1][cy][cx] == 0 then canChange = true end
|
|
if self.cursor.x == cx and self.cursor.y == cy then isSameCell = true end
|
|
end
|
|
if canChange then
|
|
if button == 1 then
|
|
if isSameCell and self.cursor.mode == "small" then
|
|
self.smallNumbers[cx][cy][num].enabled = not self.smallNumbers[cx][cy][num].enabled
|
|
end
|
|
elseif button == 2 then
|
|
if isSameCell then
|
|
if self.cursor.mode == "big" then
|
|
self.board[2][cy][cx] = 0
|
|
self.cursor.mode = "small"
|
|
else
|
|
self.cursor.mode = "big"
|
|
end
|
|
end
|
|
end
|
|
|
|
self.cursor.x = cx
|
|
self.cursor.y = cy
|
|
end
|
|
end
|
|
|
|
setmetatable(SudokuCanvas, {__call=SudokuCanvas.new})
|
|
return SudokuCanvas
|