mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-06 17:29:31 +08:00
Add tests, enhance class & function documentation for KnightsTour (#5591)
This commit is contained in:
@ -4,33 +4,26 @@ import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Problem Statement: -
|
||||
|
||||
Given a N*N board with the Knight placed on the first block of an empty board. Moving according
|
||||
to the rules of chess knight must visit each square exactly once. Print the order of each cell in
|
||||
which they are visited.
|
||||
|
||||
Example: -
|
||||
|
||||
Input : N = 8
|
||||
|
||||
Output:
|
||||
0 59 38 33 30 17 8 63
|
||||
37 34 31 60 9 62 29 16
|
||||
58 1 36 39 32 27 18 7
|
||||
35 48 41 26 61 10 15 28
|
||||
42 57 2 49 40 23 6 19
|
||||
47 50 45 54 25 20 11 14
|
||||
56 43 52 3 22 13 24 5
|
||||
51 46 55 44 53 4 21 12
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public final class KnightsTour {
|
||||
private KnightsTour() {
|
||||
}
|
||||
|
||||
// The size of the chess board (12x12 grid, with 2 extra rows/columns as a buffer around a 8x8 area)
|
||||
private static final int BASE = 12;
|
||||
|
||||
// Possible moves for a knight in chess
|
||||
private static final int[][] MOVES = {
|
||||
{1, -2},
|
||||
{2, -1},
|
||||
@ -40,36 +33,40 @@ public final class KnightsTour {
|
||||
{-2, 1},
|
||||
{-2, -1},
|
||||
{-1, -2},
|
||||
}; // Possible moves by knight on chess
|
||||
private static int[][] grid; // chess grid
|
||||
private static int total; // total squares in chess
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Chess grid representing the board
|
||||
static int[][] grid;
|
||||
|
||||
// Total number of cells the knight needs to visit
|
||||
static int total;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static void resetBoard() {
|
||||
grid = new int[BASE][BASE];
|
||||
total = (BASE - 4) * (BASE - 4);
|
||||
|
||||
for (int r = 0; r < BASE; r++) {
|
||||
for (int c = 0; c < BASE; c++) {
|
||||
if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
|
||||
grid[r][c] = -1;
|
||||
grid[r][c] = -1; // Mark boundary cells
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int row = 2 + (int) (Math.random() * (BASE - 4));
|
||||
int col = 2 + (int) (Math.random() * (BASE - 4));
|
||||
|
||||
grid[row][col] = 1;
|
||||
|
||||
if (solve(row, col, 2)) {
|
||||
printResult();
|
||||
} else {
|
||||
System.out.println("no result");
|
||||
}
|
||||
}
|
||||
|
||||
// Return True when solvable
|
||||
private static boolean solve(int row, int column, int count) {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static boolean solve(int row, int column, int count) {
|
||||
if (count > total) {
|
||||
return true;
|
||||
}
|
||||
@ -80,29 +77,37 @@ public final class KnightsTour {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sort neighbors by Warnsdorff's rule (fewest onward moves)
|
||||
neighbor.sort(Comparator.comparingInt(a -> a[2]));
|
||||
|
||||
for (int[] nb : neighbor) {
|
||||
row = nb[0];
|
||||
column = nb[1];
|
||||
grid[row][column] = count;
|
||||
if (!orphanDetected(count, row, column) && solve(row, column, count + 1)) {
|
||||
int nextRow = nb[0];
|
||||
int nextCol = nb[1];
|
||||
grid[nextRow][nextCol] = count;
|
||||
if (!orphanDetected(count, nextRow, nextCol) && solve(nextRow, nextCol, count + 1)) {
|
||||
return true;
|
||||
}
|
||||
grid[row][column] = 0;
|
||||
grid[nextRow][nextCol] = 0; // Backtrack
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns List of neighbours
|
||||
private static List<int[]> neighbors(int row, int column) {
|
||||
/**
|
||||
* 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}
|
||||
*/
|
||||
static List<int[]> neighbors(int row, int column) {
|
||||
List<int[]> neighbour = new ArrayList<>();
|
||||
|
||||
for (int[] m : MOVES) {
|
||||
int x = m[0];
|
||||
int y = m[1];
|
||||
if (grid[row + y][column + x] == 0) {
|
||||
if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
|
||||
int num = countNeighbors(row + y, column + x);
|
||||
neighbour.add(new int[] {row + y, column + x, num});
|
||||
}
|
||||
@ -110,19 +115,34 @@ public final class KnightsTour {
|
||||
return neighbour;
|
||||
}
|
||||
|
||||
// Returns the total count of neighbors
|
||||
private static int countNeighbors(int row, int column) {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static int countNeighbors(int row, int column) {
|
||||
int num = 0;
|
||||
for (int[] m : MOVES) {
|
||||
if (grid[row + m[1]][column + m[0]] == 0) {
|
||||
int x = m[0];
|
||||
int y = m[1];
|
||||
if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
// Returns true if it is orphan
|
||||
private static boolean orphanDetected(int count, int row, int column) {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
static boolean orphanDetected(int count, int row, int column) {
|
||||
if (count < total - 1) {
|
||||
List<int[]> neighbor = neighbors(row, column);
|
||||
for (int[] nb : neighbor) {
|
||||
@ -133,17 +153,4 @@ public final class KnightsTour {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prints the result grid
|
||||
private static void printResult() {
|
||||
for (int[] row : grid) {
|
||||
for (int i : row) {
|
||||
if (i == -1) {
|
||||
continue;
|
||||
}
|
||||
System.out.printf("%2d ", i);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user