mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-22 19:59:09 +08:00
157 lines
4.9 KiB
Java
157 lines
4.9 KiB
Java
package com.thealgorithms.backtracking;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Comparator;
|
|
import java.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.
|
|
*/
|
|
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},
|
|
{2, 1},
|
|
{1, 2},
|
|
{-1, 2},
|
|
{-2, 1},
|
|
{-2, -1},
|
|
{-1, -2},
|
|
};
|
|
|
|
// 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; // 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
|
|
*/
|
|
static boolean solve(int row, int column, int count) {
|
|
if (count > total) {
|
|
return true;
|
|
}
|
|
|
|
List<int[]> neighbor = neighbors(row, column);
|
|
|
|
if (neighbor.isEmpty() && count != total) {
|
|
return false;
|
|
}
|
|
|
|
// Sort neighbors by Warnsdorff's rule (fewest onward moves)
|
|
neighbor.sort(Comparator.comparingInt(a -> a[2]));
|
|
|
|
for (int[] nb : neighbor) {
|
|
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[nextRow][nextCol] = 0; // Backtrack
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 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 (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});
|
|
}
|
|
}
|
|
return neighbour;
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
if (countNeighbors(nb[0], nb[1]) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|