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