added SudokuSolver
This commit is contained in:
parent
fe28ec45a5
commit
27918e7a35
61
src/magic_squares/sudoku/GraphicsDisplay.scala
Normal file
61
src/magic_squares/sudoku/GraphicsDisplay.scala
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
109
src/magic_squares/sudoku/SudokuSolver.scala
Normal file
109
src/magic_squares/sudoku/SudokuSolver.scala
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user