author | Christian Urban <christian.urban@kcl.ac.uk> |
Wed, 06 Mar 2024 18:20:25 +0000 | |
changeset 484 | c4561fc667b7 |
parent 467 | 9b5165b8a762 |
permissions | -rw-r--r-- |
268 | 1 |
// Sudoku |
2 |
//======== |
|
3 |
||
301 | 4 |
// call parallel version with |
5 |
// |
|
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
6 |
// scala -cp scala-parallel-collections_3-1.0.4.jar sudoku.scala |
301 | 7 |
// |
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
8 |
// java -cp .:scala3-library_3-3.2.2.jar:scala-parallel-collections_3-1.0.4.jar Sudoku |
301 | 9 |
|
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
10 |
|
268 | 11 |
|
12 |
import scala.collection.parallel.CollectionConverters._ |
|
13 |
||
14 |
type Pos = (Int, Int) |
|
15 |
val emptyValue = '.' |
|
16 |
val maxValue = 9 |
|
17 |
||
18 |
val allValues = "123456789".toList |
|
19 |
val indexes = (0 to 8).toList |
|
20 |
||
21 |
||
22 |
def empty(game: String) = game.indexOf(emptyValue) |
|
23 |
def isDone(game: String) = empty(game) == -1 |
|
384 | 24 |
|
383 | 25 |
//def emptyPosition(game: String) : Pos = |
26 |
// (empty(game) % maxValue, empty(game) / maxValue) |
|
384 | 27 |
|
383 | 28 |
def emptyPosition(game: String) = { |
29 |
val e = empty(game) |
|
30 |
(e % maxValue, e / maxValue) |
|
31 |
} |
|
268 | 32 |
|
33 |
||
34 |
def get_row(game: String, y: Int) = indexes.map(col => game(y * maxValue + col)) |
|
35 |
def get_col(game: String, x: Int) = indexes.map(row => game(x + row * maxValue)) |
|
36 |
||
37 |
def get_box(game: String, pos: Pos): List[Char] = { |
|
38 |
def base(p: Int): Int = (p / 3) * 3 |
|
39 |
val x0 = base(pos._1) |
|
40 |
val y0 = base(pos._2) |
|
41 |
for (x <- (x0 until x0 + 3).toList; |
|
42 |
y <- (y0 until y0 + 3).toList) yield game(x + y * maxValue) |
|
43 |
} |
|
44 |
||
45 |
||
46 |
def update(game: String, pos: Int, value: Char): String = |
|
47 |
game.updated(pos, value) |
|
48 |
||
49 |
def toAvoid(game: String, pos: Pos): List[Char] = |
|
50 |
(get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
|
51 |
||
52 |
def candidates(game: String, pos: Pos): List[Char] = |
|
53 |
allValues.diff(toAvoid(game, pos)) |
|
54 |
||
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
55 |
// search for all solutions |
268 | 56 |
def search(game: String): List[String] = { |
57 |
if (isDone(game)) List(game) |
|
58 |
else |
|
467 | 59 |
candidates(game, emptyPosition(game)).par. |
268 | 60 |
map(c => search(update(game, empty(game), c))).toList.flatten |
61 |
} |
|
62 |
||
450 | 63 |
|
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
64 |
// search for single solution |
325 | 65 |
def search1T(games: List[String]): Option[String] = games match { |
66 |
case Nil => None |
|
67 |
case game::rest => { |
|
68 |
if (isDone(game)) Some(game) |
|
69 |
else { |
|
70 |
val cs = candidates(game, emptyPosition(game)) |
|
71 |
search1T(cs.map(c => update(game, empty(game), c)) ::: rest) |
|
72 |
} |
|
73 |
} |
|
74 |
} |
|
75 |
||
329 | 76 |
def pretty(game: String): String = |
383 | 77 |
"\n" + (game.grouped(maxValue).mkString(",\n")) |
329 | 78 |
|
79 |
||
301 | 80 |
// a list of hard games according to Andrew Coles and Peter Norvig |
268 | 81 |
|
82 |
val hard_games = |
|
321 | 83 |
List("52...6.........7.13...........4..8..6......5...........418.........3..2...87.....", |
301 | 84 |
"6.....8.3.4.7.................5.4.7.3..2.....1.6.......2.....5.....8.6......1....", |
85 |
"48.3............71.2.......7.5....6....2..8.............1.76...3.....4......5....", |
|
86 |
"......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.", |
|
87 |
"6.2.5.........3.4..........43...8....1....2........7..5..27...........81...6.....", |
|
88 |
".524.........7.1..............8.2...3.....6...9.5.....1.6.3...........897........", |
|
89 |
"6.2.5.........4.3..........43...8....1....2........7..5..27...........81...6.....", |
|
384 | 90 |
".923.........8.1...........1.7.4...........658.........6.5.2...4.....7.....9.....", |
301 | 91 |
"85...24..72......9..4.........1.7..23.5...9...4...........8..7..17..........36.4.", |
268 | 92 |
"..53.....8......2..7..1.5..4....53...1..7...6..32...8..6.5....9..4....3......97..", |
93 |
"12..4......5.69.1...9...5.........7.7...52.9..3......2.9.6...5.4..9..8.1..3...9.4", |
|
94 |
"...57..3.1......2.7...234......8...4..7..4...49....6.5.42...3.....7..9....18.....", |
|
95 |
"7..1523........92....3.....1....47.8.......6............9...5.6.4.9.7...8....6.1.", |
|
96 |
"1....7.9..3..2...8..96..5....53..9...1..8...26....4...3......1..4......7..7...3..", |
|
97 |
"1...34.8....8..5....4.6..21.18......3..1.2..6......81.52..7.9....6..9....9.64...2", |
|
98 |
"...92......68.3...19..7...623..4.1....1...7....8.3..297...8..91...5.72......64...", |
|
99 |
".6.5.4.3.1...9...8.........9...5...6.4.6.2.7.7...4...5.........4...8...1.5.2.3.4.", |
|
100 |
"7.....4...2..7..8...3..8.799..5..3...6..2..9...1.97..6...3..9...3..4..6...9..1.35", |
|
101 |
"....7..2.8.......6.1.2.5...9.54....8.........3....85.1...3.2.8.4.......9.7..6....", |
|
102 |
"52...6.........7.13...........4..8..6......5...........418.........3..2...87.....", |
|
103 |
"6.....8.3.4.7.................5.4.7.3..2.....1.6.......2.....5.....8.6......1....", |
|
104 |
"48.3............71.2.......7.5....6....2..8.............1.76...3.....4......5....", |
|
105 |
"......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.", |
|
106 |
"6.2.5.........3.4..........43...8....1....2........7..5..27...........81...6.....", |
|
107 |
".524.........7.1..............8.2...3.....6...9.5.....1.6.3...........897........", |
|
108 |
"6.2.5.........4.3..........43...8....1....2........7..5..27...........81...6.....", |
|
109 |
".923.........8.1...........1.7.4...........658.........6.5.2...4.....7.....9.....", |
|
110 |
"6..3.2....5.....1..........7.26............543.........8.15........4.2........7..", |
|
111 |
".6.5.1.9.1...9..539....7....4.8...7.......5.8.817.5.3.....5.2............76..8...", |
|
112 |
"..5...987.4..5...1..7......2...48....9.1.....6..2.....3..6..2.......9.7.......5..", |
|
113 |
"3.6.7...........518.........1.4.5...7.....6.....2......2.....4.....8.3.....5.....", |
|
114 |
"1.....3.8.7.4..............2.3.1...........958.........5.6...7.....8.2...4.......", |
|
115 |
"6..3.2....4.....1..........7.26............543.........8.15........4.2........7..", |
|
116 |
"....3..9....2....1.5.9..............1.2.8.4.6.8.5...2..75......4.1..6..3.....4.6.", |
|
117 |
"45.....3....8.1....9...........5..9.2..7.....8.........1..4..........7.2...6..8..", |
|
118 |
".237....68...6.59.9.....7......4.97.3.7.96..2.........5..47.........2....8.......", |
|
119 |
"..84...3....3.....9....157479...8........7..514.....2...9.6...2.5....4......9..56", |
|
120 |
".98.1....2......6.............3.2.5..84.........6.........4.8.93..5...........1..", |
|
121 |
"..247..58..............1.4.....2...9528.9.4....9...1.........3.3....75..685..2...", |
|
122 |
".2.3......63.....58.......15....9.3....7........1....8.879..26......6.7...6..7..4", |
|
123 |
"1.....7.9.4...72..8.........7..1..6.3.......5.6..4..2.........8..53...7.7.2....46", |
|
124 |
"4.....3.....8.2......7........1...8734.......6........5...6........1.4...82......", |
|
125 |
".......71.2.8........4.3...7...6..5....2..3..9........6...7.....8....4......5....", |
|
126 |
"6..3.2....4.....8..........7.26............543.........8.15........8.2........7..", |
|
127 |
".47.8...1............6..7..6....357......5....1..6....28..4.....9.1...4.....2.69.", |
|
128 |
"......8.17..2........5.6......7...5..1....3...8.......5......2..4..8....6...3....", |
|
129 |
"38.6.......9.......2..3.51......5....3..1..6....4......17.5..8.......9.......7.32", |
|
130 |
"...5...........5.697.....2...48.2...25.1...3..8..3.........4.7..13.5..9..2...31..", |
|
131 |
".2.......3.5.62..9.68...3...5..........64.8.2..47..9....3.....1.....6...17.43....", |
|
132 |
".8..4....3......1........2...5...4.69..1..8..2...........3.9....6....5.....2.....", |
|
133 |
"..8.9.1...6.5...2......6....3.1.7.5.........9..4...3...5....2...7...3.8.2..7....4", |
|
134 |
"1.....3.8.6.4..............2.3.1...........958.........5.6...7.....8.2...4.......", |
|
135 |
"1....6.8..64..........4...7....9.6...7.4..5..5...7.1...5....32.3....8...4........", |
|
136 |
"249.6...3.3....2..8.......5.....6......2......1..4.82..9.5..7....4.....1.7...3...", |
|
137 |
"...8....9.873...4.6..7.......85..97...........43..75.......3....3...145.4....2..1", |
|
138 |
"......8.16..2........7.5......6...2..1....3...8.......2......7..3..8....5...4....", |
|
139 |
".476...5.8.3.....2.....9......8.5..6...1.....6.24......78...51...6....4..9...4..7", |
|
140 |
".....7.95.....1...86..2.....2..73..85......6...3..49..3.5...41724................", |
|
141 |
".4.5.....8...9..3..76.2.....146..........9..7.....36....1..4.5..6......3..71..2..", |
|
142 |
".834.........7..5...........4.1.8..........27...3.....2.6.5....5.....8........1..", |
|
143 |
"..9.....3.....9...7.....5.6..65..4.....3......28......3..75.6..6...........12.3.8", |
|
144 |
".26.39......6....19.....7.......4..9.5....2....85.....3..2..9..4....762.........4", |
|
145 |
"2.3.8....8..7...........1...6.5.7...4......3....1............82.5....6...1.......", |
|
146 |
"6..3.2....1.....5..........7.26............843.........8.15........8.2........7..", |
|
147 |
"1.....9...64..1.7..7..4.......3.....3.89..5....7....2.....6.7.9.....4.1....129.3.", |
|
148 |
".........9......84.623...5....6...453...1...6...9...7....1.....4.5..2....3.8....9", |
|
149 |
".2....5938..5..46.94..6...8..2.3.....6..8.73.7..2.........4.38..7....6..........5", |
|
150 |
"9.4..5...25.6..1..31......8.7...9...4..26......147....7.......2...3..8.6.4.....9.", |
|
151 |
"...52.....9...3..4......7...1.....4..8..453..6...1...87.2........8....32.4..8..1.", |
|
152 |
"53..2.9...24.3..5...9..........1.827...7.........981.............64....91.2.5.43.", |
|
153 |
"1....786...7..8.1.8..2....9........24...1......9..5...6.8..........5.9.......93.4", |
|
154 |
"....5...11......7..6.....8......4.....9.1.3.....596.2..8..62..7..7......3.5.7.2..", |
|
155 |
".47.2....8....1....3....9.2.....5...6..81..5.....4.....7....3.4...9...1.4..27.8..", |
|
156 |
"......94.....9...53....5.7..8.4..1..463...........7.8.8..7.....7......28.5.26....", |
|
157 |
".2......6....41.....78....1......7....37.....6..412....1..74..5..8.5..7......39..", |
|
158 |
"1.....3.8.6.4..............2.3.1...........758.........7.5...6.....8.2...4.......", |
|
159 |
"2....1.9..1..3.7..9..8...2.......85..6.4.........7...3.2.3...6....5.....1.9...2.5", |
|
160 |
"..7..8.....6.2.3...3......9.1..5..6.....1.....7.9....2........4.83..4...26....51.", |
|
161 |
"...36....85.......9.4..8........68.........17..9..45...1.5...6.4....9..2.....3...", |
|
162 |
"34.6.......7.......2..8.57......5....7..1..2....4......36.2..1.......9.......7.82", |
|
163 |
"......4.18..2........6.7......8...6..4....3...1.......6......2..5..1....7...3....", |
|
164 |
".4..5..67...1...4....2.....1..8..3........2...6...........4..5.3.....8..2........", |
|
165 |
".......4...2..4..1.7..5..9...3..7....4..6....6..1..8...2....1..85.9...6.....8...3", |
|
166 |
"8..7....4.5....6............3.97...8....43..5....2.9....6......2...6...7.71..83.2", |
|
167 |
".8...4.5....7..3............1..85...6.....2......4....3.26............417........", |
|
168 |
"....7..8...6...5...2...3.61.1...7..2..8..534.2..9.......2......58...6.3.4...1....", |
|
169 |
"......8.16..2........7.5......6...2..1....3...8.......2......7..4..8....5...3....", |
|
170 |
".2..........6....3.74.8.........3..2.8..4..1.6..5.........1.78.5....9..........4.", |
|
171 |
".52..68.......7.2.......6....48..9..2..41......1.....8..61..38.....9...63..6..1.9", |
|
172 |
"....1.78.5....9..........4..2..........6....3.74.8.........3..2.8..4..1.6..5.....", |
|
173 |
"1.......3.6.3..7...7...5..121.7...9...7........8.1..2....8.64....9.2..6....4.....", |
|
174 |
"4...7.1....19.46.5.....1......7....2..2.3....847..6....14...8.6.2....3..6...9....", |
|
175 |
"......8.17..2........5.6......7...5..1....3...8.......5......2..3..8....6...4....", |
|
176 |
"963......1....8......2.5....4.8......1....7......3..257......3...9.2.4.7......9..", |
|
177 |
"15.3......7..4.2....4.72.....8.........9..1.8.1..8.79......38...........6....7423", |
|
178 |
"..........5724...98....947...9..3...5..9..12...3.1.9...6....25....56.....7......6", |
|
179 |
"....75....1..2.....4...3...5.....3.2...8...1.......6.....1..48.2........7........", |
|
180 |
"6.....7.3.4.8.................5.4.8.7..2.....1.3.......2.....5.....7.9......1....", |
|
181 |
"....6...4..6.3....1..4..5.77.....8.5...8.....6.8....9...2.9....4....32....97..1..", |
|
182 |
".32.....58..3.....9.428...1...4...39...6...5.....1.....2...67.8.....4....95....6.", |
|
183 |
"...5.3.......6.7..5.8....1636..2.......4.1.......3...567....2.8..4.7.......2..5..", |
|
184 |
".5.3.7.4.1.........3.......5.8.3.61....8..5.9.6..1........4...6...6927....2...9..", |
|
185 |
"..5..8..18......9.......78....4.....64....9......53..2.6.........138..5....9.714.", |
|
186 |
"..........72.6.1....51...82.8...13..4.........37.9..1.....238..5.4..9.........79.", |
|
187 |
"...658.....4......12............96.7...3..5....2.8...3..19..8..3.6.....4....473..", |
|
188 |
".2.3.......6..8.9.83.5........2...8.7.9..5........6..4.......1...1...4.22..7..8.9", |
|
189 |
".5..9....1.....6.....3.8.....8.4...9514.......3....2..........4.8...6..77..15..6.", |
|
190 |
".....2.......7...17..3...9.8..7......2.89.6...13..6....9..5.824.....891..........", |
|
321 | 191 |
"3...8.......7....51..............36...2..4....7...........6.13..452...........8..", |
192 |
"....14....3....2...7..........9...3.6.1.............8.2.....1.4....5.6.....7.8...", |
|
193 |
"4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......") |
|
384 | 194 |
|
329 | 195 |
|
268 | 196 |
|
197 |
// for measuring time |
|
198 |
def time_needed[T](i: Int, code: => T) = { |
|
199 |
val start = System.nanoTime() |
|
200 |
for (j <- 1 to i) code |
|
201 |
val end = System.nanoTime() |
|
301 | 202 |
(end - start) / i / 1.0e9 |
268 | 203 |
} |
204 |
||
205 |
||
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
206 |
@main |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
207 |
def test() = { |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
208 |
val total = |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
209 |
(for ((game, i) <- hard_games.zipWithIndex) yield { |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
210 |
val secs = time_needed(1, search(game)) |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
211 |
println(f"${i}%2.0f: ${game} |${secs}%2.3f secs") |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
212 |
secs |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
213 |
}).sum |
301 | 214 |
|
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
215 |
println(f"\ntotal: ${total}%.3f secs") |
268 | 216 |
} |
217 |
||
301 | 218 |
|
219 |
||
465
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
220 |
// some numbers: |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
221 |
// |
8ce150207792
updated to scala 3
Christian Urban <christian.urban@kcl.ac.uk>
parents:
450
diff
changeset
|
222 |
// single thread version 800 secs |
449 | 223 |
// |
320 | 224 |
// 4 cores parallel version on a moderate laptop 400 secs |
225 |
// 8 cores: 290 secs |
|
449 | 226 |
// 10 cores: 156 secs |
320 | 227 |
// 18 cores: 142 secs |
301 | 228 |