improved MagicSquareSolver
This commit is contained in:
parent
37314cf9db
commit
fe28ec45a5
@ -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)
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def solveFrom(grid: Grid, x: Int, y: Int): Option[Grid] = {
|
||||
if (DEBUG) println(s"Solving from $x, $y")
|
||||
if (DEBUG) print(grid)
|
||||
val solved: Boolean = _solve(inGrid.toArray)
|
||||
if (solved) {
|
||||
display(grid)
|
||||
if (!isValid(grid)) {
|
||||
} else {
|
||||
println("No solution")
|
||||
}
|
||||
}
|
||||
|
||||
private def _solve(inGrid: Array[Int]): Boolean = {
|
||||
display(grid)
|
||||
|
||||
if (DEBUG) print(grid)
|
||||
if (!isValid()) {
|
||||
if (DEBUG) println(" Grid is invalid")
|
||||
return None
|
||||
return false
|
||||
}
|
||||
if (y >= _size) {
|
||||
|
||||
val (x: Int, y: Int) = getNextEmpty()
|
||||
if (x == -1) {
|
||||
if (DEBUG) println(" Found solution")
|
||||
return Some(grid)
|
||||
return true
|
||||
}
|
||||
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 numbers: Array[Int] = NUMBERS.diff(inGrid)
|
||||
|
||||
val newGrid: Grid = copy(grid)
|
||||
var x2: Int = x + 1
|
||||
var y2: Int = y
|
||||
if (x2 >= _size) {
|
||||
x2 -= _size
|
||||
y2 += 1
|
||||
}
|
||||
if (DEBUG) println(s" Values to test: " + numbers.mkString("[", ", ", "]"))
|
||||
|
||||
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) {
|
||||
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 sol
|
||||
return true
|
||||
}
|
||||
}
|
||||
grid(y)(x) = 0
|
||||
|
||||
if (DEBUG) println(s" No solution for this configuration")
|
||||
return None
|
||||
return false
|
||||
}
|
||||
|
||||
private def isValid(grid: Grid): Boolean = {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user