20 |
20 |
21 // regex for URLs and emails |
21 // regex for URLs and emails |
22 val http_pattern = """"https?://[^"]*"""".r |
22 val http_pattern = """"https?://[^"]*"""".r |
23 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r |
23 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r |
24 |
24 |
25 //email_pattern.findAllIn |
25 // val s = "foo bla christian@kcl.ac.uk 1234567" |
26 // ("foo bla christian@kcl.ac.uk 1234567").toList |
26 // email_pattern.findAllIn(s).toList |
27 |
|
28 |
27 |
29 // drops the first and last character from a string |
28 // drops the first and last character from a string |
30 def unquote(s: String) = s.drop(1).dropRight(1) |
29 def unquote(s: String) = s.drop(1).dropRight(1) |
31 |
30 |
32 def get_all_URLs(page: String): Set[String] = |
31 def get_all_URLs(page: String): Set[String] = |
33 http_pattern.findAllIn(page).map(unquote).toSet |
32 http_pattern.findAllIn(page).map(unquote).toSet |
34 |
33 |
35 // naive version of crawl - searches until a given depth, |
34 // naive version of crawl - searches until a given depth, |
36 // visits pages potentially more than once |
35 // visits pages potentially more than once |
|
36 |
37 def crawl(url: String, n: Int) : Set[String] = { |
37 def crawl(url: String, n: Int) : Set[String] = { |
38 if (n == 0) Set() |
38 if (n == 0) Set() |
39 else { |
39 else { |
40 println(s" Visiting: $n $url") |
40 println(s" Visiting: $n $url") |
41 val page = get_page(url) |
41 val page = get_page(url) |
42 val new_emails = email_pattern.findAllIn(page).toSet |
42 val new_emails = email_pattern.findAllIn(page).toSet |
43 new_emails ++ |
43 new_emails ++ |
44 (for (u <- get_all_URLs(page)) yield crawl(u, n - 1)).flatten |
44 (for (u <- get_all_URLs(page).par) yield crawl(u, n - 1)).flatten |
45 } |
45 } |
46 } |
46 } |
47 |
47 |
48 // some starting URLs for the crawler |
48 // some starting URLs for the crawler |
49 val startURL = """https://nms.kcl.ac.uk/christian.urban/""" |
49 val startURL = """https://nms.kcl.ac.uk/christian.urban/""" |
50 |
|
51 crawl(startURL, 2) |
50 crawl(startURL, 2) |
52 |
51 |
53 |
52 |
54 |
53 |
55 // User-defined Datatypes and Pattern Matching |
54 // User-defined Datatypes and Pattern Matching |
56 //============================================ |
55 //============================================= |
57 |
|
58 |
56 |
59 abstract class Exp |
57 abstract class Exp |
60 case class N(n: Int) extends Exp |
58 case class N(n: Int) extends Exp // for numbers |
61 case class Plus(e1: Exp, e2: Exp) extends Exp |
59 case class Plus(e1: Exp, e2: Exp) extends Exp |
62 case class Times(e1: Exp, e2: Exp) extends Exp |
60 case class Times(e1: Exp, e2: Exp) extends Exp |
63 |
61 |
64 |
62 def string(e: Exp) : String = e match { |
65 |
63 case N(n) => n.toString |
66 // string of an Exp |
64 case Plus(e1, e2) => "(" + string(e1) + " + " + string(e2) + ")" |
67 // eval of an Exp |
65 case Times(e1, e2) => "(" + string(e1) + " * " + string(e2) + ")" |
68 // simp an Exp |
66 } |
69 // Tokens |
67 |
70 // Reverse Polish Notation |
68 val e = Plus(N(9), Times(N(3), N(4))) |
71 // compute RP |
69 println(string(e)) |
72 // transform RP into Exp |
70 |
73 // process RP string and generate Exp |
71 def eval(e: Exp) : Int = e match { |
|
72 case N(n) => n |
|
73 case Plus(e1, e2) => eval(e1) + eval(e2) |
|
74 case Times(e1, e2) => eval(e1) * eval(e2) |
|
75 } |
|
76 |
|
77 def simp(e: Exp) : Exp = e match { |
|
78 case N(n) => N(n) |
|
79 case Plus(e1, e2) => (simp(e1), simp(e2)) match { |
|
80 case (N(0), e2s) => e2s |
|
81 case (e1s, N(0)) => e1s |
|
82 case (e1s, e2s) => Plus(e1s, e2s) |
|
83 } |
|
84 case Times(e1, e2) => (simp(e1), simp(e2)) match { |
|
85 case (N(0), _) => N(0) |
|
86 case (_, N(0)) => N(0) |
|
87 case (N(1), e2s) => e2s |
|
88 case (e1s, N(1)) => e1s |
|
89 case (e1s, e2s) => Times(e1s, e2s) |
|
90 } |
|
91 } |
|
92 |
|
93 println(eval(e)) |
|
94 |
|
95 val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9))) |
|
96 println(string(e2)) |
|
97 println(string(simp(e2))) |
|
98 |
|
99 // Tokens and Reverse Polish Notation |
|
100 abstract class Token |
|
101 case class T(n: Int) extends Token |
|
102 case object PL extends Token |
|
103 case object TI extends Token |
|
104 |
|
105 def rp(e: Exp) : List[Token] = e match { |
|
106 case N(n) => List(T(n)) |
|
107 case Plus(e1, e2) => rp(e1) ::: rp(e2) ::: List(PL) |
|
108 case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) |
|
109 } |
|
110 println(string(e2)) |
|
111 println(rp(e2)) |
|
112 |
|
113 def comp(ls: List[Token], st: List[Int]) : Int = (ls, st) match { |
|
114 case (Nil, st) => st.head |
|
115 case (T(n)::rest, st) => comp(rest, n::st) |
|
116 case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st) |
|
117 case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st) |
|
118 } |
|
119 |
|
120 comp(rp(e), Nil) |
|
121 |
|
122 def proc(s: String) : Token = s match { |
|
123 case "+" => PL |
|
124 case "*" => TI |
|
125 case _ => T(s.toInt) |
|
126 } |
|
127 |
|
128 comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil) |
|
129 |
74 |
130 |
75 |
131 |
76 |
132 |
77 def string(e: Exp) : String = e match { |
133 def string(e: Exp) : String = e match { |
78 case N(n) => n.toString |
134 case N(n) => n.toString |
233 |
295 |
234 def jumps(xs: List[Int]) : List[List[Int]] = xs match { |
296 def jumps(xs: List[Int]) : List[List[Int]] = xs match { |
235 case Nil => Nil |
297 case Nil => Nil |
236 case (x::xs) => { |
298 case (x::xs) => { |
237 val children = moves(xs, x) |
299 val children = moves(xs, x) |
238 val results = children.flatMap((cs) => jumps(cs).map(x :: _)) |
300 val results = children.map((cs) => jumps(cs).map(x :: _)).flatten |
239 if (xs.length < x) List(x) :: results else results |
301 if (xs.length < x) List(x) :: results else results |
240 } |
302 } |
241 } |
303 } |
242 |
304 |
243 |
305 println(jumps(List(5,3,2,5,1,1)).minBy(_.length)) |
244 |
|
245 jumps(List(5,3,2,5,1,1)) |
|
246 jumps(List(3,5,1,2,1,2,1)) |
306 jumps(List(3,5,1,2,1,2,1)) |
247 jumps(List(3,5,1,2,3,4,1)) |
307 jumps(List(3,5,1,2,3,4,1)) |
248 jumps(List(3,5,1,0,0,0,1)) |
308 jumps(List(3,5,1,0,0,0,1)) |
249 jumps(List(3,5,1)) |
309 jumps(List(3,5,1)) |
250 jumps(List(5,1,1)) |
310 jumps(List(5,1,1)) |
313 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
373 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
314 } |
374 } |
315 |
375 |
316 //get_row(game0, 0) |
376 //get_row(game0, 0) |
317 //get_row(game0, 1) |
377 //get_row(game0, 1) |
318 //get_box(game0, (3,1)) |
378 //get_col(game0, 0) |
|
379 //get_box(game0, (3, 1)) |
319 |
380 |
320 |
381 |
321 // this is not mutable!! |
382 // this is not mutable!! |
322 def update(game: String, pos: Int, value: Char): String = |
383 def update(game: String, pos: Int, value: Char): String = |
323 game.updated(pos, value) |
384 game.updated(pos, value) |
324 |
385 |
325 def toAvoid(game: String, pos: Pos): List[Char] = |
386 def toAvoid(game: String, pos: Pos): List[Char] = |
326 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
387 (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |
327 |
388 |
328 def candidates(game: String, pos: Pos): List[Char] = |
389 def candidates(game: String, pos: Pos): List[Char] = |
329 allValues.diff(toAvoid(game,pos)) |
390 allValues.diff(toAvoid(game, pos)) |
330 |
391 |
331 //candidates(game0, (0,0)) |
392 //candidates(game0, (0,0)) |
332 |
393 |
333 def pretty(game: String): String = |
394 def pretty(game: String): String = |
334 "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
395 "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n")) |
335 |
396 |
336 ///////////////////// |
397 |
337 // not tail recursive |
|
338 def search(game: String): List[String] = { |
398 def search(game: String): List[String] = { |
339 if (isDone(game)) List(game) |
399 if (isDone(game)) List(game) |
340 else { |
400 else { |
341 val cs = candidates(game, emptyPosition(game)) |
401 val cs = candidates(game, emptyPosition(game)) |
342 cs.map(c => search(update(game, empty(game), c))).toList.flatten |
402 cs.par.map(c => search(update(game, empty(game), c))).toList.flatten |
343 } |
403 } |
344 } |
404 } |
345 |
405 |
346 search(game0).map(pretty) |
406 search(game0).map(pretty) |
347 |
407 |