|     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  |