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