add Save Text support and rework package
- move maze within package maze
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package org.artisanlogiciel.games.maze.solve;
|
||||
|
||||
import org.artisanlogiciel.games.maze.LabyModel;
|
||||
import org.artisanlogiciel.games.maze.Position;
|
||||
|
||||
/**
|
||||
* DirectionPosition
|
||||
* <p>
|
||||
* record direction and position ( direction as defined in LabyModel ).
|
||||
**/
|
||||
public class DirectionPosition {
|
||||
private short direction;
|
||||
private Position position;
|
||||
|
||||
// (direction,position)
|
||||
public DirectionPosition(short d, Position p) {
|
||||
direction = d;
|
||||
position = p;
|
||||
}
|
||||
|
||||
public short getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void setDirection(short d) {
|
||||
direction = d;
|
||||
}
|
||||
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (position != null) {
|
||||
return position.toString();
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
// create a new DirectionPosition from this using one possible direction.
|
||||
public DirectionPosition moveToAdjacentDirection() {
|
||||
short pointingdirection = 0;
|
||||
Position p = null;
|
||||
if (LabyModel.isFlagSet(direction, LabyModel.RIGHT)) {
|
||||
p = new Position(position.getX() + 1, position.getY());
|
||||
pointingdirection |= LabyModel.LEFT;
|
||||
} else if (LabyModel.isFlagSet(direction, LabyModel.LEFT)) {
|
||||
p = new Position(position.getX() - 1, position.getY());
|
||||
pointingdirection |= LabyModel.RIGHT;
|
||||
} else if (LabyModel.isFlagSet(direction, LabyModel.UP)) {
|
||||
p = new Position(position.getX(), position.getY() - 1);
|
||||
pointingdirection |= LabyModel.DOWN;
|
||||
} else if (LabyModel.isFlagSet(direction, LabyModel.DOWN)) {
|
||||
p = new Position(position.getX(), position.getY() + 1);
|
||||
pointingdirection |= LabyModel.UP;
|
||||
} else {
|
||||
p = position;
|
||||
}
|
||||
|
||||
return new DirectionPosition((short) pointingdirection, p);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.artisanlogiciel.games.maze.solve;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* MazeResolutionListener used as interface between resolver and (mostly) GUI
|
||||
**/
|
||||
public interface MazeResolutionListener
|
||||
{
|
||||
|
||||
boolean notifySearch(DirectionPosition pPosition);
|
||||
|
||||
void notifySearchError(String error);
|
||||
|
||||
void notifyCompletion(LinkedList<DirectionPosition> solvedPath);
|
||||
|
||||
}
|
||||
171
java/org/artisanlogiciel/games/maze/solve/SolvingModel.java
Normal file
171
java/org/artisanlogiciel/games/maze/solve/SolvingModel.java
Normal file
@@ -0,0 +1,171 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user