add Save Text support and rework package

- move maze within package maze
This commit is contained in:
philippe lhardy
2020-10-17 21:08:16 +02:00
parent c3410838e1
commit c69d068caf
24 changed files with 590 additions and 385 deletions

2
.idea/laby.iml generated
View File

@@ -24,6 +24,6 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="artgaphics-0.1.0" level="project" /> <orderEntry type="library" name="artgaphics-0.2.0" level="project" />
</component> </component>
</module> </module>

9
.idea/libraries/artgaphics_0_2_0.xml generated Normal file
View File

@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="artgaphics-0.2.0">
<CLASSES>
<root url="jar://$PROJECT_DIR$/libs/artgaphics-0.2.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

124
.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

View File

@@ -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;
}
}

View File

@@ -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<DirectionPosition> solvedPath);
}

View File

@@ -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 ab
cd cd
a is 'H' or '.' or ' ' a is 'H' or '.' or ' '
bcd is 'H' or ' ' bcd is within 'H' or ' '
*/ */
public class Brick public class Brick

View File

@@ -1,12 +1,15 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
import java.util.LinkedList; import java.util.LinkedList;
class LabyMap implements WallsProvider /**
* model with Bricks, based on walls
*/
public class LabyMap implements WallsProvider
{ {
Brick[][] tileMap; Brick[][] tileMap;
LinkedList<Position> exits = new LinkedList<Position>(); LinkedList<Position> exits;
public LabyMap(Brick[][] tileMap, LinkedList<Position> exits) public LabyMap(Brick[][] tileMap, LinkedList<Position> exits)
{ {

View File

@@ -1,6 +1,5 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Random; import java.util.Random;
@@ -30,10 +29,6 @@ public class LabyModel implements WallsProvider {
public final static short POSITIVE = 8; public final static short POSITIVE = 8;
public final static short NEGATIVE = 16; 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 // completed
public final static short LEFT = Brick.LEFT << FLAGLENGTH | DIRECTION | HORIZONTAL | NEGATIVE; public final static short LEFT = Brick.LEFT << FLAGLENGTH | DIRECTION | HORIZONTAL | NEGATIVE;
public final static short DOWN = Brick.DOWN << FLAGLENGTH | DIRECTION | VERTICAL | POSITIVE; 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; public final static short ENTRY = Brick.ENTRY << FLAGLENGTH;
// flag when a wall should be open to access this for exit // flag when a wall should be open to access this for exit
private final static short GOAL = Brick.GOAL << FLAGLENGTH; 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. // flag when solution is on this path.
public final static short SOLVED = 64 << FLAGLENGTH; public final static short SOLVED = 64 << FLAGLENGTH;
// free flag // free flag
@@ -51,7 +51,7 @@ public class LabyModel implements WallsProvider {
// remains 2 free bits ( keep one out for sign ) // remains 2 free bits ( keep one out for sign )
// orders matters see getReverseDirection // 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 width;
private int height; private int height;
@@ -100,8 +100,18 @@ public class LabyModel implements WallsProvider {
/** /**
* construct LabyModel from an InputStream, yet only "raw" is supported * construct LabyModel from an InputStream, yet only "raw" is supported
**/ **/
public LabyModel(String pFormat, InputStream pIn) throws IOException { public LabyModel(int width, int heigh, short [][] t) {
parseInputStream(pFormat, pIn); 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) { public void setMazeListener(MazeCreationListener listener) {
@@ -539,153 +549,6 @@ public class LabyModel implements WallsProvider {
return pointingdirection; 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<DirectionPosition> resolve(int x, int y, MazeResolutionListener rlistener) {
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;
}
private final void closePosition(int x, int y) { private final void closePosition(int x, int y) {
t[x][y] &= ~OPEN; 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"))) { * is there no wall in that direction ?
// first raw format, not smart. **/
DataOutputStream dataOut = new DataOutputStream(pOut); public boolean canMoveInDirection(int x, int y, short direction) {
// should dump this to stream. // tried to replace by but does not work ( can't go back ...).
dataOut.write(new byte[]{(byte) 'L', (byte) 'A', (byte) 'B', (byte) '0'}); // return ! hasWallInDirection(x,y, (short) (direction << FLAGLENGTH));
dataOut.writeInt(getWidth()); return ((getWalls(x, y) & direction ) == 0);
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.");
}
} }
} }

View File

@@ -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.LinkedList;
import java.util.Scanner; import java.util.Scanner;
public class Main public class Main {
{ public MazeParamEditor editor() {
public MazeParamEditor editor() MazeParamEditor editor = new MazeParamEditor(null);
{ System.out.println("enter width height and maxdepth");
MazeParamEditor editor = new MazeParamEditor(null);
System.out.println("enter width height and maxdepth");
Scanner console = new Scanner(System.in); Scanner console = new Scanner(System.in);
editor.read(console); editor.read(console);
return editor; return editor;
} }
public LabyMap generate2(MazeParamEditor params) public LabyMap generate2(MazeParamEditor params) {
{
params.setSeed(1024L); params.setSeed(1024L);
LabyModel model = new LabyModel(params); SolvingModel model = new SolvingModel(params);
model.generateWithEntry(0, 0); model.generateWithEntry(0, 0);
final int width = params.getWidth(); final int width = params.getWidth();
final int height = params.getHeight(); final int height = params.getHeight();
LinkedList<Position> exits = new LinkedList<Position>(); LinkedList<Position> exits = new LinkedList<Position>();
model.addEntryOrExit(-1, 0); model.addEntryOrExit(-1, 0);
model.addEntryOrExit(width, height - 1); model.addEntryOrExit(width, height - 1);
System.out.println(model.toLabyMap().toString()); System.out.println(model.toLabyMap().toString());
if (!model.check()) if (!model.check()) {
{
System.out.println("Check failed"); System.out.println("Check failed");
} }
model.debugOut(); model.debugOut();
@@ -36,10 +34,9 @@ public class Main
return labyMap; return labyMap;
} }
public static void main(String pArgs[]) public static void main(String pArgs[]) {
{
Main m = new Main(); Main m = new Main();
MazeParamEditor editor = m.editor(); MazeParamEditor editor = m.editor();
LabyMap map = m.generate2(editor); LabyMap map = m.generate2(editor);
System.out.println(map.toShortString()); System.out.println(map.toShortString());
System.out.println(map.toString()); System.out.println(map.toString());

View File

@@ -1,4 +1,4 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
/** /**
* MazeCreationListener * MazeCreationListener

View File

@@ -1,4 +1,4 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
import java.io.File; import java.io.File;
import java.util.Scanner; import java.util.Scanner;

View File

@@ -1,4 +1,4 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
import java.io.File; import java.io.File;

View File

@@ -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;
}
}

View File

@@ -1,4 +1,4 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
/** position of a cell with maze */ /** position of a cell with maze */
public class Position public class Position

View File

@@ -1,4 +1,4 @@
package org.artisanlogiciel.games; package org.artisanlogiciel.games.maze;
/** /**
* WallsProvider provide a Walls representation * WallsProvider provide a Walls representation
@@ -18,8 +18,10 @@ public interface WallsProvider
* (8)(4)(2)(1) * (8)(4)(2)(1)
* ^ > v < * ^ > v <
* U R D L * U R D L
* p i o e g w f h n t * p i o e
* t * g w f
* h n t
* t
**/ **/
public short getWalls(int x, int y); short getWalls(int x, int y);
} }

View File

@@ -27,9 +27,12 @@ import javax.swing.*;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; 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.Maze3dParams;
import org.artisanlogiciel.games.stl.Wall3d;
import org.artisanlogiciel.games.stl.Wall3dStream; import org.artisanlogiciel.games.stl.Wall3dStream;
import org.artisanlogiciel.util.UTF8Control; import org.artisanlogiciel.util.UTF8Control;
@@ -143,8 +146,12 @@ public class Display extends JFrame {
} }
void resolve() { void resolve() {
SolvingModel solving = new SolvingModel(model);
// should transform current model to be a SolvingModel
model = solving;
model.reset(); model.reset();
model.resolve(model.getWidth() - 1, model.getHeight() - 1, maze); solving.resolve(solving.getWidth() - 1, solving.getHeight() - 1, maze);
} }
void goNorth() { 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) void addStatus(String pStatus)
{ {
statusField.setText(pStatus); statusField.setText(pStatus);
@@ -414,6 +436,16 @@ public class Display extends JFrame {
} }
}; };
saveStlButton.addActionListener(saveStlAction); 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()); stlsettings = new Maze3dSettings(new Maze3dParams());
@@ -425,6 +457,7 @@ public class Display extends JFrame {
saveMenu.add(stlsettings); saveMenu.add(stlsettings);
saveMenu.add(saveStlButton); saveMenu.add(saveStlButton);
saveMenu.add(saveImcButton); saveMenu.add(saveImcButton);
saveMenu.add(saveTextButton);
return saveMenu; return saveMenu;
@@ -601,7 +634,7 @@ public class Display extends JFrame {
FileInputStream inputStream = null; FileInputStream inputStream = null;
try { try {
inputStream = new FileInputStream(infile); inputStream = new FileInputStream(infile);
model = new LabyModel("raw", inputStream); model = new MazePersistRaw().parseInputStream("raw",inputStream);
} catch (IOException io) { } catch (IOException io) {
io.printStackTrace(System.err); io.printStackTrace(System.err);
statusField.setText("[ERROR] Can't load " + infile.getAbsolutePath()); 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() { void goNorth() {
resetResolution(); resetResolution();
if ((map.getWalls(sX, sY) & Brick.UP) == 0) { if (map.canMoveInDirection(sX, sY,Brick.UP)) {
sY = sY - 1; sY = sY - 1;
// should redraw ... proceed();
invalidate();
repaint();
checkExit();
} }
} }
void goSouth() { void goSouth() {
resetResolution(); resetResolution();
if ((map.getWalls(sX, sY) & Brick.DOWN) == 0) { if (map.canMoveInDirection(sX, sY,Brick.DOWN)) {
sY = sY + 1; sY = sY + 1;
// should redraw ... proceed();
invalidate();
repaint();
checkExit();
} }
} }
void goEast() { void goEast() {
resetResolution(); resetResolution();
if ((map.getWalls(sX, sY) & Brick.RIGHT) == 0) { if (map.canMoveInDirection(sX, sY, Brick.RIGHT)) {
sX = sX + 1; sX = sX + 1;
// should redraw ... proceed();
invalidate();
repaint();
checkExit();
} }
} }
void goWest() { void goWest() {
resetResolution(); resetResolution();
if ((map.getWalls(sX, sY) & Brick.LEFT) == 0) { if (map.canMoveInDirection(sX, sY, Brick.LEFT)) {
sX = sX - 1; sX = sX - 1;
// should redraw ... proceed();
invalidate();
repaint();
checkExit();
} }
} }
/** /**
@@ -1113,7 +1134,8 @@ public class Display extends JFrame {
addStatus("Saving to " + outfile + " ..."); addStatus("Saving to " + outfile + " ...");
try { try {
FileOutputStream out = new FileOutputStream(outfile); FileOutputStream out = new FileOutputStream(outfile);
model.streamOut("raw", out); MazePersistRaw persist = new MazePersistRaw(model);
persist.streamOut("raw", out);
out.flush(); out.flush();
out.close(); out.close();
addStatus("... Done."); addStatus("... Done.");
@@ -1135,7 +1157,7 @@ public class Display extends JFrame {
if ((pArgs.length > 0) && (pArgs[0].length() > 0)) { if ((pArgs.length > 0) && (pArgs[0].length() > 0)) {
try { try {
model = new LabyModel("raw", new FileInputStream(pArgs[0])); model = new MazePersistRaw().parseInputStream("raw",new FileInputStream(pArgs[0]));
} catch (IOException io) { } catch (IOException io) {
io.printStackTrace(System.err); io.printStackTrace(System.err);
System.exit(1); System.exit(1);

View File

@@ -1,8 +1,6 @@
package org.artisanlogiciel.games.maze.gui; package org.artisanlogiciel.games.maze.gui;
import org.artisanlogiciel.games.MazeParams;
import org.artisanlogiciel.games.stl.Maze3dParams; import org.artisanlogiciel.games.stl.Maze3dParams;
import org.artisanlogiciel.games.stl.Wall3d;
import javax.swing.*; import javax.swing.*;

View File

@@ -1,7 +1,7 @@
package org.artisanlogiciel.games.maze.gui; package org.artisanlogiciel.games.maze.gui;
import org.artisanlogiciel.games.MazeParams; import org.artisanlogiciel.games.maze.MazeParams;
import org.artisanlogiciel.games.MazeParamsFixed; import org.artisanlogiciel.games.maze.MazeParamsFixed;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;

View File

@@ -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.");
}
}
}

View File

@@ -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 * DirectionPosition

View File

@@ -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);
}

View 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;
}
}

View File

@@ -1,14 +1,5 @@
package org.artisanlogiciel.games.stl; 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... * Wall3d to create walls in 3d for stl conversion South, West North East...
* *

View File

@@ -1,7 +1,7 @@
package org.artisanlogiciel.games.stl; package org.artisanlogiciel.games.stl;
import org.artisanlogiciel.games.Brick; import org.artisanlogiciel.games.maze.Brick;
import org.artisanlogiciel.games.LabyModel; import org.artisanlogiciel.games.maze.LabyModel;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;