172 lines
7.5 KiB
Java
172 lines
7.5 KiB
Java
package org.artisanlogiciel.games.maze.solve;
|
|
|
|
import org.artisanlogiciel.games.maze.LabyModel;
|
|
import org.artisanlogiciel.games.maze.MazeParams;
|
|
import org.artisanlogiciel.games.maze.Position;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
public class SolvingModel
|
|
extends LabyModel
|
|
{
|
|
|
|
public SolvingModel(MazeParams params) {
|
|
super(params);
|
|
}
|
|
|
|
public SolvingModel(LabyModel model) {
|
|
super(model);
|
|
}
|
|
|
|
/**
|
|
* resolve this labrynth using internal representation
|
|
* initial (x,y) is exit, will return list of positions from start (0,0) to end (x,y)
|
|
**/
|
|
public LinkedList<DirectionPosition> resolve(int x, int y, MazeResolutionListener rlistener) {
|
|
int width = getWidth();
|
|
int height = getHeight();
|
|
long safeguard = width * height;
|
|
int newx = 0;
|
|
int newy = 0;
|
|
|
|
resetResolving();
|
|
|
|
// list of alternate paths
|
|
LinkedList<LinkedList<DirectionPosition>> altpath = new LinkedList<>();
|
|
|
|
// list of positions from start to end
|
|
LinkedList<DirectionPosition> backpath = new LinkedList<DirectionPosition>();
|
|
// position that point to (x,y).
|
|
DirectionPosition found = new DirectionPosition((short) 0, new Position(x, y));
|
|
// entry
|
|
Position entry = new Position(0, 0);
|
|
|
|
while (!found.getPosition().equals(entry)) {
|
|
Position last = found.getPosition();
|
|
backpath.addFirst(found);
|
|
found = null;
|
|
|
|
// should find from all adjacent cells (directions) one that point to this.
|
|
{
|
|
// didx is index of four cell adjacent to this (x,y)
|
|
for (int didx = 0; didx < 4; didx++) {
|
|
int delta = 0;
|
|
short direction = AllDirections[didx];
|
|
short reversedirection = getReverseDirection(didx);
|
|
short pointingdirection = DIRECTION;
|
|
|
|
if (isFlagSet(direction, POSITIVE)) {
|
|
delta = 1;
|
|
pointingdirection |= NEGATIVE;
|
|
} else {
|
|
delta = -1;
|
|
pointingdirection |= POSITIVE;
|
|
}
|
|
|
|
if (isFlagSet(direction, HORIZONTAL)) {
|
|
newx = last.getX() + delta;
|
|
newy = last.getY();
|
|
pointingdirection |= HORIZONTAL;
|
|
} else {
|
|
newy = last.getY() + delta;
|
|
newx = last.getX();
|
|
pointingdirection |= VERTICAL;
|
|
}
|
|
|
|
// internal GUARD.
|
|
if (!isFlagSet(reversedirection, pointingdirection)) {
|
|
System.out.println("[FATAL] Internal ERROR. Please check AllDirections order "
|
|
+ (reversedirection & pointingdirection) + " " + pointingdirection);
|
|
return backpath;
|
|
}
|
|
|
|
Position p = new Position(newx, newy);
|
|
if ((newx >= 0) && (newy >= 0) && (newx < width) && (newy < height)) {
|
|
if (isFlagSet(getCell(p), reversedirection)) {
|
|
if (found != null) {
|
|
// there is already a potential solution in adjacent cell of last.
|
|
System.out.println("alternate " + p + " from " + last + "/" + safeguard);
|
|
// could be a unique parent of two paths...
|
|
// but search from other entry/exits than generated
|
|
// from
|
|
// ie entry(0,0) exit(width-1,height-1) not yet
|
|
// implemented.
|
|
{
|
|
if (!isFlagSet(getCell(p), SOLVED)) {
|
|
LinkedList<DirectionPosition> cp = new LinkedList<DirectionPosition>(backpath);
|
|
DirectionPosition altfound = new DirectionPosition(reversedirection, p);
|
|
cp.addFirst(altfound);
|
|
altpath.addLast(cp);
|
|
rlistener.notifySearchError("record alternate path " + p.toString());
|
|
} else {
|
|
// this was already solved, might be a loop.
|
|
if (rlistener != null) {
|
|
rlistener.notifySearchError("Loop " + last.toString() + " has two parents " + found.toString() + " "
|
|
+ p.toString());
|
|
}
|
|
// continue;
|
|
}
|
|
}
|
|
} else {
|
|
if (!isFlagSet(getCell(p), SOLVED)) {
|
|
// this is first potential solution in adjacent cell of last.
|
|
System.out.println("check " + p + " from " + last + "/" + safeguard);
|
|
|
|
found = new DirectionPosition(reversedirection, p);
|
|
if (rlistener != null) {
|
|
rlistener.notifySearch(found);
|
|
}
|
|
} else {
|
|
// was already solved.
|
|
System.out.println("already solved " + p + " from " + last + "/" + safeguard);
|
|
}
|
|
}
|
|
// support multiple pathes
|
|
} else {
|
|
System.out.println("not reachable " + p + " from " + last + "/" + safeguard);
|
|
}
|
|
} else {
|
|
System.out.println("p outofbounds " + p + "/" + safeguard);
|
|
}
|
|
}
|
|
if (found == null) {
|
|
if (!altpath.isEmpty()) {
|
|
// new possible backpath
|
|
backpath = altpath.removeFirst();
|
|
found = backpath.removeFirst();
|
|
if (rlistener != null) {
|
|
rlistener.notifySearchError("try alternate path " + found.toString());
|
|
rlistener.notifySearch(found);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (found == null) {
|
|
if (!altpath.isEmpty()) {
|
|
rlistener.notifySearchError("No path found BUT ALTPATH !");
|
|
}
|
|
rlistener.notifySearchError("No path found !");
|
|
break;
|
|
}
|
|
// System.out.println(found);
|
|
if (isFlagSet(getCell(found.getPosition()), SOLVED)) {
|
|
System.out.println("[INFO] position already solved" + found.toString() + " *length:" + backpath.size());
|
|
} else {
|
|
updateCell(found.getPosition(), SOLVED);
|
|
}
|
|
|
|
|
|
safeguard--;
|
|
if (safeguard < 0) {
|
|
rlistener.notifySearchError("Path too long ( or long overflow ) for width*height:" + (width * height) + " length:" + backpath.size());
|
|
break;
|
|
}
|
|
}
|
|
if (rlistener != null) {
|
|
rlistener.notifyCompletion(backpath);
|
|
}
|
|
return backpath;
|
|
}
|
|
|
|
}
|