Skip to content

Instantly share code, notes, and snippets.

@ayeo
Last active February 15, 2020 09:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayeo/8314c6472dc9290b9fc3cf11ad70c6b8 to your computer and use it in GitHub Desktop.
Save ayeo/8314c6472dc9290b9fc3cf11ad70c6b8 to your computer and use it in GitHub Desktop.
Scala Sudoku Solver
import scala.collection.immutable.{Vector => $}
/**
* This is highly inspired by https://gist.github.com/pathikrit/a32e17832296befd6b94
* Actually only main recurssion block is changed for better readability
*
* See also excellent Computerphile video https://www.youtube.com/watch?v=G_UYXzGuqvM
*/
object Solver {
val n = 9
val s = Math.sqrt(n).toInt
type Board = Vector[Vector[Int]]
private def possibleDigits(board: Board, r: Int, c: Int): Seq[Int] = {
def cells(i: Int) = Seq(board(r)(i), board(i)(c), board(s * (r / s) + i / s)(s * (c / s) + i % s))
val used = board.indices.flatMap(cells)
(1 to 9).diff(used)
}
def solve(board: Board, cell: Int = 0): Option[Board] = (cell % n, cell / n) match {
case (0, 9) => Some(board) //cell=81 board is solved
case (r, c) if board(r)(c) > 0 => solve(board, cell + 1) //cell is already filled, go to next
case (r, c) =>
possibleDigits(board, r, c)
.flatMap(n => solve(board.updated(r, board(r).updated(c, n)))) //find next solution for each digit
.headOption //return first non-empty element (the ultimate solution) otherwise None
}
def print(board: Board): Unit = println(board.map(_.mkString(" ")).mkString("\n"))
}
object SudokuSolver extends App {
val board = $(
$(8, 0, 0, 0, 0, 7, 0, 9, 0),
$(0, 7, 0, 0, 2, 0, 0, 0, 8),
$(0, 0, 9, 6, 0, 0, 5, 0, 0),
$(0, 0, 5, 3, 0, 0, 9, 0, 0),
$(0, 1, 0, 0, 8, 0, 0, 0, 2),
$(6, 0, 0, 0, 0, 4, 0, 0, 0),
$(3, 0, 0, 0, 0, 0, 0, 1, 0),
$(0, 4, 0, 0, 0, 0, 0, 0, 7),
$(0, 0, 7, 0, 0, 0, 3, 0, 0)
)
Solver.solve(board).map(Solver.print)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment