progs/lecture2.scala
changeset 147 72f7dd1a3754
parent 95 4fa7231fede7
child 148 ead6089209ba
equal deleted inserted replaced
146:61d9a5ac6430 147:72f7dd1a3754
     1 // Scala Lecture 2
     1 // Scala Lecture 2
     2 //=================
     2 //=================
     3 
     3 
     4 
     4 
       
     5 // Overloaded math operations
       
     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 
       
    42 for (e <- lst) yield square(e)
       
    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),
       
    58 // has no "yield"
       
    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 
       
    74 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e)
       
    75 
       
    76 
     5 // Option type
    77 // Option type
     6 //=============
    78 //=============
     7 
    79 
     8 //in Java if something unusually happens, you return null;
    80 //in Java, if something unusually happens, you return null;
     9 //in Scala you use Option
    81 //in Scala you use Option
    10 //   - if the value is present, you use Some(value)
    82 //   - if the value is present, you use Some(value)
    11 //   - if no value is present, you use None
    83 //   - if no value is present, you use None
    12 
    84 
    13 
    85 
    14 List(7,2,3,4,5,6).find(_ < 4)
    86 List(7,2,3,4,5,6).find(_ < 4)
    15 List(5,6,7,8,9).find(_ < 4)
    87 List(5,6,7,8,9).find(_ < 4)
    16 
    88 
    17 
    89 
    18 // Values in types
    90 // some operations on Option's
    19 //
       
    20 // Boolean: 
       
    21 // Int: 
       
    22 // String: 
       
    23 //
       
    24 // Option[String]:
       
    25 //   
       
    26 
       
    27 
    91 
    28 val lst = List(None, Some(1), Some(2), None, Some(3))
    92 val lst = List(None, Some(1), Some(2), None, Some(3))
    29 
    93 
    30 lst.flatten
    94 lst.flatten
    31 
    95 
    38 
   102 
    39 for ((x, y) <- ps) yield {
   103 for ((x, y) <- ps) yield {
    40   if (y == 0) None else Some(x / y)
   104   if (y == 0) None else Some(x / y)
    41 }
   105 }
    42 
   106 
    43 // getOrElse is for setting a default value
   107 // use .getOrElse is for setting a default value
    44 
   108 
    45 val lst = List(None, Some(1), Some(2), None, Some(3))
   109 val lst = List(None, Some(1), Some(2), None, Some(3))
       
   110 
    46 for (x <- lst) yield x.getOrElse(0)
   111 for (x <- lst) yield x.getOrElse(0)
    47 
   112 
    48 
   113 
    49 
   114 
    50 
   115 
    51 // error handling with Option (no exceptions)
   116 // error handling with Options (no exceptions)
       
   117 //
       
   118 //  Try(....)
    52 //
   119 //
    53 //  Try(something).getOrElse(what_to_do_in_an_exception)
   120 //  Try(something).getOrElse(what_to_do_in_an_exception)
    54 //
   121 //
    55 import scala.util._
   122 import scala.util._
       
   123 
       
   124 Try(1 + 3)
       
   125 Try(9 / 0) 
       
   126 
       
   127 Try(9 / 3).getOrElse(42) 
       
   128 Try(9 / 0).getOrElse(42) 
       
   129 
       
   130 
    56 import io.Source
   131 import io.Source
    57 
   132 
    58 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString
   133 val my_url = """https://nms.kcl.ac.uk/christian.urban"""
    59 
   134 
    60 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
   135 Source.fromURL(my_url).mkString
    61 
   136 
    62 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None)
   137 Try(Source.fromURL(my_url).mkString).getOrElse("")
       
   138 
       
   139 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)
       
   140 
    63 
   141 
    64 // a function that turns strings into numbers
   142 // a function that turns strings into numbers
    65 Integer.parseInt("12u34")
   143 Integer.parseInt("1234")
       
   144 
    66 
   145 
    67 def get_me_an_int(s: String): Option[Int] = 
   146 def get_me_an_int(s: String): Option[Int] = 
    68  Try(Some(Integer.parseInt(s))).getOrElse(None)
   147  Try(Some(Integer.parseInt(s))).getOrElse(None)
    69 
   148 
    70 val lst = List("12345", "foo", "5432", "bar", "x21")
   149 val lst = List("12345", "foo", "5432", "bar", "x21")
       
   150 
    71 for (x <- lst) yield get_me_an_int(x)
   151 for (x <- lst) yield get_me_an_int(x)
    72 
   152 
    73 // summing all the numbers
   153 // summing all the numbers
    74 val sum = lst.flatMap(get_me_an_int(_)).sum
   154 val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum
    75 
   155 
    76 
   156 
    77 // This may not look any better than working with null in Java, but to
   157 // This may not look any better than working with null in Java, but to
    78 // see the value, you have to put yourself in the shoes of the
   158 // see the value, you have to put yourself in the shoes of the
    79 // consumer of the get_me_an_int function, and imagine you didn't
   159 // consumer of the get_me_an_int function, and imagine you didn't
    80 // write that function.
   160 // write that function.
    81 //
   161 //
    82 // In Java, if you didn't write this function, you'd have to depend on
   162 // In Java, if you didn't write this function, you'd have to depend on
    83 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc, 
   163 // the Javadoc of get_me_an_int. If you didn't look at the Javadoc, 
    84 // you might not know that get_me_an_int could return a null, and your 
   164 // you might not know that get_me_an_int could return a null, and your 
    85 // code could potentially throw a NullPointerException.
   165 // code could potentially throw a NullPointerException.
    86 
   166 
    87 
   167 
    88 
       
    89 // even Scala is not immune to problems like this:
   168 // even Scala is not immune to problems like this:
    90 
   169 
    91 List(5,6,7,8,9).indexOf(7)
   170 List(5,6,7,8,9).indexOf(7)
    92 
   171 
       
   172 
       
   173 
       
   174 
       
   175 // Higher-Order Functions
       
   176 //========================
       
   177 
       
   178 // functions can take functions as arguments
       
   179 
       
   180 val lst = (1 to 10).toList
       
   181 
       
   182 def even(x: Int) : Boolean = x % 2 == 0
       
   183 def odd(x: Int) : Boolean = x % 2 == 1
       
   184 
       
   185 lst.filter(x => even(x))
       
   186 lst.filter(even(_))
       
   187 lst.filter(even)
       
   188 
       
   189 lst.find(_ > 8)
       
   190 
       
   191 // map applies a function to each element of a list
       
   192 
       
   193 def square(x: Int): Int = x * x
       
   194 
       
   195 lst.map(square)
       
   196 
       
   197 lst.map(square).filter(_ > 4)
       
   198 
       
   199 lst.map(square).filter(_ > 4).map(square)
       
   200 
       
   201 // map works for most collection types, including sets
       
   202 Set(1, 3, 6).map(square)
       
   203 
       
   204 
       
   205 // Why could functions as arguments be useful?
       
   206 //
       
   207 // Consider the sum between a and b:
       
   208 
       
   209 def sumInts(a: Int, b: Int) : Int = 
       
   210   if (a > b) 0 else a + sumInts(a + 1, b)
       
   211 
       
   212 
       
   213 sumInt(10, 16)
       
   214 
       
   215 // sum squares
       
   216 def square(n: Int) : Int = n * n
       
   217 
       
   218 def sumSquares(a: Int, b: Int) : Int = 
       
   219   if (a > b) 0 else square(a) + sumSquares(a + 1, b)
       
   220 
       
   221 sumSquares(2, 6)
       
   222 
       
   223 
       
   224 // sum factorials
       
   225 def fact(n: Int) : Int =  
       
   226   if (n == 0) 1 else n * fact(n - 1)
       
   227 
       
   228 def sumFacts(a: Int, b: Int) : Int = 
       
   229   if (a > b) 0 else fact(a) + sumFacts(a + 1, b)
       
   230 
       
   231 sumFacts(2, 6)
       
   232 
       
   233 
       
   234 
       
   235 // You can see the pattern....can we simplify out work?
       
   236 // The type of functions from ints to ints: Int => Int
       
   237 
       
   238 def sum(f: Int => Int, a: Int, b: Int) : Int = {
       
   239   if (a > b) 0 
       
   240   else f(a) + sum(f, a + 1, b)
       
   241 }
       
   242 
       
   243 
       
   244 def sumSquares(a: Int, b: Int) : Int = sum(square, a, b)
       
   245 def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b)
       
   246 
       
   247 // What should we do for sumInts?
       
   248 
       
   249 def id(n: Int) : Int = n
       
   250 def sumInts(a: Int, b: Int) : Int = sum(id, a, b)
       
   251 
       
   252 
       
   253 
       
   254 // Anonymous Functions: You can also write:
       
   255 
       
   256 def sumCubes(a: Int, b: Int) : Int =   sum(x => x * x * x, a, b)
       
   257 def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b)
       
   258 def sumInts(a: Int, b: Int) : Int    = sum(x => x, a, b)
       
   259 
       
   260 
       
   261 // other function types
       
   262 //
       
   263 // f1: (Int, Int) => Int
       
   264 // f2: List[String] => Option[Int]
       
   265 // ... 
       
   266 
       
   267 
       
   268 // Function Composition
       
   269 //======================
       
   270 
       
   271 // How could Higher-Order Functions and Options be helpful?
       
   272 
       
   273 def add_footer(msg: String) : String = msg ++ " - Sent from iOS"
       
   274 
       
   275 def valid_msg(msg: String) : Boolean = msg.size <= 140
       
   276 
       
   277 def duplicate(s: String) : String = s ++ s
       
   278 
       
   279 // they compose nicely
       
   280 valid_msg(add_footer("Hello World"))
       
   281 valid_msg(duplicate(add_footer("Hello World")))
       
   282 
       
   283 
       
   284 // first_word: let's first do it the ugly Java way using null:
       
   285 
       
   286 def first_word(msg: String) : String = {
       
   287   val words = msg.split(" ")
       
   288   if (words(0) != "") words(0) else null
       
   289 }
       
   290 
       
   291 duplicate(first_word("Hello World"))
       
   292 duplicate(first_word(""))
       
   293 
       
   294 def extended_duplicate(s: String) : String = 
       
   295   if (s != null) s ++ s else null
       
   296 
       
   297 extended_duplicate(first_word(""))
       
   298 
       
   299 
       
   300 // Avoid always null!
       
   301 def better_first_word(msg: String) : Option[String] = {
       
   302   val words = msg.split(" ")
       
   303   if (words(0) != "") Some(words(0)) else None
       
   304 }
       
   305 
       
   306 better_first_word("Hello World").map(duplicate)
       
   307 better_first_word("Hello World").map(duplicate).map(duplicate).map(valid_msg)
       
   308 
       
   309 better_first_word("").map(duplicate)
       
   310 better_first_word("").map(duplicate).map(valid_msg)
    93 
   311 
    94 
   312 
    95 
   313 
    96 
   314 
    97 // Type abbreviations
   315 // Type abbreviations
    98 //====================
   316 //====================
    99 
   317 
   100 // some syntactic convenience
   318 // some syntactic convenience
       
   319 
   101 type Pos = (int, Int)
   320 type Pos = (int, Int)
   102 
       
   103 type Board = List[List[Int]]
   321 type Board = List[List[Int]]
   104 
   322 
   105 
   323 
   106 
   324 
   107 // Implicits
   325 // Implicits (Cool Feature)
   108 //===========
   326 //=========================
   109 //
   327 //
   110 // for example adding your own methods to Strings:
   328 // For example adding your own methods to Strings:
   111 // imagine you want to increment strings, like
   329 // Imagine you want to increment strings, like
   112 //
   330 //
   113 //     "HAL".increment
   331 //     "HAL".increment
   114 //
   332 //
   115 // you can avoid ugly fudges, like a MyString, by
   333 // you can avoid ugly fudges, like a MyString, by
   116 // using implicit conversions
   334 // using implicit conversions.
   117 
   335 
   118 
   336 
   119 implicit class MyString(s: String) {
   337 implicit class MyString(s: String) {
   120   def increment = for (c <- s) yield (c + 1).toChar 
   338   def increment = for (c <- s) yield (c + 1).toChar 
   121 }
   339 }
   122 
   340 
   123 "HAL".increment
   341 "HAL".increment
   124 
   342 
   125 
   343 
   126 // No return in Scala
   344 
       
   345 // No returns in Scala
   127 //====================
   346 //====================
   128 
   347 
   129 //You should not use "return" in Scala:
   348 // You should not use "return" in Scala:
   130 //
   349 //
   131 // A return expression, when evaluated, abandons the 
   350 // A return expression, when evaluated, abandons the 
   132 // current computation and returns to the caller of the 
   351 // current computation and returns to the caller of the 
   133 // function in which return appears."
   352 // function in which return appears."
   134 
   353 
   135 def sq1(x: Int): Int = x * x
   354 def sq1(x: Int): Int = x * x
   136 def sq2(x: Int): Int = return x * x
   355 def sq2(x: Int): Int = return x * x
   137 
   356 
   138 def sumq(ls: List[Int]): Int = {
   357 def sumq(ls: List[Int]): Int = {
   139   (for (x <- ls) yield (return x * x)).sum[Int]
   358   ls.map(sq1).sum[Int]
   140 }
   359 }
   141 
   360 
   142 sumq(List(1,2,3,4))
   361 sumq(List(1, 2, 3, 4))
   143 
   362 
   144 
   363 
   145 // last expression in a function is the return statement
   364 
   146 def square(x: Int): Int = {
   365 def sumq(ls: List[Int]): Int = {
   147   println(s"The argument is ${x}.")
   366   val sqs : List[Int] = for (x <- ls) yield (return x * x)
   148   x * x
   367   sqs.sum
   149 }
   368 }
       
   369 
   150 
   370 
   151 
   371 
   152 
   372 
   153 // Pattern Matching
   373 // Pattern Matching
   154 //==================
   374 //==================
   177 
   397 
   178 
   398 
   179 
   399 
   180 
   400 
   181 
   401 
   182 
       
   183 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
   402 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
   184   case Nil => Nil
   403   case Nil => Nil
   185   case None::xs => my_flatten(xs)
   404   case None::xs => my_flatten(xs)
   186   case Some(n)::xs => n::my_flatten(xs)
   405   case Some(n)::xs => n::my_flatten(xs)
   187 }
   406 }
   209 
   428 
   210 // What happens if no case matches?
   429 // What happens if no case matches?
   211 
   430 
   212 println(season("foobar"))
   431 println(season("foobar"))
   213 
   432 
       
   433 
   214 // User-defined Datatypes
   434 // User-defined Datatypes
   215 //========================
   435 //========================
   216 
   436 
   217 abstract class Tree
   437 abstract class Colour
   218 case class Node(elem: Int, left: Tree, right: Tree) extends Tree
   438 case class Red() extends Colour 
   219 case class Leaf() extends Tree
   439 case class Green() extends Colour 
   220 
   440 case class Blue() extends Colour
   221 
   441 
   222 def insert(tr: Tree, n: Int): Tree = tr match {
   442 def fav_colour(c: Colour) : Boolean = c match {
   223   case Leaf() => Node(n, Leaf(), Leaf())
   443   case Red()   => false
   224   case Node(m, left, right) => 
   444   case Green() => true
   225     if (n == m) Node(m, left, right) 
   445   case Blue()  => false 
   226     else if (n < m) Node(m, insert(left, n), right)
   446 }
   227     else Node(m, left, insert(right, n))
   447 
   228 }
   448 
   229 
   449 // actually this can be written with "object"
   230 
   450 
   231 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf()))
       
   232 insert(t1, 3)
       
   233 
       
   234 def depth(tr: Tree): Int = tr match {
       
   235   case Leaf() => 0
       
   236   case Node(_, left, right) => 1 + List(depth(left), depth(right)).max
       
   237 }
       
   238 
       
   239 
       
   240 def balance(tr: Tree): Int = tr match {
       
   241   case Leaf() => 0
       
   242   case Node(_, left, right) => depth(left) - depth(right)
       
   243 }
       
   244 
       
   245 balance(insert(t1, 3))
       
   246 
   451 
   247 // another example
   452 // another example
       
   453 //=================
   248 
   454 
   249 abstract class Person
   455 abstract class Person
   250 case class King() extends Person
   456 case class King() extends Person
   251 case class Peer(deg: String, terr: String, succ: Int) extends Person
   457 case class Peer(deg: String, terr: String, succ: Int) extends Person
   252 case class Knight(name: String) extends Person
   458 case class Knight(name: String) extends Person
   253 case class Peasant(name: String) extends Person
   459 case class Peasant(name: String) extends Person
   254 case class Clown() extends Person
   460 
   255 
   461 
   256 def title(p: Person): String = p match {
   462 def title(p: Person): String = p match {
   257   case King() => "His Majesty the King"
   463   case King() => "His Majesty the King"
   258   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
   464   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
   259   case Knight(name) => s"Sir ${name}"
   465   case Knight(name) => s"Sir ${name}"
   260   case Peasant(name) => name
   466   case Peasant(name) => name
   261 }
   467 }
       
   468 
   262 
   469 
   263 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match {
   470 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match {
   264   case (King(), _) => true
   471   case (King(), _) => true
   265   case (Peer(_,_,_), Knight(_)) => true
   472   case (Peer(_,_,_), Knight(_)) => true
   266   case (Peer(_,_,_), Peasant(_)) => true
   473   case (Peer(_,_,_), Peasant(_)) => true
   279 
   486 
   280 println(people.sortWith(superior(_, _)).mkString(", "))
   487 println(people.sortWith(superior(_, _)).mkString(", "))
   281 
   488 
   282 
   489 
   283 
   490 
   284 // Higher-Order Functions
   491 
   285 //========================
   492 
   286 
   493 
   287 // functions can take functions as arguments
   494 // Problems with mutability and parallel computations
   288 
   495 //====================================================
   289 val lst = (1 to 10).toList
   496 
   290 
   497 def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
   291 def even(x: Int): Boolean = x % 2 == 0
   498   var count = 0
   292 def odd(x: Int): Boolean = x % 2 == 1
   499   for (x <- A; if (B contains x)) count += 1 
   293 
   500   count
   294 lst.filter(x => even(x))
   501 }
   295 lst.filter(even(_))
   502 
   296 lst.filter(even)
   503 val A = (1 to 1000).toSet
   297 
   504 val B = (1 to 1000 by 4).toSet
   298 lst.find(_ > 8)
   505 
   299 
   506 count_intersection(A, B)
   300 def square(x: Int): Int = x * x
   507 
   301 
   508 // but do not try to add .par to the for-loop above
   302 lst.map(square)
   509 
   303 
   510 
   304 lst.map(square).filter(_ > 4)
   511 //propper parallel version
   305 
   512 def count_intersection2(A: Set[Int], B: Set[Int]) : Int = 
   306 lst.map(square).filter(_ > 4).map(square)
   513   A.par.count(x => B contains x)
   307 
   514 
   308 // in my collatz.scala
   515 count_intersection2(A, B)
   309 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1)
   516 
   310 
   517 
   311 
   518 //for measuring time
   312 // type of functions, for example f: Int => Int
   519 def time_needed[T](n: Int, code: => T) = {
   313 
   520   val start = System.nanoTime()
   314 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match {
   521   for (i <- (0 to n)) code
   315   case Nil => Nil
   522   val end = System.nanoTime()
   316   case x::xs => f(x)::my_map_int(xs, f)
   523   (end - start) / 1.0e9
   317 }
   524 }
   318 
   525 
   319 my_map_int(lst, square)
   526 val A = (1 to 1000000).toSet
   320 
   527 val B = (1 to 1000000 by 4).toSet
   321 // other function types
   528 
   322 //
   529 time_needed(10, count_intersection(A, B))
   323 // f1: (Int, Int) => Int
   530 time_needed(10, count_intersection2(A, B))
   324 // f2: List[String] => Option[Int]
   531 
   325 // ... 
   532 
   326 
       
   327 
       
   328 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
       
   329   case Nil => 0
       
   330   case x::xs => f(x) + sumOf(f, xs)
       
   331 }
       
   332 
       
   333 def sum_squares(lst: List[Int]) = sumOf(square, lst)
       
   334 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst)
       
   335 
       
   336 sum_squares(lst)
       
   337 sum_cubes(lst)
       
   338 
       
   339 // lets try it factorial
       
   340 def fact(n: Int): Int = ...
       
   341 
       
   342 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
       
   343 sum_fact(lst)
       
   344 
       
   345 // Avoid being mutable
       
   346 //=====================
       
   347 
       
   348 // a student showed me...
       
   349 import scala.collection.mutable.ListBuffer
       
   350 
       
   351 
       
   352 
       
   353 def collatz_max(bnd: Long): (Long, Long) = {
       
   354   val colNos = ListBuffer[(Long, Long)]()
       
   355   for (i <- (1L to bnd).toList) colNos += ((collatz(i), i))
       
   356   colNos.max
       
   357 }
       
   358 
       
   359 def collatz_max(bnd: Long): (Long, Long) = {
       
   360   (1L to bnd).map((i) => (collatz(i), i)).maxBy(_._1)
       
   361 }
       
   362 
       
   363 //views -> lazy collection
       
   364 def collatz_max(bnd: Long): (Long, Long) = {
       
   365   (1L to bnd).view.map((i) => (collatz(i), i)).maxBy(_._1)
       
   366 }
       
   367 
       
   368 // raises a GC exception
       
   369 (1 to 1000000000).filter(_ % 2 == 0).take(10).toList
       
   370 // ==> java.lang.OutOfMemoryError: GC overhead limit exceeded
       
   371 
       
   372 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList
       
   373 
   533 
   374 
   534 
   375 
   535 
   376 // Sudoku
   536 // Sudoku
   377 //========
   537 //========
   397 
   557 
   398 val allValues = "123456789".toList
   558 val allValues = "123456789".toList
   399 val indexes = (0 to 8).toList
   559 val indexes = (0 to 8).toList
   400 
   560 
   401 
   561 
   402 
       
   403 
       
   404 def empty(game: String) = game.indexOf(EmptyValue)
   562 def empty(game: String) = game.indexOf(EmptyValue)
   405 def isDone(game: String) = empty(game) == -1 
   563 def isDone(game: String) = empty(game) == -1 
   406 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)
   564 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)
   407 
   565 
   408 
   566 
   409 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))
   567 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))
   410 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))
   568 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))
       
   569 
       
   570 get_row(game0, 3)
       
   571 get_col(game0, 0)
   411 
   572 
   412 def get_box(game: String, pos: Pos): List[Char] = {
   573 def get_box(game: String, pos: Pos): List[Char] = {
   413     def base(p: Int): Int = (p / 3) * 3
   574     def base(p: Int): Int = (p / 3) * 3
   414     val x0 = base(pos._1)
   575     val x0 = base(pos._1)
   415     val y0 = base(pos._2)
   576     val y0 = base(pos._2)
   416     val ys = (y0 until y0 + 3).toList
   577     val ys = (y0 until y0 + 3).toList
   417     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
   578     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
   418 }
   579 }
   419 
   580 
   420 
   581 get_box(game0, (0, 0))
   421 //get_row(game0, 0)
   582 get_box(game0, (1, 1))
   422 //get_row(game0, 1)
   583 get_box(game0, (2, 1))
   423 //get_box(game0, (3,1))
   584 
   424 
   585 // this is not mutable!!
   425 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)
   586 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)
   426 
   587 
   427 def toAvoid(game: String, pos: Pos): List[Char] = 
   588 def toAvoid(game: String, pos: Pos): List[Char] = 
   428   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
   589   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
   429 
   590 
   430 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos)
   591 def candidates(game: String, pos: Pos): List[Char] = allValues.diff(toAvoid(game,pos))
   431 
   592 
   432 //candidates(game0, (0,0))
   593 //candidates(game0, (0,0))
   433 
   594 
   434 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
   595 def pretty(game: String): String = 
       
   596   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
   435 
   597 
   436 def search(game: String): List[String] = {
   598 def search(game: String): List[String] = {
   437   if (isDone(game)) List(game)
   599   if (isDone(game)) List(game)
   438   else 
   600   else {
   439     candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten
   601     val cs = candidates(game, emptyPosition(game))
   440 }
   602     cs.map(c => search(update(game, empty(game), c))).toList.flatten
   441 
   603   }
       
   604 }
       
   605 
       
   606 search(game0).map(pretty)
   442 
   607 
   443 val game1 = """23.915...
   608 val game1 = """23.915...
   444               |...2..54.
   609               |...2..54.
   445               |6.7......
   610               |6.7......
   446               |..1.....9
   611               |..1.....9
   448               |5.....6..
   613               |5.....6..
   449               |......9.5
   614               |......9.5
   450               |.16..7...
   615               |.16..7...
   451               |...329..1""".stripMargin.replaceAll("\\n", "")
   616               |...329..1""".stripMargin.replaceAll("\\n", "")
   452 
   617 
   453 
   618 search(game1).map(pretty)
   454 // game that is in the hard category
   619 
       
   620 // game that is in the hard(er) category
   455 val game2 = """8........
   621 val game2 = """8........
   456               |..36.....
   622               |..36.....
   457               |.7..9.2..
   623               |.7..9.2..
   458               |.5...7...
   624               |.5...7...
   459               |....457..
   625               |....457..
   472               |.......7.
   638               |.......7.
   473               |.3.5...8.
   639               |.3.5...8.
   474               |9724...5.""".stripMargin.replaceAll("\\n", "")
   640               |9724...5.""".stripMargin.replaceAll("\\n", "")
   475 
   641 
   476 
   642 
   477 search(game0).map(pretty)
   643 search(game2).map(pretty)
   478 search(game1).map(pretty)
   644 search(game3).map(pretty)
   479 
   645 
   480 // for measuring time
   646 // for measuring time
   481 def time_needed[T](i: Int, code: => T) = {
   647 def time_needed[T](i: Int, code: => T) = {
   482   val start = System.nanoTime()
   648   val start = System.nanoTime()
   483   for (j <- 1 to i) code
   649   for (j <- 1 to i) code
   485   ((end - start) / i / 1.0e9) + " secs"
   651   ((end - start) / i / 1.0e9) + " secs"
   486 }
   652 }
   487 
   653 
   488 search(game2).map(pretty)
   654 search(game2).map(pretty)
   489 search(game3).distinct.length
   655 search(game3).distinct.length
   490 time_needed(3, search(game2))
   656 time_needed(1, search(game2))
   491 time_needed(3, search(game3))
   657 time_needed(1, search(game3))
   492 
   658 
   493 
   659 
   494 
   660 
   495 
   661 
   496 
   662