magic square solver

This commit is contained in:
Louis Heredero 2024-04-23 14:16:21 +02:00
parent 124b4c7a33
commit 8e9567e1a2
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
2 changed files with 149 additions and 0 deletions

View File

@ -0,0 +1,146 @@
package magic_squares
class MagicSquareSolver(initialGrid: Grid) {
protected var _initial: Grid = initialGrid
protected val _size: Int = _initial.length
protected val SUM: Int = 15
protected val DEBUG: Boolean = false
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 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)
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 9).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
}
}
if (DEBUG) println(s" No solution for this configuration")
return None
}
private def isValid(grid: Grid): Boolean = {
val values: Array[Int] = grid.reduce((a, b) => a.concat(b)).filter(_ != 0)
if (values.distinct.length != values.length) return false
val diag1: Array[Int] = new Array(_size)
val diag2: Array[Int] = new Array(_size)
for (i: Int <- 0 until _size) {
val row: Array[Int] = grid(i)
val col: Array[Int] = grid.map(_(i))
diag1(i) = row(i)
diag2(i) = col(_size - i - 1)
if (!isLineValid(row)) {
if (DEBUG) println(s" -> row $i is invalid: " + row.mkString("[", ", ", "]"))
return false
}
if (!isLineValid(col)) {
if (DEBUG) println(s" -> column $i is invalid: " + col.mkString("[", ", ", "]"))
return false
}
}
if (!isLineValid(diag1)) {
if (DEBUG) println(s" -> diag1 is invalid: " + diag1.mkString("[", ", ", "]"))
return false
}
if (!isLineValid(diag2)) {
if (DEBUG) println(s" -> diag2 is invalid: " + diag2.mkString("[", ", ", "]"))
return false
}
return true
}
private def isLineValid(line: Array[Int]): Boolean = {
val sum: Int = line.sum
if (line.contains(0)) {
if (sum > SUM) return false
} else if (sum != SUM) return false
return true
}
}
object MagicSquareSolver {
def main(args: Array[String]): Unit = {
val solver1: MagicSquareSolver = new MagicSquareSolver(Array(
Array(8, 0, 0),
Array(0, 0, 7),
Array(0, 9, 0)
))
solver1.solve()
println()
/*
8,1,6
3,5,7
4,9,2
*/
val solver2: MagicSquareSolver = new MagicSquareSolver(Array(
Array(9, 0, 0),
Array(0, 0, 7),
Array(0, 8, 0)
))
solver2.solve()
println()
/*
no solution
*/
val solver3: MagicSquareSolver = new MagicSquareSolver(Array(
Array(0, 0, 2),
Array(0, 5, 7),
Array(0, 0, 0)
))
solver3.solve()
/*
4,9,2
3,5,7
8,1,6
*/
}
}

View File

@ -0,0 +1,3 @@
package object magic_squares {
type Grid = Array[Array[Int]]
}