Created
January 9, 2016 16:55
-
-
Save kubadlo/b1604b62731e764c4841 to your computer and use it in GitHub Desktop.
Knigh's tour solution.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main; | |
import java.awt.Point; | |
public class Chessboard { | |
private final int KNIGHT_MOVES_COUNT = 8; | |
private final int[][] KNIGHT_MOVES = { | |
{1,-2}, | |
{2,-1}, | |
{2,1}, | |
{1,2}, | |
{-1,2}, | |
{-2,1}, | |
{-2,-1}, | |
{-1,-2} | |
}; | |
private int boardSize; | |
private int[][] chessBoard; | |
private Point lastPosition; | |
public Chessboard(int size) { | |
boardSize = size; | |
chessBoard = new int[boardSize][boardSize]; | |
} | |
/** | |
* Solve chessboard with greedy algorithm. | |
* @param row Start row position. | |
* @param col Start columnt position. | |
* @return True if puzzle was solved. Otherwise false. | |
*/ | |
public boolean solvePuzzle(int row, int col) { | |
int currentRow = row; | |
int currentCol = col; | |
chessBoard[row][col] = 1; | |
for (int move = 2; move <= (boardSize * boardSize); move++) { | |
boolean[] possibleMoves = new boolean[KNIGHT_MOVES_COUNT]; | |
int[] countedMoves = new int[this.KNIGHT_MOVES_COUNT]; | |
// Compute available moves from current position | |
for (int i = 0; i < KNIGHT_MOVES_COUNT; i++) { | |
int nextRow = currentRow + KNIGHT_MOVES[i][0]; | |
int nextCol = currentCol + KNIGHT_MOVES[i][1]; | |
if (!isMovePossible(nextRow, nextCol) || isVisited(nextRow, nextCol)) { | |
continue; | |
} | |
possibleMoves[i] = true; | |
countedMoves[i] = countMoves(nextRow, nextCol); | |
} | |
// Get index of move that have minimum of next possible moves | |
int minimum = KNIGHT_MOVES_COUNT + 1; | |
int index = -1; | |
for (int i = 0; i < KNIGHT_MOVES_COUNT; i++) { | |
if (possibleMoves[i]) { | |
if (index < 0 || minimum == 0 || countedMoves[i] < minimum && countedMoves[i] != 0) { | |
minimum = countedMoves[i]; | |
index = i; | |
} | |
} | |
} | |
// If this index is -1 - solution was not found . Set last visited position and return false. | |
if (index < 0) { | |
lastPosition = new Point(currentCol, currentRow); | |
return false; | |
} | |
// Set new position for next iteration | |
currentRow = currentRow + KNIGHT_MOVES[index][0]; | |
currentCol = currentCol + KNIGHT_MOVES[index][1]; | |
chessBoard[currentRow][currentCol] = move; | |
} | |
// Solution was found. Set last visited position and return true. | |
lastPosition = new Point(currentCol, currentRow); | |
return true; | |
} | |
/** | |
* Count number of possible moves from tile | |
* @param row Start row position. | |
* @param col Start columnt position. | |
* @return Number of possible moves from start position. | |
*/ | |
private int countMoves(int row, int col) { | |
int possibleMoves = 0; | |
// Compute available moves for position | |
for (int secondIteration = 0; secondIteration < this.KNIGHT_MOVES_COUNT; secondIteration++) { | |
int nextRow = row + KNIGHT_MOVES[secondIteration][0]; | |
int nextCol = col + KNIGHT_MOVES[secondIteration][1]; | |
if (!isMovePossible(nextRow, nextCol) || isVisited(nextRow, nextCol)) { | |
continue; | |
} | |
possibleMoves++; | |
} | |
return possibleMoves; | |
} | |
/** | |
* Check if tile was already visited. | |
* @param row | |
* @param col | |
* @return True if position [row, col] was visited. Otherwise false. | |
*/ | |
private boolean isVisited(int row, int col) { | |
return chessBoard[row][col] != 0; | |
} | |
/** | |
* Check if we can move to new position. | |
* @param row | |
* @param col | |
* @return True if move is possible to the position [row, col]. Otherwise false. | |
*/ | |
private boolean isMovePossible(int row, int col) { | |
return (row >= 0) && (row < boardSize) && (col >= 0) && (col < boardSize); | |
} | |
/** | |
* Prints chessboard. | |
*/ | |
public void printChessTable() { | |
for (int row = 0; row < boardSize; row++) { | |
for (int col = 0; col < boardSize; col++) { | |
System.out.print(chessBoard[row][col] + "\t"); | |
} | |
System.out.println(); | |
} | |
} | |
/** | |
* Main function. Starting point in program. | |
* @param args Command line parameters [chessboard size, starting row, starting col] | |
*/ | |
public static void main(String []args) { | |
// Check number of arguments. | |
if (args.length < 3) { | |
System.err.println("Missing or incorrect command line arguments!\n" + | |
"Usage: solver.java [size] [row] [col]"); | |
return; | |
} | |
int size, row, col; | |
// Check if command line arguments are valid. If not throw new error and stop program | |
try { | |
size = Integer.parseInt(args[0]); | |
row = Integer.parseInt(args[1]); | |
col = Integer.parseInt(args[2]); | |
if (col >= size || row >= size || col < 0 || row < 0) { | |
throw new IllegalArgumentException(); | |
} | |
} catch(Exception e) { | |
System.err.println("Incorrect input!"); | |
return; | |
} | |
Chessboard chessboard = new Chessboard(size); | |
long time = System.nanoTime(); | |
boolean solved = chessboard.solvePuzzle(row, col); | |
time = System.nanoTime() - time; | |
if (solved) { | |
System.out.println("Solution was found!"); | |
} else { | |
System.out.println("Solution was not found! "); | |
} | |
System.out.println(String.format("Computing time: %.2f ms.\nStart position: x=%d, y=%d. Last position: x=%d, y=%d.\n", | |
time / 1000000.f, row, col, chessboard.lastPosition.x, chessboard.lastPosition.y)); | |
System.out.println("Chessboard:"); | |
chessboard.printChessTable(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment