progs/lecture2.scala
changeset 57 9b88f9e04344
parent 56 6fa91be92d0c
child 58 93a2b6e4b84c
--- a/progs/lecture2.scala	Thu Nov 17 03:38:53 2016 +0000
+++ b/progs/lecture2.scala	Thu Nov 17 11:17:04 2016 +0000
@@ -2,30 +2,10 @@
 //=================
 
 
-// Implicits
-//===========
-//
-// for example adding your own methods to Strings:
-// imagine you want to increment strings, like
-//
-//     "HAL".increment
-//
-// you can avoid ugly fudges, like a MyString, by
-// using implicit conversions
-
-
-implicit class MyString(s: String) {
-  def increment = for (c <- s) yield (c + 1).toChar 
-}
-
-"HAL".increment
-
-
-
 // Option type
 //=============
 
-//in Java if something unusually happens, you return null
+//in Java if something unusually happens, you return null;
 //in Scala you use Option
 //   - if the value is present, you use Some(value)
 //   - if no value is present, you use None
@@ -49,25 +29,28 @@
   if (y == 0) None else Some(x / y)
 }
 
-// getOrElse is to set a default value
+// getOrElse is for setting a default value
 
 val lst = List(None, Some(1), Some(2), None, Some(3))
-for (x <- lst) yield x getOrElse 0
+for (x <- lst) yield x.getOrElse(0)
+
+
 
 
+// error handling with option (no exceptions)
+//
+//  Try(something).getOrElse(what_to_do_in_an_exception)
+//
 import scala.util._
 import io.Source
-// error handling with option
-//
-//  Try(something).getOrElse(what_to_do_in_an_exception)
 
-Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanccc/""").mkString
+Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString
 
 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
 
 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None)
 
-
+// a function that turns strings into numbers
 Integer.parseInt("12u34")
 
 def get_me_an_int(s: String): Option[Int] = 
@@ -86,10 +69,9 @@
 // write that function.
 //
 // In Java, if you didn't write this function, you'd have to depend on
-// the Javadoc of the get_me_an_int. If you didn't look at the Javadoc
-// for the Java, you might not know that get_me_an_int could return a
-// null, and your code could potentially throw a NullPointerException.
-
+// the Javadoc of the get_me_an_int. If you didn't look at the Javadoc, 
+// you might not know that get_me_an_int could return a null, and your 
+// code could potentially throw a NullPointerException.
 
 
 
@@ -103,6 +85,25 @@
 
 
 
+// Implicits
+//===========
+//
+// for example adding your own methods to Strings:
+// imagine you want to increment strings, like
+//
+//     "HAL".increment
+//
+// you can avoid ugly fudges, like a MyString, by
+// using implicit conversions
+
+
+implicit class MyString(s: String) {
+  def increment = for (c <- s) yield (c + 1).toChar 
+}
+
+"HAL".increment
+
+
 // No return in Scala
 //====================
 
@@ -121,6 +122,7 @@
 
 sumq(List(1,2,3,4))
 
+
 // last expression in a function is the return statement
 def square(x: Int): Int = {
   println(s"The argument is ${x}.")
@@ -155,6 +157,13 @@
 }
 
 
+
+
+
+
+
+
+
 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
   case Nil => Nil
   case None::xs => my_flatten(xs)
@@ -170,6 +179,8 @@
   case _ => "many"
 }
 
+get_me_a_string(0)
+
 // User-defined Datatypes
 //========================
 
@@ -177,6 +188,7 @@
 case class Node(elem: Int, left: Tree, right: Tree) extends Tree
 case class Leaf() extends Tree
 
+
 def insert(tr: Tree, n: Int): Tree = tr match {
   case Leaf() => Node(n, Leaf(), Leaf())
   case Node(m, left, right) => 
@@ -223,12 +235,14 @@
 }
 
 val people = List(Knight("David"), 
-                  Peer("Duke", "Norfolk", 42), 
+                  Peer("Duke", "Norfolk", 84), 
                   Peasant("Christian"), 
                   King(), 
                   Clown())
 
-println(people.sortWith(superior(_, _)))
+println(people.sortWith(superior(_, _)).mkString(", "))
+
+
 
 // Higher-Order Functions
 //========================
@@ -258,7 +272,8 @@
 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1)
 
 
-// type of functions
+// type of functions, for example f: Int => Int
+
 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match {
   case Nil => Nil
   case x::xs => f(x)::my_map_int(xs, f)
@@ -266,6 +281,12 @@
 
 my_map_int(lst, square)
 
+// other function types
+//
+// f1: (Int, Int) => Int
+// f2: List[String] => Option[Int]
+// ... 
+
 
 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
   case Nil => 0
@@ -278,7 +299,11 @@
 sum_squares(lst)
 sum_cubes(lst)
 
+def fact(n: Int): Int = 
+  if (n == 0) 1 else n * fact(n - 1)
 
+def sum_fact(lst: List[Int]) = sumOf(fact, lst)
+sum_fact(lst)
 
 // Avoid being mutable
 //=====================
@@ -307,9 +332,16 @@
 
 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList
 
+
+
 // Sudoku
 //========
 
+// THE POINT OF THIS CODE IS NOT TO BE SUPER
+// EFFICIENT AND FAST, just explaining exhaustive
+// depth-first search
+
+
 val game0 = """.14.6.3..
               |62...4..9
               |.8..5.6..
@@ -320,7 +352,6 @@
               |1..5...92
               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
 
-
 type Pos = (Int, Int)
 val EmptyValue = '.'
 val MaxValue = 9
@@ -328,14 +359,18 @@
 val allValues = "123456789".toList
 val indexes = (0 to 8).toList
 
-def empty(game: String) = game.indexOf(EmptyValue)
-def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)
-def isDone(game: String) = empty(game) == -1 
+
+
 
-def row(game: String, y: Int): List[Char] = indexes.map(col => game(y * MaxValue + col))
-def col(game: String, x: Int): List[Char] = indexes.map(row => game(x + row * MaxValue))
+def empty(game: String) = game.indexOf(EmptyValue)
+def isDone(game: String) = empty(game) == -1 
+def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)
+
 
-def box(game: String, pos: Pos): List[Char] = {
+def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))
+def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))
+
+def get_box(game: String, pos: Pos): List[Char] = {
     def base(p: Int): Int = (p / 3) * 3
     val x0 = base(pos._1)
     val y0 = base(pos._2)
@@ -344,14 +379,14 @@
 }
 
 
-//row(game0, 0)
-//row(game0, 1)
-//box(game0, (3,1))
+//get_row(game0, 0)
+//get_row(game0, 1)
+//get_box(game0, (3,1))
 
 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)
 
 def toAvoid(game: String, pos: Pos): List[Char] = 
-  (col(game, pos._1) ++ row(game, pos._2) ++ box(game, pos)).distinct
+  (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
 
 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos)
 
@@ -362,7 +397,7 @@
 def search(game: String): List[String] = {
   if (isDone(game)) List(game)
   else 
-    candidates(game, emptyPosition(game)).par.map(c => search(update(game, empty(game), c))).toList.flatten
+    candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten
 }
 
 
@@ -376,6 +411,7 @@
               |.16..7...
               |...329..1""".stripMargin.replaceAll("\\n", "")
 
+
 // game that is in the hard category
 val game2 = """8........
               |..36.....
@@ -398,6 +434,7 @@
               |.3.5...8.
               |9724...5.""".stripMargin.replaceAll("\\n", "")
 
+
 search(game0).map(pretty)
 search(game1).map(pretty)
 
@@ -410,7 +447,7 @@
 }
 
 search(game2).map(pretty)
-search(game3).distinct.map(pretty).length
+search(game3).distinct.length
 time_needed(3, search(game2))
 time_needed(3, search(game3))