-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKnightTour.java
More file actions
184 lines (145 loc) · 4.77 KB
/
KnightTour.java
File metadata and controls
184 lines (145 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*======================================
class KnightTour
Animates a Knight's Tour of a square chess board.
Mean execution times for boards of size n*n:
n=5 __s over __ executions
n=6 __s over __ executions
n=7 __s over __ executions
n=8 __s over __ executions
======================================*/
/***
* USAGE:
* $ javac KnightTour.java
* $ java KnightTour
* $ java KnightTour [N]
*
* (default N value: 8)
*
* POSIX TIP: to measure execution time, use time program:
* $ time java KnightTour 5
***/
import java.io.*;
import java.util.*;
class TourFinder
{
//instance vars
private int[][] _board;
private int sideLength; //board has dimensions n x n
private boolean solved = false;
//constructor
public TourFinder( int n ) {
sideLength = n;
//init 2D array to represent square board with moat
_board = new int[n+4][n+4];
//SETUP BOARD -- 0 on each cell to represent unvisited
// -1 on each border/buffer cell around edges
//---------------------------------------------------------
for( int i=0; i < n+4; i++ )
for( int j=0; j < n+4; j++ )
_board[i][j] = -1; //lay down initial blanket of -1's
for( int i=2; i < n+2; i++ )
for( int j=2; j < n+2; j++ )
_board[i][j] = 0; //lay down 0's for actual _board
//---------------------------------------------------------
}//end constructor
public String toString()
{
//send ANSI code "ESC[0;0H" to place cursor in upper left
String retStr = "[0;0H";
//emacs shortcut: C-q, then press ESC
//emacs shortcut: M-x quoted-insert, then press ESC
int i, j;
for( i=0; i < sideLength+4; i++ ) {
for( j=0; j < sideLength+4; j++ )
retStr = retStr + String.format( "%3d", _board[j][i] );
//"%3d" allots 3 spaces for each number
retStr = retStr + "\n";
}
return retStr;
}
//helper method to keep try/catch clutter out of main flow
private void delay( int n )
{
try {
Thread.sleep(n);
} catch( InterruptedException e ) {
System.exit(0);
}
}
/*********************************************
* void findTour(int x,int y,int moves) -- use depth-first w/ backtracking algo
* to find valid knight's tour
* @param x starting x-coord
* @param y starting y-coord
* @param moves number of moves made so far
*********************************************/
public boolean findTour( int x, int y, int moves )
{
//delay(50); //slow it down enough to be followable
System.out.println( this ); //refresh screen
//if a tour has been completed, stop animation
if ( solved ) System.exit(0);
//primary base case: tour completed
if ( moves > sideLength*sideLength ) {
solved = true;
System.out.println( this ); //refresh screen
return true;
}
//other base case: stepped off board or onto visited cell
if ( _board[x][y] != 0 ) {
return false;
}
//otherwise, mark current location
//and recursively generate tour possibilities from current pos
else {
//mark current cell with current move number
_board[x][y] = moves;
System.out.println( this ); //refresh screen
//delay(1000); //uncomment to slow down enough to view
/*======================================
Recursively try to solve (find tour) from
each of knight's available moves.
. e . d .
f . . . c
. . @ . .
g . . . b
. h . a .
======================================*/
findTour( x+1, y+2, moves+1 ); // a
findTour( x+2, y+1, moves+1 ); // b
findTour( x+2, y-1, moves+1 ); // c
findTour( x+1, y-2, moves+1 ); // d
findTour( x-1, y-2, moves+1 ); // e
findTour( x-2, y-1, moves+1 ); // f
findTour( x-2, y+1, moves+1 ); // g
findTour( x-1, y+2, moves+1 ); // h
// (Overwrite number at this cell with a 0.)
_board[x][y] = 0;
//If made it this far, path did not lead to tour, so back up.
}
}//end findTour()
return false;
}//end class TourFinder
public class KnightTour
{
public static void main( String[] args ) {
int n = 8;
try {
n = Integer.parseInt( args[0] );
}catch( Exception e ) {
System.out.println( "Invalid input. Using board size "
+ n + "..." );
}
TourFinder tf = new TourFinder( n );
//clear screen using ANSI control code
System.out.println( "[2J" );
//display board
System.out.println( tf );
//for random starting location, use lines below:
//int startX = 2 + (int)( n * Math.random() );
//int startY = 2 + (int)( n * Math.random() );
//tf.findTour( startX, startY, 1 ); // 1 or 0 ?
//for fixed starting location, use line below:
tf.findTour( 2, 2, 1 );
}//end main()
}//end class KnightTour