- Notifications
You must be signed in to change notification settings - Fork 19.9k
/
Copy pathKnightsTour.java
156 lines (139 loc) · 4.93 KB
/
KnightsTour.java
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
packagecom.thealgorithms.backtracking;
importjava.util.ArrayList;
importjava.util.Comparator;
importjava.util.List;
/**
* The KnightsTour class solves the Knight's Tour problem using backtracking.
*
* Problem Statement:
* Given an N*N board with a knight placed on the first block, the knight must
* move according to chess rules and visit each square on the board exactly once.
* The class outputs the sequence of moves for the knight.
*
* Example:
* Input: N = 8 (8x8 chess board)
* Output: The sequence of numbers representing the order in which the knight visits each square.
*/
publicfinalclassKnightsTour {
privateKnightsTour() {
}
// The size of the chess board (12x12 grid, with 2 extra rows/columns as a buffer around a 8x8 area)
privatestaticfinalintBASE = 12;
// Possible moves for a knight in chess
privatestaticfinalint[][] MOVES = {
{1, -2},
{2, -1},
{2, 1},
{1, 2},
{-1, 2},
{-2, 1},
{-2, -1},
{-1, -2},
};
// Chess grid representing the board
staticint[][] grid;
// Total number of cells the knight needs to visit
staticinttotal;
/**
* Resets the chess board to its initial state.
* Initializes the grid with boundary cells marked as -1 and internal cells as 0.
* Sets the total number of cells the knight needs to visit.
*/
publicstaticvoidresetBoard() {
grid = newint[BASE][BASE];
total = (BASE - 4) * (BASE - 4);
for (intr = 0; r < BASE; r++) {
for (intc = 0; c < BASE; c++) {
if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
grid[r][c] = -1; // Mark boundary cells
}
}
}
}
/**
* Recursive method to solve the Knight's Tour problem.
*
* @param row The current row of the knight
* @param column The current column of the knight
* @param count The current move number
* @return True if a solution is found, False otherwise
*/
staticbooleansolve(introw, intcolumn, intcount) {
if (count > total) {
returntrue;
}
List<int[]> neighbor = neighbors(row, column);
if (neighbor.isEmpty() && count != total) {
returnfalse;
}
// Sort neighbors by Warnsdorff's rule (fewest onward moves)
neighbor.sort(Comparator.comparingInt(a -> a[2]));
for (int[] nb : neighbor) {
intnextRow = nb[0];
intnextCol = nb[1];
grid[nextRow][nextCol] = count;
if (!orphanDetected(count, nextRow, nextCol) && solve(nextRow, nextCol, count + 1)) {
returntrue;
}
grid[nextRow][nextCol] = 0; // Backtrack
}
returnfalse;
}
/**
* Returns a list of valid neighboring cells where the knight can move.
*
* @param row The current row of the knight
* @param column The current column of the knight
* @return A list of arrays representing valid moves, where each array contains:
* {nextRow, nextCol, numberOfPossibleNextMoves}
*/
staticList<int[]> neighbors(introw, intcolumn) {
List<int[]> neighbour = newArrayList<>();
for (int[] m : MOVES) {
intx = m[0];
inty = m[1];
if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
intnum = countNeighbors(row + y, column + x);
neighbour.add(newint[] {row + y, column + x, num});
}
}
returnneighbour;
}
/**
* Counts the number of possible valid moves for a knight from a given position.
*
* @param row The row of the current position
* @param column The column of the current position
* @return The number of valid neighboring moves
*/
staticintcountNeighbors(introw, intcolumn) {
intnum = 0;
for (int[] m : MOVES) {
intx = m[0];
inty = m[1];
if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
num++;
}
}
returnnum;
}
/**
* Detects if moving to a given position will create an orphan (a position with no further valid moves).
*
* @param count The current move number
* @param row The row of the current position
* @param column The column of the current position
* @return True if an orphan is detected, False otherwise
*/
staticbooleanorphanDetected(intcount, introw, intcolumn) {
if (count < total - 1) {
List<int[]> neighbor = neighbors(row, column);
for (int[] nb : neighbor) {
if (countNeighbors(nb[0], nb[1]) == 0) {
returntrue;
}
}
}
returnfalse;
}
}