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