main_testing4/knight1.scala
author Christian Urban <christian.urban@kcl.ac.uk>
Mon, 11 Apr 2022 23:55:27 +0100
changeset 424 daf561a83ba6
parent 403 ffce7b61b446
child 433 6af86ba1208f
permissions -rw-r--r--
added
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
424
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     1
// Main Part 4 about finding Knight's tours
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     2
//==========================================
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     3
import scala.annotation.tailrec
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     4
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     5
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     6
object M4a {
220
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
     7
424
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     8
// If you need any auxiliary functions, feel free to 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
     9
// implement them, but do not make any changes to the
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    10
// templates below. Also have a look whether the functions
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    11
// at the end of the file are of any help.
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    12
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    13
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 221
diff changeset
    14
220
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    15
type Pos = (Int, Int)    // a position on a chessboard 
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    16
type Path = List[Pos]    // a path...a list of positions
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    17
424
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    18
//(1) Complete the function that tests whether the position x
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    19
//    is inside the board and not yet element in the path.
220
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
    20
424
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    21
def is_legal(dim: Int, path: Path, x: Pos) : Boolean = {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    22
  (x._1 < dim) && (x._2 < dim) && (!path.contains(x))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    23
}
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    24
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    25
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    26
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    27
//(2) Complete the function that calculates for a position x
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    28
//    all legal onward moves that are not already in the path. 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    29
//    The moves should be ordered in a "clockwise" manner.
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    30
 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    31
def legal_moves(dim: Int, path: Path, x: Pos) : List[Pos] = {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    32
    val movesets = List(
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    33
    (x._1 + 1, x._2 + 2),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    34
    (x._1 + 2, x._2 + 1),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    35
    (x._1 + 2, x._2 - 1),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    36
    (x._1 + 1, x._2 - 2),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    37
    (x._1 - 1, x._2 - 2),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    38
    (x._1 - 2, x._2 - 1),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    39
    (x._1 - 2, x._2 + 1),
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    40
    (x._1 - 1, x._2 + 2)
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    41
  )
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    42
  movesets.filter(is_legal(dim, path, _))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    43
}
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    44
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    45
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    46
//some testcases
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    47
//
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    48
//assert(legal_moves(8, Nil, (2,2)) == 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    49
//  List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4)))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    50
//assert(legal_moves(8, Nil, (7,7)) == List((6,5), (5,6)))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    51
//assert(legal_moves(8, List((4,1), (1,0)), (2,2)) == 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    52
//  List((3,4), (4,3), (3,0), (0,1), (0,3), (1,4)))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    53
//assert(legal_moves(8, List((6,6)), (7,7)) == List((6,5), (5,6)))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    54
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    55
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    56
//(3) Complete the two recursive functions below. 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    57
//    They exhaustively search for knight's tours starting from the 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    58
//    given path. The first function counts all possible tours, 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    59
//    and the second collects all tours in a list of paths.
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    60
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    61
def count_tours(dim: Int, path: Path) : Int = {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    62
  if (dim <= 4) 0 else {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    63
    if (path.length >= (dim * dim)) 1 else {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    64
      val movesets = legal_moves(dim, path, path.head)
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    65
      (for (move <- movesets) yield count_tours(dim, move :: path)).sum
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    66
    }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    67
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    68
}
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    69
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    70
def enum_tours(dim: Int, path: Path) : List[Path] = {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    71
  if (dim <= 4) Nil else {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    72
    if (path.length >= (dim * dim)) List(path) else {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    73
      val movesets = legal_moves(dim, path, path.head)
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    74
      (for (move <- movesets) yield enum_tours(dim, move :: path)).flatten
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    75
    }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    76
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    77
}
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    78
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    79
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    80
//(4) Implement a first-function that finds the first 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    81
//    element, say x, in the list xs where f is not None. 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    82
//    In that case Return f(x), otherwise None. If possible,
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    83
//    calculate f(x) only once.
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    84
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    85
@tailrec
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    86
def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    87
  xs match {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    88
    case Nil => None
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    89
    case head :: rest => {
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    90
      val result = f(head)
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    91
      if (result.isEmpty) first(rest, f) else result
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    92
    }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    93
  }
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    94
}
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    95
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    96
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    97
// testcases
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    98
//
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
    99
//def foo(x: (Int, Int)) = if (x._1 > 3) Some(List(x)) else None
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   100
//
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   101
//first(List((1, 0),(2, 0),(3, 0),(4, 0)), foo)   // Some(List((4,0)))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   102
//first(List((1, 0),(2, 0),(3, 0)), foo)          // None
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   103
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   104
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   105
//(5) Implement a function that uses the first-function from (4) for
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   106
//    trying out onward moves, and searches recursively for a
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   107
//    knight tour on a dim * dim-board.
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   108
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   109
def first_tour(dim: Int, path: Path) : Option[Path] = ???
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   110
 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   111
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   112
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   113
/* Helper functions
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   114
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   115
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   116
// for measuring time
220
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   117
def time_needed[T](code: => T) : T = {
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   118
  val start = System.nanoTime()
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   119
  val result = code
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   120
  val end = System.nanoTime()
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   121
  println(f"Time needed: ${(end - start) / 1.0e9}%3.3f secs.")
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   122
  result
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   123
}
3020f8c76baa updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   124
424
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   125
// can be called for example with
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   126
//
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   127
//     time_needed(count_tours(dim, List((0, 0))))
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   128
//
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   129
// in order to print out the time that is needed for 
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   130
// running count_tours
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   131
Christian Urban <christian.urban@kcl.ac.uk>
parents: 403
diff changeset
   132
347
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   133
// for printing a board
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   134
def print_board(dim: Int, path: Path): Unit = {
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   135
  println()
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   136
  for (i <- 0 until dim) {
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   137
    for (j <- 0 until dim) {
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   138
      print(f"${path.reverse.indexOf((j, dim - i - 1))}%3.0f ")
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   139
    }
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   140
    println()
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   141
  } 
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   142
}
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   143
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   144
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   145
*/
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   146
4de31fdc0d67 updated
Christian Urban <christian.urban@kcl.ac.uk>
parents: 346
diff changeset
   147
}