improved MagicSquareSolver

This commit is contained in:
Louis Heredero 2024-04-30 13:51:57 +02:00
parent 37314cf9db
commit fe28ec45a5
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7

View File

@ -1,10 +1,14 @@
package magic_squares
import scala.collection.mutable.ArrayBuffer
abstract class MagicSquareSolver(initialGrid: Grid) extends Displayable {
protected var _initial: Grid = initialGrid
protected var grid: Grid = copy(_initial)
protected val _size: Int = _initial.length
protected val SUM: Int = _size * (_size * _size + 1) / 2
protected val DEBUG: Boolean = false
protected val NUMBERS: Array[Int] = Array.range(1, _size * _size + 1)
protected def print(grid: Grid): Unit = {
for (y: Int <- 0 until _size) {
@ -17,53 +21,67 @@ abstract class MagicSquareSolver(initialGrid: Grid) extends Displayable {
}
def solve(): Unit = {
val sol: Option[Grid] = solveFrom(_initial, 0, 0)
if (sol.isEmpty) {
println("No solution")
} else {
print(sol.get)
}
}
private def solveFrom(grid: Grid, x: Int, y: Int): Option[Grid] = {
if (DEBUG) println(s"Solving from $x, $y")
if (DEBUG) print(grid)
display(grid)
if (!isValid(grid)) {
if (DEBUG) println(" Grid is invalid")
return None
}
if (y >= _size) {
if (DEBUG) println(" Found solution")
return Some(grid)
}
var values: Array[Int] = Array(_initial(y)(x))
if (values(0) == 0) values = (1 to _size * _size).toArray
if (DEBUG) println(s" Values to test: " + values.mkString("[", ", ", "]"))
val newGrid: Grid = copy(grid)
var x2: Int = x + 1
var y2: Int = y
if (x2 >= _size) {
x2 -= _size
y2 += 1
}
for (i: Int <- values) {
if (DEBUG) println(s" Testing $i")
newGrid(y)(x) = i
val sol: Option[Grid] = solveFrom(newGrid, x2, y2)
if (sol.isDefined) {
if (DEBUG) println(" Found solution, collapsing call stack")
return sol
val inGrid: ArrayBuffer[Int] = ArrayBuffer.empty
for (y: Int <- 0 until _size) {
for (x: Int <- 0 until _size) {
if (grid(y)(x) != 0) {
inGrid.addOne(grid(y)(x))
}
}
}
if (DEBUG) println(s" No solution for this configuration")
return None
val solved: Boolean = _solve(inGrid.toArray)
if (solved) {
display(grid)
} else {
println("No solution")
}
}
private def isValid(grid: Grid): Boolean = {
private def _solve(inGrid: Array[Int]): Boolean = {
display(grid)
if (DEBUG) print(grid)
if (!isValid()) {
if (DEBUG) println(" Grid is invalid")
return false
}
val (x: Int, y: Int) = getNextEmpty()
if (x == -1) {
if (DEBUG) println(" Found solution")
return true
}
val numbers: Array[Int] = NUMBERS.diff(inGrid)
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(inGrid.appended(n))) {
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 isValid(): Boolean = {
val values: Array[Int] = grid.reduce((a, b) => a.concat(b)).filter(_ != 0)
if (values.distinct.length != values.length) return false
@ -113,7 +131,7 @@ object MagicSquareSolver {
Array(0, 0, 7),
Array(0, 9, 0)
)) with TextDisplay
solver1.solve()
//solver1.solve()
println()
/*
8,1,6
@ -126,7 +144,7 @@ object MagicSquareSolver {
Array(0, 0, 7),
Array(0, 8, 0)
)) with TextDisplay
solver2.solve()
//solver2.solve()
println()
/*
no solution