1 // Part 3 about finding a single tour using the Warnsdorf Rule |
1 // Part 3 about finding a single tour using the Warnsdorf Rule |
2 //============================================================= |
2 //============================================================= |
3 |
3 |
4 object CW7c { |
4 //object CW8c { // for preparing the jar |
5 |
5 |
6 type Pos = (Int, Int) |
6 type Pos = (Int, Int) |
7 type Path = List[Pos] |
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 |
8 |
19 |
9 def print_board(dim: Int, path: Path): Unit = { |
20 def print_board(dim: Int, path: Path): Unit = { |
10 println |
21 println |
11 for (i <- 0 until dim) { |
22 for (i <- 0 until dim) { |
12 for (j <- 0 until dim) { |
23 for (j <- 0 until dim) { |
13 print(f"${path.reverse.indexOf((i, j))}%3.0f ") |
24 print(f"${path.reverse.indexOf((i, j))}%4.0f ") |
14 } |
25 } |
15 println |
26 println |
16 } |
27 } |
17 } |
28 } |
18 |
29 |
19 def add_pair(x: Pos)(y: Pos): Pos = |
30 def add_pair(x: Pos, y: Pos): Pos = |
20 (x._1 + y._1, x._2 + y._2) |
31 (x._1 + y._1, x._2 + y._2) |
21 |
32 |
22 def is_legal(dim: Int, path: Path)(x: Pos): Boolean = |
33 def is_legal(dim: Int, path: Path, x: Pos): Boolean = |
23 0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x) |
34 0 <= x._1 && 0 <= x._2 && x._1 < dim && x._2 < dim && !path.contains(x) |
24 |
35 |
25 def moves(x: Pos): List[Pos] = |
36 def moves(x: Pos): List[Pos] = |
26 List(( 1, 2),( 2, 1),( 2, -1),( 1, -2), |
37 List(( 1, 2),( 2, 1),( 2, -1),( 1, -2), |
27 (-1, -2),(-2, -1),(-2, 1),(-1, 2)).map(add_pair(x)) |
38 (-1, -2),(-2, -1),(-2, 1),(-1, 2)).map(add_pair(x, _)) |
28 |
39 |
29 def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = |
40 def legal_moves(dim: Int, path: Path, x: Pos): List[Pos] = |
30 moves(x).filter(is_legal(dim, path)) |
41 moves(x).filter(is_legal(dim, path, _)) |
31 |
42 |
32 def ordered_moves(dim: Int, path: Path, x: Pos): List[Pos] = |
43 def ordered_moves(dim: Int, path: Path, x: Pos): List[Pos] = |
33 legal_moves(dim, path, x).sortBy((x) => legal_moves(dim, path, x).length) |
44 legal_moves(dim, path, x).sortBy((x) => legal_moves(dim, path, x).length) |
34 |
|
35 |
45 |
36 import scala.annotation.tailrec |
46 import scala.annotation.tailrec |
37 |
47 |
38 @tailrec |
48 @tailrec |
39 def first(xs: List[Pos], f: Pos => Option[Path]): Option[Path] = xs match { |
49 def tour_on_mega_board_aux(dim: Int, paths: List[Path]): Option[Path] = paths match { |
40 case Nil => None |
50 case Nil => None |
41 case x::xs => { |
51 case (path::rest) => |
42 val result = f(x) |
52 if (path.length == dim * dim) Some(path) |
43 if (result.isDefined) result else first(xs, f) |
53 else tour_on_mega_board_aux(dim, ordered_moves(dim, path, path.head).map(_::path) ::: rest) |
44 } |
|
45 } |
54 } |
46 |
55 |
47 |
56 def ttour_on_mega_board(dim: Int, path: Path): Option[Path] = |
48 def first_closed_tour_heuristic(dim: Int, path: Path): Option[Path] = { |
57 tour_on_mega_board_aux(dim, List(path)) |
49 if (path.length == dim * dim && moves(path.head).contains(path.last)) Some(path) |
|
50 else |
|
51 first(ordered_moves(dim, path, path.head), (x: Pos) => first_closed_tour_heuristic(dim, x::path)) |
|
52 } |
|
53 |
|
54 /* |
|
55 for (dim <- 1 to 6) { |
|
56 val t = first_closed_tour_heuristic(dim, List((dim / 2, dim / 2))) |
|
57 println(s"${dim} x ${dim} closed: " + (if (t == None) "" else { print_board(dim, t.get) ; "" })) |
|
58 }*/ |
|
59 |
58 |
60 |
59 |
61 def first_tour_heuristic(dim: Int, path: Path): Option[Path] = { |
60 def tour_on_mega_board(dim: Int, path: Path) = |
|
61 time_needed(ttour_on_mega_board(dim: Int, path: Path)) |
62 |
62 |
63 @tailrec |
63 //} |
64 def aux(dim: Int, path: Path, moves: List[Pos]): Option[Path] = |
|
65 if (path.length == dim * dim) Some(path) |
|
66 else |
|
67 moves match { |
|
68 case Nil => None |
|
69 case x::xs => { |
|
70 val r = first_tour_heuristic(dim, x::path) |
|
71 if (r.isDefined) r else aux(dim, path, xs) |
|
72 } |
|
73 } |
|
74 |
|
75 aux(dim, path, ordered_moves(dim, path, path.head)) |
|
76 } |
|
77 |
|
78 /* |
|
79 def first_tour_heuristic(dim: Int, path: Path): Option[Path] = { |
|
80 if (path.length == dim * dim) Some(path) |
|
81 else |
|
82 first(ordered_moves(dim, path, path.head), (x: Pos) => first_tour_heuristic(dim, x::path)) |
|
83 } |
|
84 */ |
|
85 |
|
86 /* |
|
87 for (dim <- 1 to 50) { |
|
88 val t = first_tour_heuristic(dim, List((dim / 2, dim / 2))) |
|
89 println(s"${dim} x ${dim}: " + (if (t == None) "" else { print_board(dim, t.get) ; "" })) |
|
90 } |
|
91 */ |
|
92 |
|
93 } |
|
94 |
|
95 |
|
96 //CW7c.first_tour_heuristic(50, List((0,0))).get |
|