149 case 1 => "one" |
168 case 1 => "one" |
150 case 2 => "two" |
169 case 2 => "two" |
151 case _ => "many" |
170 case _ => "many" |
152 } |
171 } |
153 |
172 |
|
173 // User-defined Datatypes |
|
174 //======================== |
|
175 |
|
176 abstract class Tree |
|
177 case class Node(elem: Int, left: Tree, right: Tree) extends Tree |
|
178 case class Leaf() extends Tree |
|
179 |
|
180 def insert(tr: Tree, n: Int): Tree = tr match { |
|
181 case Leaf() => Node(n, Leaf(), Leaf()) |
|
182 case Node(m, left, right) => |
|
183 if (n == m) Node(m, left, right) |
|
184 else if (n < m) Node(m, insert(left, n), right) |
|
185 else Node(m, left, insert(right, n)) |
|
186 } |
|
187 |
|
188 |
|
189 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf())) |
|
190 insert(t1, 3) |
|
191 |
|
192 def balance(tr: Tree): Int = tr match { |
|
193 case Leaf() => 0 |
|
194 case Node(_, left, right) => balance(left) - balance(right) |
|
195 } |
|
196 |
|
197 |
|
198 // another example |
|
199 |
|
200 abstract class Person |
|
201 case class King() extends Person |
|
202 case class Peer(deg: String, terr: String, succ: Int) extends Person |
|
203 case class Knight(name: String) extends Person |
|
204 case class Peasant(name: String) extends Person |
|
205 case class Clown() extends Person |
|
206 |
|
207 def title(p: Person): String = p match { |
|
208 case King() => "His Majesty the King" |
|
209 case Peer(deg, terr, _) => s"The ${deg} of ${terr}" |
|
210 case Knight(name) => s"Sir ${name}" |
|
211 case Peasant(name) => name |
|
212 } |
|
213 |
|
214 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { |
|
215 case (King(), _) => true |
|
216 case (Peer(_,_,_), Knight(_)) => true |
|
217 case (Peer(_,_,_), Peasant(_)) => true |
|
218 case (Peer(_,_,_), Clown()) => true |
|
219 case (Knight(_), Peasant(_)) => true |
|
220 case (Knight(_), Clown()) => true |
|
221 case (Clown(), Peasant(_)) => true |
|
222 case _ => false |
|
223 } |
|
224 |
|
225 val people = List(Knight("David"), |
|
226 Peer("Duke", "Norfolk", 42), |
|
227 Peasant("Christian"), |
|
228 King(), |
|
229 Clown()) |
|
230 |
|
231 println(people.sortWith(superior(_, _))) |
154 |
232 |
155 // Higher-Order Functions |
233 // Higher-Order Functions |
156 //======================== |
234 //======================== |
157 |
235 |
158 // functions can take functions as arguments |
236 // functions can take functions as arguments |
172 |
250 |
173 lst.map(square) |
251 lst.map(square) |
174 |
252 |
175 lst.map(square).filter(_ > 4) |
253 lst.map(square).filter(_ > 4) |
176 |
254 |
177 |
255 lst.map(square).filter(_ > 4).map(square) |
|
256 |
|
257 // in my collatz.scala |
|
258 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) |
|
259 |
|
260 |
|
261 // type of functions |
|
262 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { |
|
263 case Nil => Nil |
|
264 case x::xs => f(x)::my_map_int(xs, f) |
|
265 } |
|
266 |
|
267 my_map_int(lst, square) |
|
268 |
|
269 |
|
270 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
|
271 case Nil => 0 |
|
272 case x::xs => f(x) + sumOf(f, xs) |
|
273 } |
|
274 |
|
275 def sum_squares(lst: List[Int]) = sumOf(square, lst) |
|
276 def sum_cubes(lst: List[Int]) = sumOf(x => x * x * x, lst) |
|
277 |
|
278 sum_squares(lst) |
|
279 sum_cubes(lst) |
178 |
280 |
179 |
281 |
180 // Sudoku |
282 // Sudoku |
181 //======== |
283 //======== |
182 |
284 |
183 |
285 val game0 = """.14.6.3.. |
184 |
286 |62...4..9 |
185 |
287 |.8..5.6.. |
186 |
288 |.6.2....3 |
187 //sorting, higher-order functions |
289 |.7..1..5. |
188 //lexicographic ordering |
290 |5....9.6. |
189 |
291 |..6.2..3. |
190 |
292 |1..5...92 |
191 // Implicits |
293 |..7.9.41.""".stripMargin.replaceAll("\\n", "") |
192 //=========== |
294 |
193 // |
295 |
194 // for example adding your own methods to Strings: |
296 type Pos = (Int, Int) |
195 // imagine you want to increment strings, like |
297 val EmptyValue = '.' |
196 // |
298 val MaxValue = 9 |
197 // "HAL".increment |
299 |
198 // |
300 val allValues = "123456789".toList |
199 // you can avoid ugly fudges, like a MyString, by |
301 val indexes = (0 to 8).toList |
200 // using implicit conversions |
302 |
201 |
303 def empty(game: String) = game.indexOf(EmptyValue) |
202 |
304 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) |
203 implicit class MyString(s: String) { |
305 def isDone(game: String) = empty(game) == -1 |
204 def increment = for (c <- s) yield (c + 1).toChar |
306 |
205 } |
307 def row(game: String, y: Int): List[Char] = indexes.map(col => game(y * MaxValue + col)) |
206 |
308 def col(game: String, x: Int): List[Char] = indexes.map(row => game(x + row * MaxValue)) |
207 "HAL".increment |
309 |
|
310 def box(game: String, pos: Pos): List[Char] = { |
|
311 def base(p: Int): Int = (p / 3) * 3 |
|
312 val x0 = base(pos._1) |
|
313 val y0 = base(pos._2) |
|
314 val ys = (y0 until y0 + 3).toList |
|
315 (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |
|
316 } |
|
317 |
|
318 |
|
319 //row(game0, 0) |
|
320 //row(game0, 1) |
|
321 //box(game0, (3,1)) |
|
322 |
|
323 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) |
|
324 |
|
325 def toAvoid(game: String, pos: Pos): List[Char] = |
|
326 (col(game, pos._1) ++ row(game, pos._2) ++ box(game, pos)).distinct |
|
327 |
|
328 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos) |
|
329 |
|
330 //candidates(game0, (0,0)) |
|
331 |
|
332 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |
|
333 |
|
334 def search(game: String): List[String] = { |
|
335 if (isDone(game)) List(game) |
|
336 else |
|
337 candidates(game, emptyPosition(game)).par.map(c => search(update(game, empty(game), c))).toList.flatten |
|
338 } |
|
339 |
|
340 |
|
341 val game1 = """23.915... |
|
342 |...2..54. |
|
343 |6.7...... |
|
344 |..1.....9 |
|
345 |89.5.3.17 |
|
346 |5.....6.. |
|
347 |......9.5 |
|
348 |.16..7... |
|
349 |...329..1""".stripMargin.replaceAll("\\n", "") |
|
350 |
|
351 // game that is in the hard category |
|
352 val game2 = """8........ |
|
353 |..36..... |
|
354 |.7..9.2.. |
|
355 |.5...7... |
|
356 |....457.. |
|
357 |...1...3. |
|
358 |..1....68 |
|
359 |..85...1. |
|
360 |.9....4..""".stripMargin.replaceAll("\\n", "") |
|
361 |
|
362 // game with multiple solutions |
|
363 val game3 = """.8...9743 |
|
364 |.5...8.1. |
|
365 |.1....... |
|
366 |8....5... |
|
367 |...8.4... |
|
368 |...3....6 |
|
369 |.......7. |
|
370 |.3.5...8. |
|
371 |9724...5.""".stripMargin.replaceAll("\\n", "") |
|
372 |
|
373 search(game0).map(pretty) |
|
374 search(game1).map(pretty) |
|
375 |
|
376 // for measuring time |
|
377 def time_needed[T](i: Int, code: => T) = { |
|
378 val start = System.nanoTime() |
|
379 for (j <- 1 to i) code |
|
380 val end = System.nanoTime() |
|
381 ((end - start) / i / 1.0e9) + " secs" |
|
382 } |
|
383 |
|
384 search(game2).map(pretty) |
|
385 search(game3).distinct.map(pretty).length |
|
386 time_needed(3, search(game2)) |
|
387 time_needed(3, search(game3)) |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |