progs/knight3.scala
changeset 468 0587ef444547
parent 467 9b5165b8a762
child 469 48de09728447
equal deleted inserted replaced
467:9b5165b8a762 468:0587ef444547
     1 // Part 3 about finding a single tour using the Warnsdorf Rule
       
     2 //=============================================================
       
     3 
       
     4 
       
     5 type Pos = (Int, Int)
       
     6 type Path = List[Pos]
       
     7 
       
     8 // for measuring time
       
     9 def time_needed[T](n: Int, code: => T) : T = {
       
    10   val start = System.nanoTime()
       
    11   for (i <- 0 until n) code
       
    12   val result = code
       
    13   val end = System.nanoTime()
       
    14   println(f"Time needed: ${(end - start) / 1.0e9}%3.3f secs.")
       
    15   result
       
    16 }
       
    17 
       
    18 def print_board(dim: Int, path: Path): Unit = {
       
    19   println
       
    20   for (i <- 0 until dim) {
       
    21     for (j <- 0 until dim) {
       
    22       print(f"${path.reverse.indexOf((i, j))}%4.0f ")
       
    23     }
       
    24     println
       
    25   } 
       
    26 }
       
    27 
       
    28 def add_pair(x: Pos, y: Pos): Pos = 
       
    29   (x._1 + y._1, x._2 + y._2)
       
    30 
       
    31 def is_legal(dim: Int, path: Path, x: Pos): Boolean = 
       
    32   0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x)
       
    33 
       
    34 def moves(x: Pos): List[Pos] = 
       
    35   List(( 1,  2),( 2,  1),( 2, -1),( 1, -2),
       
    36        (-1, -2),(-2, -1),(-2,  1),(-1,  2)).map(add_pair(x, _))
       
    37 
       
    38 def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = 
       
    39   moves(x).filter(is_legal(dim, path, _))
       
    40 
       
    41 def ordered_moves(dim: Int, path: Path, x: Pos): List[Pos] = 
       
    42   legal_moves(dim, path, x).sortBy((x) => legal_moves(dim, path, x).length)
       
    43 
       
    44 import scala.annotation.tailrec
       
    45 
       
    46 @tailrec
       
    47 def first(xs: List[Pos], f: Pos => Option[Path]): Option[Path] = xs match {
       
    48   case Nil => None
       
    49   case x::xs => {
       
    50     val result = f(x)
       
    51     if (result.isDefined) result else first(xs, f)
       
    52   }
       
    53 }
       
    54 
       
    55 
       
    56 //def first[A, B](xs: List[A], f: A => Option[B]): Option[B] =
       
    57 //  xs.flatMap(f(_)).headOption
       
    58 
       
    59 
       
    60 def first_closed_tour_heuristics(dim: Int, path: Path): Option[Path] = {
       
    61   if (path.length == dim * dim && moves(path.head).contains(path.last)) Some(path)
       
    62   else
       
    63     first(ordered_moves(dim, path, path.head), (x: Pos) => first_closed_tour_heuristics(dim, x::path))
       
    64 }
       
    65 
       
    66 // heuristic cannot be used to search for closed tours on 7 x 7
       
    67 for (dim <- 1 to 6) {
       
    68   val t = time_needed(0, first_closed_tour_heuristics(dim, List((dim / 2, dim / 2))))
       
    69   println(s"${dim} x ${dim} closed: " + (if (t == None) "" else { print_board(dim, t.get) ; "" }))
       
    70 }
       
    71 
       
    72 
       
    73 //@tailrec
       
    74 /*
       
    75 def first_tour_heuristics(dim: Int, path: Path): Option[Path] = {
       
    76 
       
    77   @tailrec
       
    78   def aux(dim: Int, path: Path, moves: List[Pos]): Option[Path] = 
       
    79   if (path.length == dim * dim) Some(path)
       
    80   else
       
    81     moves match {
       
    82       case Nil => None
       
    83       case x::xs => {
       
    84         val r = first_tour_heuristics(dim, x::path)
       
    85         if (r.isDefined) r else aux(dim, path, xs)
       
    86       }    
       
    87     }
       
    88 
       
    89   aux(dim, path, ordered_moves(dim, path, path.head)) 
       
    90 }
       
    91 */ 
       
    92 
       
    93 @tailrec
       
    94 def tour_on_mega_board(dim: Int, paths: List[Path]): Option[Path] = paths match {
       
    95   case Nil => None
       
    96   case (path::rest) =>
       
    97     if (path.length == dim * dim) Some(path)
       
    98     else tour_on_mega_board(dim, ordered_moves(dim, path, path.head).map(_::path) ::: rest)
       
    99 }
       
   100 
       
   101 
       
   102 
       
   103 /*
       
   104 def first_tour_heuristics(dim: Int, path: Path): Option[Path] = {
       
   105   if (path.length == dim * dim) Some(path)
       
   106   else
       
   107     for (p <- ordered_moves(dim, path, path.head))
       
   108       val r = first_tour_heuristics(dim, x::path)
       
   109     //first(ordered_moves(dim, path, path.head), (x: Pos) => first_tour_heuristics(dim, x::path))
       
   110     ordered_moves(dim, path, path.head).view.flatMap((x: Pos) => first_tour_heuristics(dim, x::path)).headOption
       
   111 }
       
   112 */ 
       
   113 
       
   114 /*
       
   115 for (dim <- 1 to 50) {
       
   116   val t = first_tour_heuristics(dim, List((dim / 2, dim / 2)))
       
   117   println(s"${dim} x ${dim}: " + (if (t == None) "" else { print_board(dim, t.get) ; "" }))
       
   118 }
       
   119 */
       
   120 
       
   121 val dim = 70
       
   122 println(s"${dim} x ${dim}:")
       
   123 print_board(dim, time_needed(0, tour_on_mega_board(dim, List(List((0, 0)))).get))
       
   124