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 labyrinth using internal representation * initial (x,y) is exit, will return list of positions from start (0,0) to end (x,y) **/ public LinkedList 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> altpath = new LinkedList<>(); // list of positions from start to end LinkedList backpath = new LinkedList(); // 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 cp = new LinkedList(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; } }