51
|
1 |
// Scala Lecture 2
|
|
2 |
//=================
|
|
3 |
|
|
4 |
|
148
|
5 |
// the pain with overloaded math operations
|
147
|
6 |
|
|
7 |
(100 / 4)
|
|
8 |
|
|
9 |
(100 / 3)
|
|
10 |
|
|
11 |
(100.toDouble / 3.toDouble)
|
|
12 |
|
|
13 |
|
|
14 |
// For-Comprehensions again
|
|
15 |
//==========================
|
|
16 |
|
|
17 |
def square(n: Int) : Int = n * n
|
|
18 |
|
|
19 |
for (n <- (1 to 10).toList) yield {
|
|
20 |
val res = square(n)
|
|
21 |
res
|
|
22 |
}
|
|
23 |
|
|
24 |
// like in functions, the "last" item inside the yield
|
|
25 |
// will be returned; the last item is not necessarily
|
|
26 |
// the last line
|
|
27 |
|
|
28 |
for (n <- (1 to 10).toList) yield {
|
|
29 |
if (n % 2 == 0) n
|
|
30 |
else square(n)
|
|
31 |
}
|
|
32 |
|
|
33 |
|
|
34 |
// ...please, please do not write:
|
|
35 |
val lst = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
|
|
36 |
|
|
37 |
for (i <- (0 until lst.length).toList) yield square(lst(i))
|
|
38 |
|
|
39 |
// this is just so prone to off-by-one errors;
|
|
40 |
// write instead
|
|
41 |
|
150
|
42 |
for (e <- lst; if (e % 2) == 0; if (e != 4)) yield square(e)
|
147
|
43 |
|
|
44 |
|
|
45 |
//this works for sets as well
|
|
46 |
val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9)
|
|
47 |
|
|
48 |
for (e <- st) yield {
|
|
49 |
if (e < 5) e else square(e)
|
|
50 |
}
|
|
51 |
|
|
52 |
|
|
53 |
|
|
54 |
// Side-Effects
|
|
55 |
//==============
|
|
56 |
|
|
57 |
// with only a side-effect (no list is produced),
|
150
|
58 |
// for has no "yield"
|
147
|
59 |
|
|
60 |
for (n <- (1 to 10)) println(n)
|
|
61 |
|
|
62 |
|
|
63 |
for (n <- (1 to 10)) {
|
|
64 |
print("The number is: ")
|
|
65 |
print(n)
|
|
66 |
print("\n")
|
|
67 |
}
|
|
68 |
|
|
69 |
|
|
70 |
|
|
71 |
|
|
72 |
// know when to use yield and when not:
|
|
73 |
|
150
|
74 |
val test =
|
|
75 |
for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e)
|
|
76 |
|
147
|
77 |
|
|
78 |
|
51
|
79 |
// Option type
|
|
80 |
//=============
|
53
|
81 |
|
147
|
82 |
//in Java, if something unusually happens, you return null;
|
53
|
83 |
//in Scala you use Option
|
|
84 |
// - if the value is present, you use Some(value)
|
|
85 |
// - if no value is present, you use None
|
|
86 |
|
|
87 |
|
150
|
88 |
List(7,24,3,4,5,6).find(_ < 4)
|
53
|
89 |
List(5,6,7,8,9).find(_ < 4)
|
|
90 |
|
150
|
91 |
List(7,2,3,4,5,6).filter(_ < 4)
|
58
|
92 |
|
147
|
93 |
// some operations on Option's
|
58
|
94 |
|
51
|
95 |
val lst = List(None, Some(1), Some(2), None, Some(3))
|
|
96 |
|
|
97 |
lst.flatten
|
53
|
98 |
|
150
|
99 |
Some(10).get
|
|
100 |
None.get
|
51
|
101 |
|
53
|
102 |
Some(1).isDefined
|
|
103 |
None.isDefined
|
|
104 |
|
51
|
105 |
val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
|
|
106 |
|
|
107 |
for ((x, y) <- ps) yield {
|
|
108 |
if (y == 0) None else Some(x / y)
|
|
109 |
}
|
|
110 |
|
147
|
111 |
// use .getOrElse is for setting a default value
|
53
|
112 |
|
|
113 |
val lst = List(None, Some(1), Some(2), None, Some(3))
|
147
|
114 |
|
57
|
115 |
for (x <- lst) yield x.getOrElse(0)
|
|
116 |
|
|
117 |
|
53
|
118 |
|
|
119 |
|
147
|
120 |
// error handling with Options (no exceptions)
|
|
121 |
//
|
|
122 |
// Try(....)
|
57
|
123 |
//
|
|
124 |
// Try(something).getOrElse(what_to_do_in_an_exception)
|
|
125 |
//
|
53
|
126 |
import scala.util._
|
147
|
127 |
|
|
128 |
Try(1 + 3)
|
|
129 |
Try(9 / 0)
|
|
130 |
|
|
131 |
Try(9 / 3).getOrElse(42)
|
|
132 |
Try(9 / 0).getOrElse(42)
|
|
133 |
|
|
134 |
|
53
|
135 |
import io.Source
|
|
136 |
|
147
|
137 |
val my_url = """https://nms.kcl.ac.uk/christian.urban"""
|
150
|
138 |
//val my_url = """https://nms.kcl.ac.uk/christan.urban""" // misspelled
|
147
|
139 |
|
|
140 |
Source.fromURL(my_url).mkString
|
53
|
141 |
|
147
|
142 |
Try(Source.fromURL(my_url).mkString).getOrElse("")
|
53
|
143 |
|
147
|
144 |
Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)
|
|
145 |
|
53
|
146 |
|
57
|
147 |
// a function that turns strings into numbers
|
147
|
148 |
Integer.parseInt("1234")
|
|
149 |
|
53
|
150 |
|
|
151 |
def get_me_an_int(s: String): Option[Int] =
|
|
152 |
Try(Some(Integer.parseInt(s))).getOrElse(None)
|
|
153 |
|
|
154 |
val lst = List("12345", "foo", "5432", "bar", "x21")
|
147
|
155 |
|
53
|
156 |
for (x <- lst) yield get_me_an_int(x)
|
|
157 |
|
|
158 |
// summing all the numbers
|
147
|
159 |
val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum
|
53
|
160 |
|
|
161 |
|
|
162 |
// This may not look any better than working with null in Java, but to
|
|
163 |
// see the value, you have to put yourself in the shoes of the
|
|
164 |
// consumer of the get_me_an_int function, and imagine you didn't
|
|
165 |
// write that function.
|
|
166 |
//
|
|
167 |
// In Java, if you didn't write this function, you'd have to depend on
|
147
|
168 |
// the Javadoc of get_me_an_int. If you didn't look at the Javadoc,
|
57
|
169 |
// you might not know that get_me_an_int could return a null, and your
|
|
170 |
// code could potentially throw a NullPointerException.
|
53
|
171 |
|
|
172 |
|
58
|
173 |
// even Scala is not immune to problems like this:
|
|
174 |
|
150
|
175 |
List(5,6,7,8,9).indexOf(42)
|
58
|
176 |
|
|
177 |
|
150
|
178 |
// ... how are we supposed to know that this returns -1
|
58
|
179 |
|
|
180 |
|
147
|
181 |
// Higher-Order Functions
|
|
182 |
//========================
|
|
183 |
|
|
184 |
// functions can take functions as arguments
|
|
185 |
|
|
186 |
val lst = (1 to 10).toList
|
|
187 |
|
|
188 |
def even(x: Int) : Boolean = x % 2 == 0
|
|
189 |
def odd(x: Int) : Boolean = x % 2 == 1
|
|
190 |
|
150
|
191 |
lst.filter(x => even(x) && odd(x))
|
147
|
192 |
lst.filter(even(_))
|
150
|
193 |
lst.filter(odd && even)
|
147
|
194 |
|
|
195 |
lst.find(_ > 8)
|
|
196 |
|
|
197 |
// map applies a function to each element of a list
|
|
198 |
|
|
199 |
def square(x: Int): Int = x * x
|
|
200 |
|
150
|
201 |
val lst = (1 to 10).toList
|
147
|
202 |
lst.map(square)
|
|
203 |
|
|
204 |
lst.map(square).filter(_ > 4)
|
|
205 |
|
|
206 |
lst.map(square).filter(_ > 4).map(square)
|
|
207 |
|
|
208 |
// map works for most collection types, including sets
|
150
|
209 |
Set(1, 3, 6).map(square).filter(_ > 4)
|
147
|
210 |
|
|
211 |
|
150
|
212 |
val l = List((1, 3),(2, 4),(4, 1),(6, 2))
|
|
213 |
|
|
214 |
l.map(square(_._1))
|
|
215 |
|
|
216 |
|
|
217 |
// Why are functions as arguments useful?
|
147
|
218 |
//
|
|
219 |
// Consider the sum between a and b:
|
|
220 |
|
|
221 |
def sumInts(a: Int, b: Int) : Int =
|
|
222 |
if (a > b) 0 else a + sumInts(a + 1, b)
|
|
223 |
|
|
224 |
|
150
|
225 |
sumInts(10, 16)
|
147
|
226 |
|
|
227 |
// sum squares
|
|
228 |
def square(n: Int) : Int = n * n
|
|
229 |
|
|
230 |
def sumSquares(a: Int, b: Int) : Int =
|
|
231 |
if (a > b) 0 else square(a) + sumSquares(a + 1, b)
|
|
232 |
|
|
233 |
sumSquares(2, 6)
|
|
234 |
|
|
235 |
|
|
236 |
// sum factorials
|
|
237 |
def fact(n: Int) : Int =
|
|
238 |
if (n == 0) 1 else n * fact(n - 1)
|
|
239 |
|
|
240 |
def sumFacts(a: Int, b: Int) : Int =
|
|
241 |
if (a > b) 0 else fact(a) + sumFacts(a + 1, b)
|
|
242 |
|
|
243 |
sumFacts(2, 6)
|
|
244 |
|
|
245 |
|
|
246 |
|
150
|
247 |
// You can see the pattern....can we simplify our work?
|
147
|
248 |
// The type of functions from ints to ints: Int => Int
|
|
249 |
|
|
250 |
def sum(f: Int => Int, a: Int, b: Int) : Int = {
|
|
251 |
if (a > b) 0
|
|
252 |
else f(a) + sum(f, a + 1, b)
|
|
253 |
}
|
|
254 |
|
|
255 |
|
|
256 |
def sumSquares(a: Int, b: Int) : Int = sum(square, a, b)
|
|
257 |
def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b)
|
|
258 |
|
|
259 |
// What should we do for sumInts?
|
|
260 |
|
|
261 |
def id(n: Int) : Int = n
|
|
262 |
def sumInts(a: Int, b: Int) : Int = sum(id, a, b)
|
|
263 |
|
150
|
264 |
sumInts(10, 12)
|
147
|
265 |
|
|
266 |
|
|
267 |
// Anonymous Functions: You can also write:
|
|
268 |
|
|
269 |
def sumCubes(a: Int, b: Int) : Int = sum(x => x * x * x, a, b)
|
|
270 |
def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b)
|
|
271 |
def sumInts(a: Int, b: Int) : Int = sum(x => x, a, b)
|
|
272 |
|
|
273 |
|
|
274 |
// other function types
|
|
275 |
//
|
|
276 |
// f1: (Int, Int) => Int
|
|
277 |
// f2: List[String] => Option[Int]
|
|
278 |
// ...
|
|
279 |
|
|
280 |
|
148
|
281 |
// an aside: partial application
|
|
282 |
|
|
283 |
def add(a: Int)(b: Int) : Int = a + b
|
150
|
284 |
def add_abc(a: Int)(b: Int)(c: Int) : Int = a + b + c
|
|
285 |
|
|
286 |
val add2 : Int => Int = add(2)
|
|
287 |
add2(5)
|
|
288 |
|
|
289 |
val add2_bc : Int => Int => Int = add_abc(2)
|
|
290 |
val add2_9_c : Int => Int = add2_bc(9)
|
|
291 |
|
|
292 |
add2_9_c(10)
|
148
|
293 |
|
|
294 |
sum(add(2), 0, 2)
|
|
295 |
sum(add(10), 0, 2)
|
|
296 |
|
|
297 |
|
167
|
298 |
|
|
299 |
|
|
300 |
// some automatic timing in each evaluation
|
|
301 |
package wrappers {
|
|
302 |
|
|
303 |
object wrap {
|
|
304 |
|
|
305 |
def timed[R](block: => R): R = {
|
|
306 |
val t0 = System.nanoTime()
|
|
307 |
val result = block
|
|
308 |
println("Elapsed time: " + (System.nanoTime - t0) + "ns")
|
|
309 |
result
|
|
310 |
}
|
|
311 |
|
|
312 |
def apply[A](a: => A): A = {
|
|
313 |
timed(a)
|
|
314 |
}
|
|
315 |
}
|
|
316 |
}
|
|
317 |
|
|
318 |
$intp.setExecutionWrapper("wrappers.wrap")
|
|
319 |
|
|
320 |
// Iteration
|
|
321 |
|
|
322 |
def fib(n: Int) : Int =
|
|
323 |
if (n <= 1) 1 else fib(n - 1) + fib(n - 2)
|
|
324 |
|
|
325 |
fib(10)
|
|
326 |
|
|
327 |
|
|
328 |
Iterator.iterate((1,1)){ case (n: Int, m: Int) => (n + m, n) }.drop(9).next
|
|
329 |
|
|
330 |
|
|
331 |
|
|
332 |
|
147
|
333 |
// Function Composition
|
|
334 |
//======================
|
|
335 |
|
150
|
336 |
// How can be Higher-Order Functions and Options be helpful?
|
147
|
337 |
|
|
338 |
def add_footer(msg: String) : String = msg ++ " - Sent from iOS"
|
|
339 |
|
|
340 |
def valid_msg(msg: String) : Boolean = msg.size <= 140
|
|
341 |
|
|
342 |
def duplicate(s: String) : String = s ++ s
|
|
343 |
|
150
|
344 |
// they compose very nicely, e.g
|
|
345 |
|
147
|
346 |
valid_msg(add_footer("Hello World"))
|
150
|
347 |
valid_msg(duplicate(duplicate(add_footer("Helloooooooooooooooooo World"))))
|
147
|
348 |
|
150
|
349 |
// but not all functions do
|
147
|
350 |
// first_word: let's first do it the ugly Java way using null:
|
|
351 |
|
|
352 |
def first_word(msg: String) : String = {
|
|
353 |
val words = msg.split(" ")
|
|
354 |
if (words(0) != "") words(0) else null
|
|
355 |
}
|
|
356 |
|
|
357 |
duplicate(first_word("Hello World"))
|
|
358 |
duplicate(first_word(""))
|
|
359 |
|
|
360 |
def extended_duplicate(s: String) : String =
|
|
361 |
if (s != null) s ++ s else null
|
|
362 |
|
|
363 |
extended_duplicate(first_word(""))
|
|
364 |
|
150
|
365 |
// but this is against the rules of the game: we do not want
|
|
366 |
// to change duplicate, because first_word might return null
|
|
367 |
|
147
|
368 |
|
|
369 |
// Avoid always null!
|
|
370 |
def better_first_word(msg: String) : Option[String] = {
|
|
371 |
val words = msg.split(" ")
|
|
372 |
if (words(0) != "") Some(words(0)) else None
|
|
373 |
}
|
|
374 |
|
|
375 |
better_first_word("Hello World").map(duplicate)
|
150
|
376 |
|
|
377 |
better_first_word("Hello World").map(duplicate)
|
|
378 |
better_first_word("").map(duplicate).map(duplicate).map(valid_msg)
|
147
|
379 |
|
|
380 |
better_first_word("").map(duplicate)
|
|
381 |
better_first_word("").map(duplicate).map(valid_msg)
|
|
382 |
|
|
383 |
|
150
|
384 |
|
|
385 |
|
|
386 |
|
|
387 |
// Problems with mutability and parallel computations
|
|
388 |
//====================================================
|
|
389 |
|
|
390 |
def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
|
|
391 |
var count = 0
|
|
392 |
for (x <- A; if (B contains x)) count += 1
|
|
393 |
count
|
|
394 |
}
|
|
395 |
|
|
396 |
val A = (1 to 1000).toSet
|
|
397 |
val B = (1 to 1000 by 4).toSet
|
|
398 |
|
|
399 |
count_intersection(A, B)
|
|
400 |
|
|
401 |
// but do not try to add .par to the for-loop above,
|
|
402 |
// otherwise you will be caught in race-condition hell.
|
|
403 |
|
|
404 |
|
|
405 |
//propper parallel version
|
|
406 |
def count_intersection2(A: Set[Int], B: Set[Int]) : Int =
|
|
407 |
A.par.count(x => B contains x)
|
|
408 |
|
|
409 |
count_intersection2(A, B)
|
|
410 |
|
|
411 |
|
|
412 |
//for measuring time
|
|
413 |
def time_needed[T](n: Int, code: => T) = {
|
|
414 |
val start = System.nanoTime()
|
|
415 |
for (i <- (0 to n)) code
|
|
416 |
val end = System.nanoTime()
|
|
417 |
(end - start) / 1.0e9
|
|
418 |
}
|
|
419 |
|
|
420 |
val A = (1 to 1000000).toSet
|
|
421 |
val B = (1 to 1000000 by 4).toSet
|
|
422 |
|
|
423 |
time_needed(10, count_intersection(A, B))
|
|
424 |
time_needed(10, count_intersection2(A, B))
|
53
|
425 |
|
|
426 |
|
57
|
427 |
|
|
428 |
|
|
429 |
|
147
|
430 |
|
|
431 |
// No returns in Scala
|
53
|
432 |
//====================
|
|
433 |
|
147
|
434 |
// You should not use "return" in Scala:
|
53
|
435 |
//
|
|
436 |
// A return expression, when evaluated, abandons the
|
|
437 |
// current computation and returns to the caller of the
|
|
438 |
// function in which return appears."
|
|
439 |
|
|
440 |
def sq1(x: Int): Int = x * x
|
|
441 |
def sq2(x: Int): Int = return x * x
|
|
442 |
|
|
443 |
def sumq(ls: List[Int]): Int = {
|
147
|
444 |
ls.map(sq1).sum[Int]
|
53
|
445 |
}
|
|
446 |
|
147
|
447 |
sumq(List(1, 2, 3, 4))
|
36
|
448 |
|
57
|
449 |
|
147
|
450 |
|
|
451 |
def sumq(ls: List[Int]): Int = {
|
|
452 |
val sqs : List[Int] = for (x <- ls) yield (return x * x)
|
|
453 |
sqs.sum
|
53
|
454 |
}
|
|
455 |
|
55
|
456 |
|
|
457 |
|
147
|
458 |
|
148
|
459 |
// Type abbreviations
|
|
460 |
//====================
|
|
461 |
|
|
462 |
// some syntactic convenience
|
|
463 |
|
|
464 |
type Pos = (int, Int)
|
|
465 |
type Board = List[List[Int]]
|
|
466 |
|
56
|
467 |
|
57
|
468 |
|
|
469 |
|
150
|
470 |
// Sudoku in Scala
|
|
471 |
//=================
|
53
|
472 |
|
57
|
473 |
// THE POINT OF THIS CODE IS NOT TO BE SUPER
|
|
474 |
// EFFICIENT AND FAST, just explaining exhaustive
|
|
475 |
// depth-first search
|
|
476 |
|
|
477 |
|
55
|
478 |
val game0 = """.14.6.3..
|
|
479 |
|62...4..9
|
|
480 |
|.8..5.6..
|
|
481 |
|.6.2....3
|
|
482 |
|.7..1..5.
|
|
483 |
|5....9.6.
|
|
484 |
|..6.2..3.
|
|
485 |
|1..5...92
|
|
486 |
|..7.9.41.""".stripMargin.replaceAll("\\n", "")
|
|
487 |
|
|
488 |
type Pos = (Int, Int)
|
|
489 |
val EmptyValue = '.'
|
|
490 |
val MaxValue = 9
|
|
491 |
|
|
492 |
val allValues = "123456789".toList
|
|
493 |
val indexes = (0 to 8).toList
|
|
494 |
|
57
|
495 |
|
|
496 |
def empty(game: String) = game.indexOf(EmptyValue)
|
|
497 |
def isDone(game: String) = empty(game) == -1
|
150
|
498 |
def emptyPosition(game: String) =
|
|
499 |
(empty(game) % MaxValue, empty(game) / MaxValue)
|
57
|
500 |
|
55
|
501 |
|
150
|
502 |
def get_row(game: String, y: Int) =
|
|
503 |
indexes.map(col => game(y * MaxValue + col))
|
|
504 |
def get_col(game: String, x: Int) =
|
|
505 |
indexes.map(row => game(x + row * MaxValue))
|
57
|
506 |
|
147
|
507 |
get_row(game0, 3)
|
|
508 |
get_col(game0, 0)
|
|
509 |
|
57
|
510 |
def get_box(game: String, pos: Pos): List[Char] = {
|
55
|
511 |
def base(p: Int): Int = (p / 3) * 3
|
|
512 |
val x0 = base(pos._1)
|
|
513 |
val y0 = base(pos._2)
|
|
514 |
val ys = (y0 until y0 + 3).toList
|
|
515 |
(x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
|
|
516 |
}
|
|
517 |
|
147
|
518 |
get_box(game0, (0, 0))
|
|
519 |
get_box(game0, (1, 1))
|
|
520 |
get_box(game0, (2, 1))
|
55
|
521 |
|
147
|
522 |
// this is not mutable!!
|
150
|
523 |
def update(game: String, pos: Int, value: Char): String =
|
|
524 |
game.updated(pos, value)
|
55
|
525 |
|
|
526 |
def toAvoid(game: String, pos: Pos): List[Char] =
|
57
|
527 |
(get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
|
55
|
528 |
|
150
|
529 |
def candidates(game: String, pos: Pos): List[Char] =
|
|
530 |
allValues.diff(toAvoid(game,pos))
|
55
|
531 |
|
|
532 |
//candidates(game0, (0,0))
|
|
533 |
|
147
|
534 |
def pretty(game: String): String =
|
|
535 |
"\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
|
55
|
536 |
|
|
537 |
def search(game: String): List[String] = {
|
|
538 |
if (isDone(game)) List(game)
|
147
|
539 |
else {
|
|
540 |
val cs = candidates(game, emptyPosition(game))
|
150
|
541 |
cs.par.map(c => search(update(game, empty(game), c))).toList.flatten
|
147
|
542 |
}
|
55
|
543 |
}
|
|
544 |
|
147
|
545 |
search(game0).map(pretty)
|
55
|
546 |
|
|
547 |
val game1 = """23.915...
|
|
548 |
|...2..54.
|
|
549 |
|6.7......
|
|
550 |
|..1.....9
|
|
551 |
|89.5.3.17
|
|
552 |
|5.....6..
|
|
553 |
|......9.5
|
|
554 |
|.16..7...
|
|
555 |
|...329..1""".stripMargin.replaceAll("\\n", "")
|
|
556 |
|
147
|
557 |
search(game1).map(pretty)
|
57
|
558 |
|
147
|
559 |
// game that is in the hard(er) category
|
55
|
560 |
val game2 = """8........
|
|
561 |
|..36.....
|
|
562 |
|.7..9.2..
|
|
563 |
|.5...7...
|
|
564 |
|....457..
|
|
565 |
|...1...3.
|
|
566 |
|..1....68
|
|
567 |
|..85...1.
|
|
568 |
|.9....4..""".stripMargin.replaceAll("\\n", "")
|
|
569 |
|
|
570 |
// game with multiple solutions
|
|
571 |
val game3 = """.8...9743
|
|
572 |
|.5...8.1.
|
|
573 |
|.1.......
|
|
574 |
|8....5...
|
|
575 |
|...8.4...
|
|
576 |
|...3....6
|
|
577 |
|.......7.
|
|
578 |
|.3.5...8.
|
|
579 |
|9724...5.""".stripMargin.replaceAll("\\n", "")
|
|
580 |
|
57
|
581 |
|
147
|
582 |
search(game2).map(pretty)
|
|
583 |
search(game3).map(pretty)
|
55
|
584 |
|
|
585 |
// for measuring time
|
|
586 |
def time_needed[T](i: Int, code: => T) = {
|
|
587 |
val start = System.nanoTime()
|
|
588 |
for (j <- 1 to i) code
|
|
589 |
val end = System.nanoTime()
|
|
590 |
((end - start) / i / 1.0e9) + " secs"
|
|
591 |
}
|
|
592 |
|
|
593 |
search(game2).map(pretty)
|
57
|
594 |
search(game3).distinct.length
|
147
|
595 |
time_needed(1, search(game2))
|
|
596 |
time_needed(1, search(game3))
|
55
|
597 |
|
53
|
598 |
|
|
599 |
|
|
600 |
|
150
|
601 |
//===================
|
|
602 |
// the end for today
|