diff --git a/.idea/laby.iml b/.idea/laby.iml index 216b054..4b248d8 100644 --- a/.idea/laby.iml +++ b/.idea/laby.iml @@ -24,6 +24,6 @@ - + \ No newline at end of file diff --git a/.idea/libraries/artgaphics_0_2_0.xml b/.idea/libraries/artgaphics_0_2_0.xml new file mode 100644 index 0000000..6ed4394 --- /dev/null +++ b/.idea/libraries/artgaphics_0_2_0.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/org/artisanlogiciel/games/MazeParamsFixed.java b/java/org/artisanlogiciel/games/MazeParamsFixed.java deleted file mode 100644 index 6f9e505..0000000 --- a/java/org/artisanlogiciel/games/MazeParamsFixed.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.artisanlogiciel.games; - -import java.io.File; - -public class MazeParamsFixed implements MazeParams -{ - long seed; - int width; - int height; - int maxdepth; - File labdir; - String name; - - public MazeParamsFixed() - { - } - - public MazeParamsFixed(MazeParams params) - { - setParams(params.getSaveDir(),params.getWidth(),params.getHeight(),params.getMaxDepth()); - } - - public void setParams(File saveDir, int W, int H, int MD) - { - labdir = saveDir; - width=W; - height=H; - maxdepth=MD; - } - - public MazeParamsFixed(File saveDir, int W, int H, int MD, long seed) - { - name = null; - setParams(saveDir,W,H,MD); - this.seed=seed; - } - - public long getSeed() - { - return seed; - } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } - - public int getMaxDepth() - { - return maxdepth; - } - - public void setName(String n) - { - name = n; - } - - public String getName() - { - if (name == null) - { - name = "lab" + width + "x" + height; - } - return name; - } - - public File getSaveDir() - { - return labdir; - } -} diff --git a/java/org/artisanlogiciel/games/MazeResolutionListener.java b/java/org/artisanlogiciel/games/MazeResolutionListener.java deleted file mode 100644 index 9c12371..0000000 --- a/java/org/artisanlogiciel/games/MazeResolutionListener.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.artisanlogiciel.games; - -import java.util.LinkedList; - -/** - * MazeResolutionListener used as interface between resolver and (mostly) GUI - **/ -public interface MazeResolutionListener -{ - - public boolean notifySearch(DirectionPosition pPosition); - - public void notifySearchError(String error); - - public void notifyCompletion(LinkedList solvedPath); - -} diff --git a/java/org/artisanlogiciel/games/Brick.java b/java/org/artisanlogiciel/games/maze/Brick.java similarity index 91% rename from java/org/artisanlogiciel/games/Brick.java rename to java/org/artisanlogiciel/games/maze/Brick.java index 9b238a2..df980d1 100644 --- a/java/org/artisanlogiciel/games/Brick.java +++ b/java/org/artisanlogiciel/games/maze/Brick.java @@ -1,13 +1,19 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; /* - 2x2 Tile to represent a labyrinth position + +2x2 Tile to represent a labyrinth position with some walls + +this is 2x2 downright most part of 3x3 centered tile. + +center right +down downright ab cd a is 'H' or '.' or ' ' -bcd is 'H' or ' ' +bcd is within 'H' or ' ' */ public class Brick diff --git a/java/org/artisanlogiciel/games/LabyMap.java b/java/org/artisanlogiciel/games/maze/LabyMap.java similarity index 93% rename from java/org/artisanlogiciel/games/LabyMap.java rename to java/org/artisanlogiciel/games/maze/LabyMap.java index 324b779..26543d1 100644 --- a/java/org/artisanlogiciel/games/LabyMap.java +++ b/java/org/artisanlogiciel/games/maze/LabyMap.java @@ -1,12 +1,15 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; import java.util.LinkedList; -class LabyMap implements WallsProvider +/** + * model with Bricks, based on walls + */ +public class LabyMap implements WallsProvider { Brick[][] tileMap; - LinkedList exits = new LinkedList(); + LinkedList exits; public LabyMap(Brick[][] tileMap, LinkedList exits) { diff --git a/java/org/artisanlogiciel/games/LabyModel.java b/java/org/artisanlogiciel/games/maze/LabyModel.java similarity index 70% rename from java/org/artisanlogiciel/games/LabyModel.java rename to java/org/artisanlogiciel/games/maze/LabyModel.java index 56e22b9..0a08322 100644 --- a/java/org/artisanlogiciel/games/LabyModel.java +++ b/java/org/artisanlogiciel/games/maze/LabyModel.java @@ -1,6 +1,5 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; -import java.io.*; import java.util.ArrayList; import java.util.LinkedList; import java.util.Random; @@ -30,10 +29,6 @@ public class LabyModel implements WallsProvider { public final static short POSITIVE = 8; public final static short NEGATIVE = 16; - // can it be both OPEN and CLOSED ? - private final static short OPEN = 32; // can be reused once generation is - // completed - private final static short CLOSED = 64; // can be reused once generation is // completed public final static short LEFT = Brick.LEFT << FLAGLENGTH | DIRECTION | HORIZONTAL | NEGATIVE; public final static short DOWN = Brick.DOWN << FLAGLENGTH | DIRECTION | VERTICAL | POSITIVE; @@ -44,6 +39,11 @@ public class LabyModel implements WallsProvider { public final static short ENTRY = Brick.ENTRY << FLAGLENGTH; // flag when a wall should be open to access this for exit private final static short GOAL = Brick.GOAL << FLAGLENGTH; + + // can it be both OPEN and CLOSED ? + private final static short OPEN = 32; // can be reused once generation is + // completed + private final static short CLOSED = 64; // can be reused once generation is // flag when solution is on this path. public final static short SOLVED = 64 << FLAGLENGTH; // free flag @@ -51,7 +51,7 @@ public class LabyModel implements WallsProvider { // remains 2 free bits ( keep one out for sign ) // orders matters see getReverseDirection - private static final short[] AllDirections = {LEFT, DOWN, RIGHT, UP}; + public static final short[] AllDirections = {LEFT, DOWN, RIGHT, UP}; private int width; private int height; @@ -100,8 +100,18 @@ public class LabyModel implements WallsProvider { /** * construct LabyModel from an InputStream, yet only "raw" is supported **/ - public LabyModel(String pFormat, InputStream pIn) throws IOException { - parseInputStream(pFormat, pIn); + public LabyModel(int width, int heigh, short [][] t) { + random = null; + this.width = width; + this.height = height; + this.t = t; + } + + public LabyModel(LabyModel other ) { + random = null; + this.width = other.width; + this.height = other.height; + this.t = other.t; } public void setMazeListener(MazeCreationListener listener) { @@ -539,153 +549,6 @@ public class LabyModel implements WallsProvider { return pointingdirection; } - /** - * 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 resolve(int x, int y, MazeResolutionListener rlistener) { - 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; - } private final void closePosition(int x, int y) { t[x][y] &= ~OPEN; @@ -877,59 +740,13 @@ public class LabyModel implements WallsProvider { } } - public void streamOut(String pFormat, OutputStream pOut) throws IOException { - if ((pFormat == null) || (pFormat.equals("raw"))) { - // first raw format, not smart. - DataOutputStream dataOut = new DataOutputStream(pOut); - // should dump this to stream. - dataOut.write(new byte[]{(byte) 'L', (byte) 'A', (byte) 'B', (byte) '0'}); - dataOut.writeInt(getWidth()); - dataOut.writeInt(getHeight()); - dataOut.flush(); - for (int y = 0; y < getHeight(); y++) { - for (int x = 0; x < getWidth(); x++) { - dataOut.writeShort(t[x][y]); - } - } - dataOut.flush(); - } else { - throw new IOException("Format " + pFormat + " Not yet implemented."); - } - } - - private void streamIn(String pFormat, InputStream pIn) throws IOException { - throw new IOException("Use correct constructor."); - } - - private void parseInputStream(String pFormat, InputStream pIn) throws IOException { - if ((pFormat == null) || (pFormat.equals("raw"))) { - // maxdepth is unset then unmodified - byte[] header = new byte[4]; - DataInputStream in = new DataInputStream(pIn); - in.read(header); - int rwidth = in.readInt(); - int rheight = in.readInt(); - if ((rwidth > 0) && (rheight > 0)) { - width = rwidth; - height = rheight; - random = null; - // SHOULD CHECK max width and max height... - // CLEAR == 0 and array is initialized with 0s - t = new short[width][height]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - t[x][y] = in.readShort(); - } - } - } else { - throw new IOException("Invalid header for width and height"); - } - // should be at end of stream ? Not necessary can stream multiple - // labs ( or tiling ). - } else { - throw new IOException("Format " + pFormat + " Not yet implemented."); - } - + /** + * is there no wall in that direction ? + **/ + public boolean canMoveInDirection(int x, int y, short direction) { + // tried to replace by but does not work ( can't go back ...). + // return ! hasWallInDirection(x,y, (short) (direction << FLAGLENGTH)); + return ((getWalls(x, y) & direction ) == 0); } } diff --git a/java/org/artisanlogiciel/games/Main.java b/java/org/artisanlogiciel/games/maze/Main.java similarity index 55% rename from java/org/artisanlogiciel/games/Main.java rename to java/org/artisanlogiciel/games/maze/Main.java index 4b19244..ac9d70a 100644 --- a/java/org/artisanlogiciel/games/Main.java +++ b/java/org/artisanlogiciel/games/maze/Main.java @@ -1,33 +1,31 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; + +import org.artisanlogiciel.games.maze.solve.SolvingModel; import java.util.LinkedList; import java.util.Scanner; -public class Main -{ - public MazeParamEditor editor() - { - MazeParamEditor editor = new MazeParamEditor(null); - System.out.println("enter width height and maxdepth"); +public class Main { + public MazeParamEditor editor() { + MazeParamEditor editor = new MazeParamEditor(null); + System.out.println("enter width height and maxdepth"); Scanner console = new Scanner(System.in); - editor.read(console); - return editor; + editor.read(console); + return editor; } - public LabyMap generate2(MazeParamEditor params) - { + public LabyMap generate2(MazeParamEditor params) { params.setSeed(1024L); - LabyModel model = new LabyModel(params); + SolvingModel model = new SolvingModel(params); model.generateWithEntry(0, 0); - final int width = params.getWidth(); - final int height = params.getHeight(); + final int width = params.getWidth(); + final int height = params.getHeight(); LinkedList exits = new LinkedList(); model.addEntryOrExit(-1, 0); model.addEntryOrExit(width, height - 1); System.out.println(model.toLabyMap().toString()); - if (!model.check()) - { + if (!model.check()) { System.out.println("Check failed"); } model.debugOut(); @@ -36,10 +34,9 @@ public class Main return labyMap; } - public static void main(String pArgs[]) - { + public static void main(String pArgs[]) { Main m = new Main(); - MazeParamEditor editor = m.editor(); + MazeParamEditor editor = m.editor(); LabyMap map = m.generate2(editor); System.out.println(map.toShortString()); System.out.println(map.toString()); diff --git a/java/org/artisanlogiciel/games/MazeCreationListener.java b/java/org/artisanlogiciel/games/maze/MazeCreationListener.java similarity index 80% rename from java/org/artisanlogiciel/games/MazeCreationListener.java rename to java/org/artisanlogiciel/games/maze/MazeCreationListener.java index 633ecac..d4df454 100644 --- a/java/org/artisanlogiciel/games/MazeCreationListener.java +++ b/java/org/artisanlogiciel/games/maze/MazeCreationListener.java @@ -1,4 +1,4 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; /** * MazeCreationListener diff --git a/java/org/artisanlogiciel/games/MazeParamEditor.java b/java/org/artisanlogiciel/games/maze/MazeParamEditor.java similarity index 96% rename from java/org/artisanlogiciel/games/MazeParamEditor.java rename to java/org/artisanlogiciel/games/maze/MazeParamEditor.java index 003723b..35f6dc8 100644 --- a/java/org/artisanlogiciel/games/MazeParamEditor.java +++ b/java/org/artisanlogiciel/games/maze/MazeParamEditor.java @@ -1,4 +1,4 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; import java.io.File; import java.util.Scanner; diff --git a/java/org/artisanlogiciel/games/MazeParams.java b/java/org/artisanlogiciel/games/maze/MazeParams.java similarity index 92% rename from java/org/artisanlogiciel/games/MazeParams.java rename to java/org/artisanlogiciel/games/maze/MazeParams.java index e2020a8..e0ded6f 100644 --- a/java/org/artisanlogiciel/games/MazeParams.java +++ b/java/org/artisanlogiciel/games/maze/MazeParams.java @@ -1,4 +1,4 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; import java.io.File; diff --git a/java/org/artisanlogiciel/games/maze/MazeParamsFixed.java b/java/org/artisanlogiciel/games/maze/MazeParamsFixed.java new file mode 100644 index 0000000..6f8668e --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/MazeParamsFixed.java @@ -0,0 +1,63 @@ +package org.artisanlogiciel.games.maze; + +import java.io.File; + +public class MazeParamsFixed implements MazeParams { + long seed; + int width; + int height; + int maxdepth; + File labdir; + String name; + + public MazeParamsFixed() { + } + + public MazeParamsFixed(MazeParams params) { + setParams(params.getSaveDir(), params.getWidth(), params.getHeight(), params.getMaxDepth()); + } + + public void setParams(File saveDir, int W, int H, int MD) { + labdir = saveDir; + width = W; + height = H; + maxdepth = MD; + } + + public MazeParamsFixed(File saveDir, int W, int H, int MD, long seed) { + name = null; + setParams(saveDir, W, H, MD); + this.seed = seed; + } + + public long getSeed() { + return seed; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getMaxDepth() { + return maxdepth; + } + + public void setName(String n) { + name = n; + } + + public String getName() { + if (name == null) { + name = "lab" + width + "x" + height; + } + return name; + } + + public File getSaveDir() { + return labdir; + } +} diff --git a/java/org/artisanlogiciel/games/Position.java b/java/org/artisanlogiciel/games/maze/Position.java similarity index 95% rename from java/org/artisanlogiciel/games/Position.java rename to java/org/artisanlogiciel/games/maze/Position.java index da2a162..11d0801 100644 --- a/java/org/artisanlogiciel/games/Position.java +++ b/java/org/artisanlogiciel/games/maze/Position.java @@ -1,4 +1,4 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; /** position of a cell with maze */ public class Position diff --git a/java/org/artisanlogiciel/games/WallsProvider.java b/java/org/artisanlogiciel/games/maze/WallsProvider.java similarity index 67% rename from java/org/artisanlogiciel/games/WallsProvider.java rename to java/org/artisanlogiciel/games/maze/WallsProvider.java index 6c96c10..0159a74 100644 --- a/java/org/artisanlogiciel/games/WallsProvider.java +++ b/java/org/artisanlogiciel/games/maze/WallsProvider.java @@ -1,4 +1,4 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze; /** * WallsProvider provide a Walls representation @@ -18,8 +18,10 @@ public interface WallsProvider * (8)(4)(2)(1) * ^ > v < * U R D L - * p i o e g w f h n t - * t + * p i o e + * g w f + * h n t + * t **/ - public short getWalls(int x, int y); + short getWalls(int x, int y); } diff --git a/java/org/artisanlogiciel/games/maze/gui/Display.java b/java/org/artisanlogiciel/games/maze/gui/Display.java index 79893e5..a214b36 100644 --- a/java/org/artisanlogiciel/games/maze/gui/Display.java +++ b/java/org/artisanlogiciel/games/maze/gui/Display.java @@ -27,9 +27,12 @@ import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; -import org.artisanlogiciel.games.*; +import org.artisanlogiciel.games.maze.*; +import org.artisanlogiciel.games.maze.persist.MazePersistRaw; +import org.artisanlogiciel.games.maze.solve.DirectionPosition; +import org.artisanlogiciel.games.maze.solve.MazeResolutionListener; +import org.artisanlogiciel.games.maze.solve.SolvingModel; import org.artisanlogiciel.games.stl.Maze3dParams; -import org.artisanlogiciel.games.stl.Wall3d; import org.artisanlogiciel.games.stl.Wall3dStream; import org.artisanlogiciel.util.UTF8Control; @@ -143,8 +146,12 @@ public class Display extends JFrame { } void resolve() { + + SolvingModel solving = new SolvingModel(model); + // should transform current model to be a SolvingModel + model = solving; model.reset(); - model.resolve(model.getWidth() - 1, model.getHeight() - 1, maze); + solving.resolve(solving.getWidth() - 1, solving.getHeight() - 1, maze); } void goNorth() { @@ -311,6 +318,21 @@ public class Display extends JFrame { } } + void saveText() { + File outfile = getFileForExtension("txt"); + writeSentence("Saving to " + outfile + " ..."); + try { + DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile)); + out.write(model.toLabyMap().toString().getBytes()); + out.flush(); + out.close(); + writeSentence("... Done."); + } catch (IOException io) { + io.printStackTrace(System.err); + } + } + + void addStatus(String pStatus) { statusField.setText(pStatus); @@ -414,6 +436,16 @@ public class Display extends JFrame { } }; saveStlButton.addActionListener(saveStlAction); + final JButton saveTextButton = new JButton(labels.getString("save") + " txt"); + Action saveTextAction = new AbstractAction() { + public void actionPerformed(ActionEvent evt) { + // + addStatus("save txt"); + setMazeName(saveName.getText()); + saveText(); + } + }; + saveTextButton.addActionListener(saveTextAction); stlsettings = new Maze3dSettings(new Maze3dParams()); @@ -425,6 +457,7 @@ public class Display extends JFrame { saveMenu.add(stlsettings); saveMenu.add(saveStlButton); saveMenu.add(saveImcButton); + saveMenu.add(saveTextButton); return saveMenu; @@ -601,7 +634,7 @@ public class Display extends JFrame { FileInputStream inputStream = null; try { inputStream = new FileInputStream(infile); - model = new LabyModel("raw", inputStream); + model = new MazePersistRaw().parseInputStream("raw",inputStream); } catch (IOException io) { io.printStackTrace(System.err); statusField.setText("[ERROR] Can't load " + infile.getAbsolutePath()); @@ -851,55 +884,43 @@ public class Display extends JFrame { } } + private void proceed() + { + // should redraw ... + invalidate(); + repaint(); + checkExit(); + } void goNorth() { resetResolution(); - if ((map.getWalls(sX, sY) & Brick.UP) == 0) { + if (map.canMoveInDirection(sX, sY,Brick.UP)) { sY = sY - 1; - // should redraw ... - invalidate(); - repaint(); - - checkExit(); + proceed(); } - } void goSouth() { resetResolution(); - if ((map.getWalls(sX, sY) & Brick.DOWN) == 0) { + if (map.canMoveInDirection(sX, sY,Brick.DOWN)) { sY = sY + 1; - // should redraw ... - invalidate(); - repaint(); - - checkExit(); + proceed(); } - } void goEast() { resetResolution(); - if ((map.getWalls(sX, sY) & Brick.RIGHT) == 0) { + if (map.canMoveInDirection(sX, sY, Brick.RIGHT)) { sX = sX + 1; - // should redraw ... - invalidate(); - repaint(); - - checkExit(); + proceed(); } } void goWest() { resetResolution(); - if ((map.getWalls(sX, sY) & Brick.LEFT) == 0) { + if (map.canMoveInDirection(sX, sY, Brick.LEFT)) { sX = sX - 1; - // should redraw ... - invalidate(); - repaint(); - - checkExit(); + proceed(); } - } /** @@ -1113,7 +1134,8 @@ public class Display extends JFrame { addStatus("Saving to " + outfile + " ..."); try { FileOutputStream out = new FileOutputStream(outfile); - model.streamOut("raw", out); + MazePersistRaw persist = new MazePersistRaw(model); + persist.streamOut("raw", out); out.flush(); out.close(); addStatus("... Done."); @@ -1135,7 +1157,7 @@ public class Display extends JFrame { if ((pArgs.length > 0) && (pArgs[0].length() > 0)) { try { - model = new LabyModel("raw", new FileInputStream(pArgs[0])); + model = new MazePersistRaw().parseInputStream("raw",new FileInputStream(pArgs[0])); } catch (IOException io) { io.printStackTrace(System.err); System.exit(1); diff --git a/java/org/artisanlogiciel/games/maze/gui/Maze3dSettings.java b/java/org/artisanlogiciel/games/maze/gui/Maze3dSettings.java index 601e396..c8c595d 100644 --- a/java/org/artisanlogiciel/games/maze/gui/Maze3dSettings.java +++ b/java/org/artisanlogiciel/games/maze/gui/Maze3dSettings.java @@ -1,8 +1,6 @@ package org.artisanlogiciel.games.maze.gui; -import org.artisanlogiciel.games.MazeParams; import org.artisanlogiciel.games.stl.Maze3dParams; -import org.artisanlogiciel.games.stl.Wall3d; import javax.swing.*; diff --git a/java/org/artisanlogiciel/games/maze/gui/MazeSettings.java b/java/org/artisanlogiciel/games/maze/gui/MazeSettings.java index f7e4a4e..421c9bb 100644 --- a/java/org/artisanlogiciel/games/maze/gui/MazeSettings.java +++ b/java/org/artisanlogiciel/games/maze/gui/MazeSettings.java @@ -1,7 +1,7 @@ package org.artisanlogiciel.games.maze.gui; -import org.artisanlogiciel.games.MazeParams; -import org.artisanlogiciel.games.MazeParamsFixed; +import org.artisanlogiciel.games.maze.MazeParams; +import org.artisanlogiciel.games.maze.MazeParamsFixed; import javax.swing.*; import javax.swing.event.ChangeEvent; diff --git a/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java b/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java new file mode 100644 index 0000000..eef055f --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java @@ -0,0 +1,75 @@ +package org.artisanlogiciel.games.maze.persist; + +import org.artisanlogiciel.games.maze.LabyModel; + +import java.io.*; + +public class MazePersistRaw +{ + private LabyModel model; + + public MazePersistRaw(LabyModel model) + { + this.model = model; + } + + public MazePersistRaw() + { + this.model = model; + } + + + public void streamOut(String pFormat, OutputStream pOut) throws IOException { + if ((pFormat == null) || (pFormat.equals("raw"))) { + // first raw format, not smart. + DataOutputStream dataOut = new DataOutputStream(pOut); + // should dump this to stream. + dataOut.write(new byte[]{(byte) 'L', (byte) 'A', (byte) 'B', (byte) '0'}); + dataOut.writeInt(model.getWidth()); + dataOut.writeInt(model.getHeight()); + dataOut.flush(); + for (int y = 0; y < model.getHeight(); y++) { + for (int x = 0; x < model.getWidth(); x++) { + dataOut.writeShort(model.getPath(x,y)); + } + } + dataOut.flush(); + } else { + throw new IOException("Format " + pFormat + " Not yet implemented."); + } + } + + + public LabyModel parseInputStream(String pFormat, InputStream pIn) throws IOException { + if ((pFormat == null) || (pFormat.equals("raw"))) { + // maxdepth is unset then unmodified + byte[] header = new byte[4]; + DataInputStream in = new DataInputStream(pIn); + in.read(header); + int rwidth = in.readInt(); + int rheight = in.readInt(); + if ((rwidth > 0) && (rheight > 0)) { + int width = rwidth; + int height = rheight; + // SHOULD CHECK max width and max height... + // CLEAR == 0 and array is initialized with 0s + short[][] t = new short[width][height]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + t[x][y] = in.readShort(); + } + } + model= new LabyModel(width, height, t); + return model; + } else { + throw new IOException("Invalid header for width and height"); + } + // should be at end of stream ? Not necessary can stream multiple + // labs ( or tiling ). + } else { + throw new IOException("Format " + pFormat + " Not yet implemented."); + } + + } + +} diff --git a/java/org/artisanlogiciel/games/DirectionPosition.java b/java/org/artisanlogiciel/games/maze/solve/DirectionPosition.java similarity index 92% rename from java/org/artisanlogiciel/games/DirectionPosition.java rename to java/org/artisanlogiciel/games/maze/solve/DirectionPosition.java index f11f88a..6be3447 100644 --- a/java/org/artisanlogiciel/games/DirectionPosition.java +++ b/java/org/artisanlogiciel/games/maze/solve/DirectionPosition.java @@ -1,4 +1,7 @@ -package org.artisanlogiciel.games; +package org.artisanlogiciel.games.maze.solve; + +import org.artisanlogiciel.games.maze.LabyModel; +import org.artisanlogiciel.games.maze.Position; /** * DirectionPosition diff --git a/java/org/artisanlogiciel/games/maze/solve/MazeResolutionListener.java b/java/org/artisanlogiciel/games/maze/solve/MazeResolutionListener.java new file mode 100644 index 0000000..80abad4 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/solve/MazeResolutionListener.java @@ -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 solvedPath); + +} diff --git a/java/org/artisanlogiciel/games/maze/solve/SolvingModel.java b/java/org/artisanlogiciel/games/maze/solve/SolvingModel.java new file mode 100644 index 0000000..765e1f2 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/solve/SolvingModel.java @@ -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 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; + } + +} diff --git a/java/org/artisanlogiciel/games/stl/Wall3d.java b/java/org/artisanlogiciel/games/stl/Wall3d.java index 7f77f3d..aadbb21 100644 --- a/java/org/artisanlogiciel/games/stl/Wall3d.java +++ b/java/org/artisanlogiciel/games/stl/Wall3d.java @@ -1,14 +1,5 @@ package org.artisanlogiciel.games.stl; -import java.util.Scanner; - -import org.artisanlogiciel.games.Brick; -import org.artisanlogiciel.games.LabyModel; -import org.artisanlogiciel.games.WallsProvider; - -import java.io.OutputStream; -import java.io.IOException; - /** * Wall3d to create walls in 3d for stl conversion South, West North East... * diff --git a/java/org/artisanlogiciel/games/stl/Wall3dStream.java b/java/org/artisanlogiciel/games/stl/Wall3dStream.java index f2ed4d6..0e2df1a 100644 --- a/java/org/artisanlogiciel/games/stl/Wall3dStream.java +++ b/java/org/artisanlogiciel/games/stl/Wall3dStream.java @@ -1,7 +1,7 @@ package org.artisanlogiciel.games.stl; -import org.artisanlogiciel.games.Brick; -import org.artisanlogiciel.games.LabyModel; +import org.artisanlogiciel.games.maze.Brick; +import org.artisanlogiciel.games.maze.LabyModel; import java.io.IOException; import java.io.OutputStream;