| author | Christian Urban <christian.urban@kcl.ac.uk> | 
| Sat, 11 Mar 2023 22:42:09 +0000 | |
| changeset 461 | eda26fa6d3ec | 
| parent 421 | 864107857d27 | 
| permissions | -rw-r--r-- | 
| 421 | 1 | // Part 2 about finding a single tour using the Warnsdorf Rule | 
| 391 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 2 | //============================================================= | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 3 | |
| 421 | 4 | object M4b { // for preparing the jar
 | 
| 391 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 5 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 6 | type Pos = (Int, Int) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 7 | type Path = List[Pos] | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 8 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 9 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 10 | // for measuring time in the JAR | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 11 | def time_needed[T](code: => T) : T = {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 12 | val start = System.nanoTime() | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 13 | val result = code | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 14 | val end = System.nanoTime() | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 15 |   println(f"Time needed: ${(end - start) / 1.0e9}%3.3f secs.")
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 16 | result | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 17 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 18 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 19 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 20 | def print_board(dim: Int, path: Path): Unit = {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 21 | println() | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 22 |   for (i <- 0 until dim) {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 23 |     for (j <- 0 until dim) {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 24 |       print(f"${path.reverse.indexOf((i, j))}%4.0f ")
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 25 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 26 | println() | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 27 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 28 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 29 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 30 | def add_pair(x: Pos, y: Pos): Pos = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 31 | (x._1 + y._1, x._2 + y._2) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 32 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 33 | def is_legal(dim: Int, path: Path, x: Pos): Boolean = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 34 | 0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 35 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 36 | def moves(x: Pos): List[Pos] = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 37 | List(( 1, 2),( 2, 1),( 2, -1),( 1, -2), | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 38 | (-1, -2),(-2, -1),(-2, 1),(-1, 2)).map(add_pair(x, _)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 39 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 40 | def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 41 | moves(x).filter(is_legal(dim, path, _)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 42 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 43 | def ordered_moves(dim: Int, path: Path, x: Pos): List[Pos] = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 44 | legal_moves(dim, path, x).sortBy((x) => legal_moves(dim, path, x).length) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 45 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 46 | import scala.annotation.tailrec | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 47 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 48 | @tailrec | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 49 | def first(xs: List[Pos], f: Pos => Option[Path]): Option[Path] = xs match {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 50 | case Nil => None | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 51 |   case x::xs => {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 52 | val result = f(x) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 53 | if (result.isDefined) result else first(xs, f) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 54 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 55 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 56 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 57 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 58 | def tfirst_closed_tour_heuristics(dim: Int, path: Path): Option[Path] = {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 59 | if (path.length == dim * dim && moves(path.head).contains(path.last)) Some(path) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 60 | else | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 61 | first(ordered_moves(dim, path, path.head), (x: Pos) => tfirst_closed_tour_heuristics(dim, x::path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 62 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 63 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 64 | def first_closed_tour_heuristics(dim: Int, path: Path) = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 65 | time_needed(tfirst_closed_tour_heuristics(dim: Int, path: Path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 66 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 67 | def first_closed_tour_heuristic(dim: Int, path: Path) = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 68 | time_needed(tfirst_closed_tour_heuristics(dim: Int, path: Path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 69 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 70 | // heuristic cannot be used to search for closed tours on 7 x 7 an beyond | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 71 | //for (dim <- 1 to 6) {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 72 | // val t = time_needed(0, first_closed_tour_heuristics(dim, List((dim / 2, dim / 2)))) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 73 | //  println(s"${dim} x ${dim} closed: " + (if (t == None) "" else { print_board(dim, t.get) ; "" }))
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 74 | //} | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 75 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 76 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 77 | def tfirst_tour_heuristics(dim: Int, path: Path): Option[Path] = {
 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 78 | if (path.length == dim * dim) Some(path) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 79 | else | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 80 | first(ordered_moves(dim, path, path.head), (x: Pos) => tfirst_tour_heuristics(dim, x::path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 81 | } | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 82 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 83 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 84 | def first_tour_heuristics(dim: Int, path: Path) = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 85 | time_needed(tfirst_tour_heuristics(dim: Int, path: Path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 86 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 87 | def first_tour_heuristic(dim: Int, path: Path) = | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 88 | time_needed(tfirst_tour_heuristics(dim: Int, path: Path)) | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 89 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 90 | // will be called with boards up to 30 x 30 | 
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 91 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 92 | |
| 
048fc6b70776
added main4 marking
 Christian Urban <christian.urban@kcl.ac.uk> parents: diff
changeset | 93 | } |