package org.teachingextensions.logo.utils.PuzzleUtils; import java.awt.Point; import java.util.Arrays; /** * A nine-puzzle * * @see <a href="http://en.wikipedia.org/wiki/15_puzzle">Wikipedia</a> */ public class Puzzle { private static final int blank = 8; private final int[] cells; public Puzzle(int[] cells) { this.cells = cells; } /** * Gives the position of the cell as it would appear on a 3x3 board. * * @param cell * The cell to get the position for. * @return The position of the cell. */ public static Point getPosition(int cell) { return new Point(cell % 3, cell / 3); } /** * Calculate the <a href="http://en.wikipedia.org/wiki/Taxicab_geometry">Manhattan Distance</a> between two positions. * * @param start * The starting position. * @param end * The ending position. * @return The distance between the two positions. */ public static int getDistance(Point start, Point end) { return Math.abs(start.x - end.x) + Math.abs(start.y - end.y); } /** * Calculate the <a href="http://en.wikipedia.org/wiki/Taxicab_geometry">Manhattan Distance</a> between two cells by first converting them to positions. * * @param start * The starting cell * @param end * The ending cell * @return The distance between the cells. */ public static int getDistance(int start, int end) { return getDistance(getPosition(start), getPosition(end)); } @Override public int hashCode() { return Arrays.hashCode(cells); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Puzzle puzzle = (Puzzle) o; return Arrays.equals(cells, puzzle.cells); } @Override public String toString() { return Arrays.toString(cells); } public boolean isSolved() { return getDistanceToGoal() == 0; } public int getBlankIndex() { for (int i = 0; i < cells.length; i++) { if (cells[i] == blank) { return i; } } return -1; } /** * Create a copy of the puzzle where the blank swapped with the value in the target position * * @param target * move the blank to this location, and move the value from this location to the current blank location * @return A copy of the puzzle with the blank and target swapped. */ public Puzzle swapBlank(int target) { int[] copy = Arrays.copyOf(cells, cells.length); int x = copy[target]; copy[getBlankIndex()] = x; copy[target] = 8; return new Puzzle(copy); } /** * Calculate the distance between the goal by summing the distance between each cell and its goal. * * @return The distance to the goal. */ public int getDistanceToGoal() { int distance = 0; for (int i = 0; i < cells.length; i++) { distance += getDistance(i, cells[i]); } return distance; } public int[] getCells() { return Arrays.copyOf(cells, cells.length); } }