diff --git a/src/magic_squares/MagicSquareSolver.scala b/src/magic_squares/MagicSquareSolver.scala index 31cb763..a521fa2 100644 --- a/src/magic_squares/MagicSquareSolver.scala +++ b/src/magic_squares/MagicSquareSolver.scala @@ -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