Итак, чистое (er) решение, которое выполняет то, что вы просили, выглядит следующим образом:
package basic;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final String data;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
return result;
}
public Node getPrevious() {
return previous;
}
public String getData() {
return data;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
public Node(String data) {
this.data = data;
this.previous = null;
}
public Node(String data, Node previous) {
this.data = data;
this.previous = previous;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>();
Set<Node> closed = new HashSet<>();
Node start = new Node("120345678");
Node goal = new Node("012345678");
open.add(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll();
int pos = current.getData().indexOf('0');
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, pos, open, closed);
down(current, pos, open, closed);
left(current, pos, open, closed);
right(current, pos, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition >= 3) {
char substitutedChar = current.getData().charAt(zeroPosition - 3);
open.add(new Node(current.getData().substring(0, zeroPosition - 3) + '0'
+ current.getData().substring(zeroPosition - 2, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition <= 5) {
char substitutedChar = current.getData().charAt(zeroPosition + 3);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar
+ current.getData().substring(zeroPosition + 1, zeroPosition + 3) + '0'
+ current.getData().substring(zeroPosition + 4), current));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 0) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition - 1) + '0' + substitutedChar
+ current.getData().substring(zeroPosition + 1), current));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, int zeroPosition, Queue<Node> open, Set<Node> closed) {
if (zeroPosition % 3 != 2) {
char substitutedChar = current.getData().charAt(zeroPosition - 1);
open.add(new Node(current.getData().substring(0, zeroPosition) + substitutedChar + '0'
+ current.getData().substring(zeroPosition + 2), current));
}
}
private static void printPath(Node current) {
Stack<String> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(String s) {
System.out.println(s.substring(0, 3));
System.out.println(s.substring(3, 6));
System.out.println(s.substring(6, 9));
System.out.println();
}
}
Обратите внимание, что я не изменил базовое представление платы (вы решили использовать String, хотя я рекомендую использовать двухмерный массив, где свопы намного дешевле и код становится проще для понимания)
Несколько замечаний:
- Чтобы напечатать весь «путь», выдолжны поддерживать связи между «шагами» вашего решения
- Избегайте использования глобальных переменных, где это возможно
- Предпочитайте использовать интерфейсы (Set, Queue) в качестве типов ваших коллекций (и выбирайте их в зависимости от того, как выбудет использовать их)
- Java 8 не требует, чтобы вы указывали конкретные типы, используемые в универсальной коллекции во время построения (поэтому используйте
Set<String> set = new HashSet<>();
вместо использования Set<String> set = new HashSet<String>();
- Где это возможно,избегайте использования лишних (и менее читаемых) условий / структуры кода (предпочитайте
if (booleanVariable)
, а не if (booleanVariable == true)
(возможно, есть еще несколько вещей, которые нужно отнять, но это полезноl список для начала)
EDIT: версия, в которой данные представляют собой 2d-массив, добавляется ниже базового пакета;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class Puzzle {
private static class Node {
private final Node previous;
private final char[][] data;
public Node getPrevious() {
return previous;
}
public char[][] getData() {
return data;
}
public int getZeroX() {
return zeroX;
}
public int getZeroY() {
return zeroY;
}
private final int zeroX;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(data);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Node other = (Node) obj;
if (!Arrays.deepEquals(data, other.data))
return false;
return true;
}
private final int zeroY;
public Node(Node previous, char[][] data, int zeroX, int zeroY) {
super();
this.previous = previous;
this.data = data;
this.zeroX = zeroX;
this.zeroY = zeroY;
}
}
public static void main(String args[]) {
Queue<Node> open = new LinkedList<>(); //Stack<Node> open = new Stack<>();
Set<Node> closed = new HashSet<>();
Node start = new Node(null, new char[][] { { '1', '2', '0' }, { '3', '4', '5' }, { '6', '7', '8' } }, 2, 0);
Node goal = new Node(null, new char[][] { { '0', '1', '2' }, { '3', '4', '5' }, { '6', '7', '8' } }, 0, 0);
open.add(start); //open.push(start);
boolean solving = true;
while (!open.isEmpty() && solving) {
Node current = open.poll(); //open.pop();
if (!closed.contains(current)) {
if (current.equals(goal)) {
printPath(current);
System.out.println("SUCCESS");
solving = false;
} else {
// generate children
up(current, open, closed);
down(current, open, closed);
left(current, open, closed);
right(current, open, closed);
closed.add(current);
}
}
}
}
/*
* MOVEMENT UP
*/
private static void up(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() - 1][current.getZeroX()];
chars[current.getZeroY() - 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() - 1));
}
}
/*
* MOVEMENT DOWN
*/
private static void down(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroY() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY() + 1][current.getZeroX()];
chars[current.getZeroY() + 1][current.getZeroX()] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX(), current.getZeroY() + 1));
}
}
/*
* MOVEMENT LEFT
*/
private static void left(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() > 0) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() - 1];
chars[current.getZeroY()][current.getZeroX() - 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() - 1, current.getZeroY()));
}
}
/*
* MOVEMENT RIGHT
*/
private static void right(Node current, Queue<Node>/*Stack<Node>*/ open, Set<Node> closed) {
if (current.getZeroX() < 2) {
char[][] chars = copy(current.getData());
chars[current.getZeroY()][current.getZeroX()] = chars[current.getZeroY()][current.getZeroX() + 1];
chars[current.getZeroY()][current.getZeroX() + 1] = '0';
open.add/*push*/(new Node(current, chars, current.getZeroX() + 1, current.getZeroY()));
}
}
private static char[][] copy(char[][] data) {
char[][] newData = new char[3][3];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
newData[i][j] = data[i][j];
}
}
return newData;
}
private static void printPath(Node current) {
Stack<char[][]> stack = new Stack<>();
for (; current != null; current = current.getPrevious()) {
stack.push(current.getData());
}
while (!stack.isEmpty()) {
print(stack.pop());
}
}
private static void print(char[][] chars) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(chars[i][j]);
}
System.out.println();
}
System.out.println();
}
}
EDIT2: добавлены комментарии изменений, которые превращают это в DFS
Удачи!