added SudokuSolver

This commit is contained in:
Louis Heredero 2024-04-30 14:28:34 +02:00
parent fe28ec45a5
commit 27918e7a35
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
2 changed files with 170 additions and 0 deletions

View File

@ -0,0 +1,61 @@
package magic_squares.sudoku
import hevs.graphics.FunGraphics
import magic_squares.{Displayable, Grid}
import java.awt.{Color, Font}
import javax.swing.SwingConstants
trait GraphicsDisplay extends Displayable {
private var _win: Option[FunGraphics] = None
private val WIDTH: Int = 400
private val HEIGHT: Int = 400
private val MARGIN: Int = 20
private val FONT: Font = new Font("Arial", Font.PLAIN, 24)
override def display(g: Grid): Unit = {
if (_win.isEmpty) {
_win = Some(new FunGraphics(WIDTH, HEIGHT))
}
val win: FunGraphics = _win.get
win.clear()
val size: Int = SudokuSolver.SIZE
val squareSize: Int = SudokuSolver.SQUARE_SIZE
val w: Int = WIDTH - 2 * MARGIN
val h: Int = HEIGHT - 2 * MARGIN
val gridSize: Int = math.min(w, h)
val cellSize: Int = gridSize / size
val ox: Int = (WIDTH - gridSize) / 2
val oy: Int = (HEIGHT - gridSize) / 2
win.setPenWidth(2)
win.drawRect(ox, oy, gridSize, gridSize)
for (i: Int <- 1 until size / squareSize) {
win.drawLine(ox + cellSize * squareSize * i, oy, ox + cellSize * squareSize * i, oy + gridSize)
win.drawLine(ox, oy + cellSize * squareSize * i, ox + gridSize, oy + cellSize * squareSize * i)
}
win.setPenWidth(1)
for (i: Int <- 1 until size) {
win.drawLine(ox + cellSize * i, oy, ox + cellSize * i, oy + gridSize)
win.drawLine(ox, oy + cellSize * i, ox + gridSize, oy + cellSize * i)
}
for (y: Int <- 0 until size) {
for (x: Int <- 0 until size) {
val v: Int = g(y)(x)
if (v != 0) {
win.drawString(
(ox + cellSize * (x + 0.5)).toInt,
(oy + cellSize * (y + 0.5)).toInt,
v.toString,
FONT,
Color.BLACK,
SwingConstants.CENTER,
SwingConstants.CENTER
)
}
}
}
win.syncGameLogic(60)
}
}

View File

@ -0,0 +1,109 @@
package magic_squares.sudoku
import magic_squares.{Displayable, Grid}
import scala.collection.mutable.ArrayBuffer
abstract class SudokuSolver(initialGrid: Grid) extends Displayable {
protected var _initial: Grid = initialGrid
protected var grid: Grid = copy(_initial)
protected val SIZE: Int = SudokuSolver.SIZE
protected val SQUARE_SIZE: Int = SudokuSolver.SQUARE_SIZE
protected val DEBUG: Boolean = false
protected val NUMBERS: Array[Int] = Array.range(1, SIZE + 1)
protected def print(grid: Grid): Unit = {
for (y: Int <- 0 until SIZE) {
println(grid(y).mkString(","))
}
}
protected def copy(grid: Grid): Grid = {
return grid.map(_.clone())
}
def solve(): Unit = {
val solved: Boolean = _solve()
if (solved) {
display(grid)
} else {
println("No solution")
}
}
private def _solve(): Boolean = {
display(grid)
if (DEBUG) print(grid)
val (x: Int, y: Int) = getNextEmpty()
if (x == -1) {
if (DEBUG) println(" Found solution")
return true
}
val numbers: Array[Int] = getPossibleNumbers(x, y)
if (numbers.isEmpty) {
return false
}
if (DEBUG) println(s" Values to test: " + numbers.mkString("[", ", ", "]"))
for (n: Int <- numbers) {
if (DEBUG) println(s" Testing $n")
grid(y)(x) = n
if (_solve()) {
if (DEBUG) println(" Found solution, collapsing call stack")
return true
}
}
grid(y)(x) = 0
if (DEBUG) println(s" No solution for this configuration")
return false
}
private def getNextEmpty(): (Int, Int) = {
for (y: Int <- 0 until SIZE) {
for (x: Int <- 0 until SIZE) {
if (grid(y)(x) == 0) {
return (x, y)
}
}
}
return (-1, -1)
}
private def getPossibleNumbers(x: Int, y: Int): Array[Int] = {
val inGrid: ArrayBuffer[Int] = grid(y).concat(grid.map(_(x))).to(ArrayBuffer)
val sx: Int = (x / 3) * 3
val sy: Int = (y / 3) * 3
for (dy: Int <- 0 until SQUARE_SIZE) {
for (dx: Int <- 0 until SQUARE_SIZE) {
inGrid.addOne(grid(sy + dy)(sx + dx))
}
}
return NUMBERS.diff(inGrid.distinct)
}
}
object SudokuSolver {
val SIZE: Int = 9
val SQUARE_SIZE: Int = SIZE / 3
def main(args: Array[String]): Unit = {
val solver1: SudokuSolver = new SudokuSolver(Array(
Array(5,3,0, 0,7,0, 0,0,0),
Array(6,0,0, 1,9,5, 0,0,0),
Array(0,9,8, 0,0,0, 0,6,0),
Array(8,0,0, 0,6,0, 0,0,3),
Array(4,0,0, 8,0,3, 0,0,1),
Array(7,0,0, 0,2,0, 0,0,6),
Array(0,6,0, 0,0,0, 2,8,0),
Array(0,0,0, 4,1,9, 0,0,5),
Array(0,0,0, 0,8,0, 0,7,9),
)) with GraphicsDisplay
solver1.solve()
}
}