progs/sudoku_test.scala
changeset 383 c02929f2647c
equal deleted inserted replaced
382:1bd800376e0c 383:c02929f2647c
       
     1 // Sudoku
       
     2 //========
       
     3 
       
     4 // call parallel version with
       
     5 //
       
     6 // scala -cp scala-parallel-collections_2.13-0.2.0.jar sudoku_test.scala 
       
     7 //
       
     8 // or
       
     9 //
       
    10 // scalac -cp scala-parallel-collections_2.13-0.2.0.jar sudoku_test.scala
       
    11 // java -cp .:scala-library-2.13.0.jar:scala-parallel-collections_2.13-0.2.0.jar Sudoku
       
    12 
       
    13 object Sudoku extends App { 
       
    14 
       
    15 import scala.collection.parallel.CollectionConverters._
       
    16 
       
    17 type Pos = (Int, Int)
       
    18 val emptyValue = '.'
       
    19 val maxValue = 9
       
    20 
       
    21 val allValues = "123456789".toList
       
    22 val indexes = (0 to 8).toList
       
    23 
       
    24 
       
    25 def empty(game: String) = game.indexOf(emptyValue)
       
    26 def isDone(game: String) = empty(game) == -1 
       
    27 def emptyPosition(game: String) = {
       
    28   val e = empty(game)
       
    29   (e % maxValue, e / maxValue)
       
    30 }
       
    31 
       
    32 
       
    33 def get_row(game: String, y: Int) = indexes.map(col => game(y * maxValue + col))
       
    34 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * maxValue))
       
    35 
       
    36 def get_box(game: String, pos: Pos): List[Char] = {
       
    37     def base(p: Int): Int = (p / 3) * 3
       
    38     val x0 = base(pos._1)
       
    39     val y0 = base(pos._2)
       
    40     for (x <- (x0 until x0 + 3).toList;
       
    41          y <- (y0 until y0 + 3).toList) yield game(x + y * maxValue)
       
    42 }         
       
    43 
       
    44 
       
    45 def update(game: String, pos: Int, value: Char): String = 
       
    46   game.updated(pos, value)
       
    47 
       
    48 def toAvoid(game: String, pos: Pos): List[Char] = 
       
    49   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
       
    50 
       
    51 def candidates(game: String, pos: Pos): List[Char] = 
       
    52   allValues.diff(toAvoid(game, pos))
       
    53 
       
    54 def search(game: String): List[String] = {
       
    55   if (isDone(game)) List(game)
       
    56   else {
       
    57     val cs = candidates(game, emptyPosition(game))
       
    58     cs.par.map(c => search(update(game, empty(game), c))).toList.flatten
       
    59   }
       
    60 }
       
    61 
       
    62 
       
    63 def pretty(game: String): String = 
       
    64   "\n" + (game.grouped(maxValue).mkString(",\n"))
       
    65 
       
    66 
       
    67 val game2 = """8........
       
    68               |..36.....
       
    69               |.7..9.2..
       
    70               |.5...7...
       
    71               |....457..
       
    72               |...1...3.
       
    73               |..1....68
       
    74               |..85...1.
       
    75               |.9....4..""".stripMargin.replaceAll("\\n", "")
       
    76 
       
    77 // for measuring time
       
    78 def time_needed[T](i: Int, code: => T) = {
       
    79   val start = System.nanoTime()
       
    80   for (j <- 1 to i) code
       
    81   val end = System.nanoTime()
       
    82   s"${(end - start) / 1.0e9} secs"
       
    83 }
       
    84 
       
    85 
       
    86 println(time_needed(10, search(game2)))
       
    87 
       
    88 }