diff --git a/java/org/artisanlogiciel/games/maze/Brick.java b/java/org/artisanlogiciel/games/maze/Brick.java index f7c47b0..abdfbea 100644 --- a/java/org/artisanlogiciel/games/maze/Brick.java +++ b/java/org/artisanlogiciel/games/maze/Brick.java @@ -26,10 +26,12 @@ public class Brick public final static short ENTRY = 16; public final static short GOAL = 32; + // TODO get rid of those chars char a; char b; char c; char d; + short walls; // according to LabyModel.getWalls(); protected Brick() @@ -46,6 +48,11 @@ public class Brick this.walls = walls; } + public static boolean isFlagSet(short flags, short wall) + { + return ( flags & wall ) == flags; + } + public String getUpString() { return "" + a + b; diff --git a/java/org/artisanlogiciel/games/maze/BrickTextMapping.java b/java/org/artisanlogiciel/games/maze/BrickTextMapping.java index c70b9b4..4394450 100644 --- a/java/org/artisanlogiciel/games/maze/BrickTextMapping.java +++ b/java/org/artisanlogiciel/games/maze/BrickTextMapping.java @@ -1,9 +1,17 @@ package org.artisanlogiciel.games.maze; -public class BrickTextMapping -extends Brick { +import static org.artisanlogiciel.games.maze.Brick.*; - public static String getDirLine() +public class BrickTextMapping { + + private String charmap; + + public BrickTextMapping(String pCharMap) + { + charmap = pCharMap; + } + + public static String getDefaultDirLine() { char dir[] = new char[16]; String s = ""; @@ -43,18 +51,22 @@ extends Brick { } - public static char getChar(short walls) + public static char getDefaultChar(short walls) { // return getDirLine().charAt(walls & 0xFFF0); - return getDirLine().charAt(walls); + return getDefaultDirLine().charAt(walls); } - public static char getChar(Brick brick) + public static char getDefaultChar(Brick brick) { // return getDirLine().charAt(walls & 0xFFF0); - return getChar(brick.walls); + return getDefaultChar(brick.walls); } + public char getChar(Brick brick) + { + return charmap.charAt((brick.walls)*0xf); + } } diff --git a/java/org/artisanlogiciel/games/maze/LabyMap.java b/java/org/artisanlogiciel/games/maze/LabyMap.java index ad40826..74d5a0e 100644 --- a/java/org/artisanlogiciel/games/maze/LabyMap.java +++ b/java/org/artisanlogiciel/games/maze/LabyMap.java @@ -111,7 +111,7 @@ public class LabyMap implements WallsProvider { for (int x = 0; x < tileMap.length; x++) { - laby += "" + BrickTextMapping.getChar(tileMap[x][y]); + laby += "" + BrickTextMapping.getDefaultChar(tileMap[x][y]); } laby += "\n"; } diff --git a/java/org/artisanlogiciel/games/maze/LabyModel.java b/java/org/artisanlogiciel/games/maze/LabyModel.java index 698fe32..c372977 100644 --- a/java/org/artisanlogiciel/games/maze/LabyModel.java +++ b/java/org/artisanlogiciel/games/maze/LabyModel.java @@ -170,8 +170,14 @@ lues, they are used as it is for } } - public void out4XY(int x, int y) { - int direction = t[x][y]; + + public void out4XY(int x, int y) + { + out4XY(x,y,t[x][y],(x < width -1) ?t[x+1][y] : 0); + } + + public void out4XY(int x, int y, short txy, short txpy) { + int direction = txy; if ((direction & OPEN) == OPEN) { System.out.print("?"); } else if ((direction & CLOSED) == CLOSED) { @@ -251,7 +257,7 @@ lues, they are used as it is for System.out.print(".."); } - if (((t[x][y] & RIGHT) == RIGHT) || ((x + 1 < width) && ((t[x + 1][y] & LEFT) == LEFT))) { + if (((txy & RIGHT) == RIGHT) || ((x + 1 < width) && (txpy & LEFT) == LEFT)) { System.out.print("-"); } else { System.out.print("H"); @@ -260,8 +266,12 @@ lues, they are used as it is for } public String outHorizWall2XY(int x, int y) { + return outHorizWall2XY(x,y,t[x][y],(y width)) { @@ -271,23 +281,28 @@ lues, they are used as it is for return "HH"; } - if (((t[x][y] & DOWN) == DOWN) || ((y + 1 < height) && ((t[x][y + 1] & UP) == UP))) { + if (((txy & DOWN) == DOWN) || ((y + 1 < height) && ((txyp & UP) == UP))) { return freeway + "H"; } else { return "HH"; } } - public String out2XY(int x, int y) { + public String out2XY(int x, int y) + { + return out2XY(x,y,t[x][y],(x < width -1) ?t[x+1][y] : 0, width, height); + } + + public static String out2XY(int x, int y, short txy, short txpy, int width, int height) { // can check for entry exits. if ((y < 0) || (y >= height) || (x < 0) || (x > width)) { return " H"; } String low = ""; - int direction = t[x][y]; + int direction = txy; String freeway = " "; - if ((t[x][y] & SOLVED) == SOLVED) { + if ((txy & SOLVED) == SOLVED) { freeway = "*"; } // don't display information about short. @@ -337,14 +352,16 @@ lues, they are used as it is for low = "."; } + /* don't display entry or exits for (Position exit : entryExits) { if ((exit.getX() == x + 1) && (exit.getY() == y)) { low = low + ">"; return low; } } + */ - if (((t[x][y] & RIGHT) == RIGHT) || ((x + 1 < width) && ((t[x + 1][y] & LEFT) == LEFT))) { + if (((txy & RIGHT) == RIGHT) || ((x + 1 < width) && ((txpy & LEFT) == LEFT))) { low = low + freeway; } else { low = low + "H"; diff --git a/java/org/artisanlogiciel/games/maze/Maze.java b/java/org/artisanlogiciel/games/maze/Maze.java index 35cdef9..e7f1a67 100644 --- a/java/org/artisanlogiciel/games/maze/Maze.java +++ b/java/org/artisanlogiciel/games/maze/Maze.java @@ -1,5 +1,8 @@ package org.artisanlogiciel.games.maze; +import org.artisanlogiciel.games.maze.model.HalfSquareModelCreator; +import org.artisanlogiciel.games.maze.model.HalfSquareRasterModel; +import org.artisanlogiciel.games.maze.persist.HalfSquareRasterModelPersistRaw; import org.artisanlogiciel.games.maze.persist.MazePersistRaw; import org.artisanlogiciel.games.maze.persist.MazePersistWorldEdit; import org.artisanlogiciel.games.stl.Maze3dParams; @@ -176,7 +179,6 @@ public class Maze { } } - public void saveText() { File outfile = getFileForExtension("txt"); writeSentence("Saving to " + outfile + " ..."); @@ -191,6 +193,24 @@ public class Maze { } } + public void saveHalfSquerRaw() { + String extension = "sraw"; + File outfile = getFileForExtension(extension); + writeSentence("Saving to " + outfile + " ..."); + try { + // TODO + HalfSquareRasterModelPersistRaw persistRaw = new HalfSquareRasterModelPersistRaw(new HalfSquareModelCreator().createFromMovesProvider(model)); + DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile)); + persistRaw.streamOut(extension,out); + out.write(model.toLabyMap().toString().getBytes()); + out.flush(); + out.close(); + writeSentence("... Done."); + } catch (IOException io) { + io.printStackTrace(System.err); + } + } + protected void setModel( LabyModel model) { this.model = model; diff --git a/java/org/artisanlogiciel/games/maze/gui/Display.java b/java/org/artisanlogiciel/games/maze/gui/Display.java index c9d0276..c15d745 100644 --- a/java/org/artisanlogiciel/games/maze/gui/Display.java +++ b/java/org/artisanlogiciel/games/maze/gui/Display.java @@ -50,6 +50,7 @@ implements StatusListener boolean statusEnable = true; boolean mGrow = false; + boolean mHexagon = false; JTextField statusField = null; @@ -101,7 +102,8 @@ implements StatusListener } private MazeComponent createMazeComponent(LabyModel model, int W, int H) { - MazeCellParameters cp = new MazeCellParameters(model.getWidth(), model.getHeight(), W, H, 0, 0); + + MazeCellParameters cp = mHexagon ? new HexagonCell(model.getWidth(), model.getHeight(), W, H, 0, 0) : new MazeCellParameters(model.getWidth(), model.getHeight(), W, H, 0, 0); MazeComponent comp = new MazeComponent(model, cp, this); Xpm xpm = new Xpm(); try { diff --git a/java/org/artisanlogiciel/games/maze/gui/HexagonCell.java b/java/org/artisanlogiciel/games/maze/gui/HexagonCell.java new file mode 100644 index 0000000..c1e6c8d --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/gui/HexagonCell.java @@ -0,0 +1,90 @@ +package org.artisanlogiciel.games.maze.gui; + +import org.artisanlogiciel.games.maze.Brick; + +import java.awt.*; + +/** + * draw cell as an hexagon + * using a square model ( LEFT UP only). + */ + +public class HexagonCell +extends MazeCellParameters +{ + public final static int SUBCELL = 4; + + public HexagonCell(int mapw, int maph, int W, int H, int x, int y) { + super(mapw, maph, W, H, x, y); + } + + void drawLine(Graphics g, int refx, int refy, int x, int y, int a, int b) { + g.drawLine( + (int) ((refx + x) * getWidth() / SUBCELL), (int) ((refy + y) * getHeight() / SUBCELL), + (int) ((refx + a) * getWidth() / SUBCELL),(int) ((refy + b) * getHeight() / SUBCELL)); + } + + @Override + public void drawBackground(Graphics g, int pX, int pY, short walls) { + UV uv= new UV(pX,pY); + int x = offsetX + (int) (uv.getX() * width / SUBCELL); + int y = offsetY + (int) (uv.getY() * height / SUBCELL); + Color savecolor = g.getColor(); + int greylevel = walls << 2; + g.setColor(getGreyedColor(savecolor,greylevel)); + //g.fillRect(x+1,y+1,((int)width) -1,((int)height) - 1); + g.fillRect(x,y,((int)width),((int)height)); + } + + class UV + { + int u; + int v; + + UV(int u, int v) + { + this.u=u; + this.v=v; + } + + int getX() + { + return u*4 + 2*(v%2); + } + + int getY() + { + return 3*v; + } + + } + + @Override + public void drawWalls(Graphics g, int pX, int pY, short walls) { + drawHalfNW(g, pX, pY, walls); + } + + void drawHalfNW(Graphics g, int refx, int refy, short walls) + { + UV uv= new UV(refx,refy); + int x = uv.getX(); + int y = uv.getY(); + // NW : (0,1) - (2,0) + if (Brick.isFlagSet( Brick.UP, walls)) + drawLine(g,x, y, 0,1,2,0); + // W : (0,1) - (0,3) + if (Brick.isFlagSet( Brick.LEFT, walls)) + drawLine(g,x,y,0,1,0,3); + // NE : (2,0) - (4,1) + // if (Brick.isFlagSet( Brick.NE, walls)) + drawLine(g,x,y,2,0,4,1); + } + + void drawHalfSW(Graphics g) + { + // SW : (0,3) - (2,4) + // SE : (2,4) - (4,3) + // E : (4,3) - (4,1) + } + +} diff --git a/java/org/artisanlogiciel/games/maze/gui/MazeCellParameters.java b/java/org/artisanlogiciel/games/maze/gui/MazeCellParameters.java index 49a8cfd..c863e6c 100644 --- a/java/org/artisanlogiciel/games/maze/gui/MazeCellParameters.java +++ b/java/org/artisanlogiciel/games/maze/gui/MazeCellParameters.java @@ -94,13 +94,13 @@ public class MazeCellParameters { public void drawWalls(Graphics g, int pX, int pY, short walls) { int x = offsetX + (int) (pX * width); int y = offsetY + (int) (pY * height); - if ((pY == 0) && ((walls & Brick.UP) == Brick.UP)) + if ((pY == 0) && ( Brick.isFlagSet( Brick.UP, walls))) g.drawLine(x, y, x + (int) width, y); - if ((walls & Brick.DOWN) == Brick.DOWN) + if (Brick.isFlagSet( Brick.DOWN, walls)) g.drawLine(x, y + (int) height, x + (int) width, y + (int) height); - if ((walls & Brick.RIGHT) == Brick.RIGHT) + if (Brick.isFlagSet( Brick.RIGHT, walls)) g.drawLine(x + (int) width, y, x + (int) width, y + (int) height); - if ((pX == 0) && ((walls & Brick.LEFT) == Brick.LEFT)) + if ((pX == 0) && (Brick.isFlagSet( Brick.LEFT, walls))) g.drawLine(x, y, x, y + (int) height); } diff --git a/java/org/artisanlogiciel/games/maze/model/BooleanLongSet.java b/java/org/artisanlogiciel/games/maze/model/BooleanLongSet.java new file mode 100644 index 0000000..ce08f75 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/model/BooleanLongSet.java @@ -0,0 +1,41 @@ +package org.artisanlogiciel.games.maze.model; + +/** + * store an array booleans in a long + */ + +public class BooleanLongSet { + + long[] internal; + + // 62 bits for long, 2 bits reserved + int USED_BITS = 62; + int width; + + public BooleanLongSet(int width, int USED_BITS) + { + internal = new long[width]; + this.width = width; + this.USED_BITS = USED_BITS; + } + + boolean isSet(int x) { + int group = x / USED_BITS; + if (group < width) { + int pos = x % USED_BITS; + long mask = 1 << pos; + return (internal[group] & mask) != 0; + } + return false; + } + + void set(int x, boolean value) + { + int group = x / USED_BITS; + if (group < width) { + int pos = x % USED_BITS; + long mask = 1 << pos; + internal[group] &= mask; + } + } +} diff --git a/java/org/artisanlogiciel/games/maze/model/HalfSquareProvider.java b/java/org/artisanlogiciel/games/maze/model/HalfSquareProvider.java new file mode 100644 index 0000000..1a01911 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/model/HalfSquareProvider.java @@ -0,0 +1,6 @@ +package org.artisanlogiciel.games.maze.model; + +public interface HalfSquareProvider { + + long getLeftDown(int x, int y); +} diff --git a/java/org/artisanlogiciel/games/maze/model/HalfSquareRasterModel.java b/java/org/artisanlogiciel/games/maze/model/HalfSquareRasterModel.java index 71bb709..9304128 100644 --- a/java/org/artisanlogiciel/games/maze/model/HalfSquareRasterModel.java +++ b/java/org/artisanlogiciel/games/maze/model/HalfSquareRasterModel.java @@ -16,11 +16,13 @@ import org.artisanlogiciel.games.maze.WallsProvider; * bit value : * - set : there is a wall , no move in that direction * - unset : move is possible , there is no wall + * */ public class HalfSquareRasterModel implements WallsProvider, MovesProvider, - WidthHeightProvider + WidthHeightProvider, + HalfSquareProvider { int LEFT = 0x01; int DOWN = 0x02; @@ -42,7 +44,16 @@ public class HalfSquareRasterModel this.width = width; this.height = height; - lines = new long[height][(BITSX * width)/USED_BITS]; + lines = new long[height][getLongs()]; + } + + public int getLongs() + { + return (BITSX * width)/USED_BITS; + } + + public long[][] getLines() { + return lines; } public void setLeftDown(int x, int y, short moves) diff --git a/java/org/artisanlogiciel/games/maze/model/HexagonModelProvider.java b/java/org/artisanlogiciel/games/maze/model/HexagonModelProvider.java new file mode 100644 index 0000000..854467b --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/model/HexagonModelProvider.java @@ -0,0 +1,4 @@ +package org.artisanlogiciel.games.maze.model; + +public class HexagonModelProvider { +} diff --git a/java/org/artisanlogiciel/games/maze/model/LineColumnModel.java b/java/org/artisanlogiciel/games/maze/model/LineColumnModel.java new file mode 100644 index 0000000..99ae194 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/model/LineColumnModel.java @@ -0,0 +1,84 @@ +package org.artisanlogiciel.games.maze.model; + +import org.artisanlogiciel.games.maze.Brick; +import org.artisanlogiciel.games.maze.MovesProvider; +import org.artisanlogiciel.games.maze.WallsProvider; + +public class LineColumnModel + implements WallsProvider, + MovesProvider +{ + + final BooleanLongSet lines[]; + final BooleanLongSet columns[]; + + public LineColumnModel(int width, int height) + { + lines = new BooleanLongSet[height]; + columns = new BooleanLongSet[width]; + } + + BooleanLongSet getLine(int column) + { + BooleanLongSet l = lines[column]; + if ( l == null ) + { + l= new BooleanLongSet(getWidth(),63); + lines[column] = l; + } + return l; + } + + BooleanLongSet getColumn(int line) + { + BooleanLongSet c = columns[line]; + if ( c == null ) + { + c = new BooleanLongSet(getHeight(),63); + columns[line] = c; + } + return c; + } + + @Override + public short getWalls(int x, int y) { + return (short) ( + (getLine(y).isSet(x) ? Brick.UP : 0) + + (getColumn(x).isSet(y) ? Brick.LEFT : 0) + + (getLine(y+1).isSet(x) ? Brick.DOWN : 0) + + (getColumn(x+1).isSet(y) ? Brick.RIGHT : 0) + ); + } + + @Override + public short getMoves(int x, int y) + { + // moves are where there is no walls ... + return (short) ((~ getWalls(x,y)) & 0x0f); + } + + @Override + public int getWidth() { + return columns.length; + } + + @Override + public int getHeight() { + return lines.length; + } + + public void setWalls(int x, int y, short walls) + { + getLine(y).set(x, (walls & Brick.UP) != 0); + getColumn(x).set(y, (walls & Brick.LEFT) != 0); + getLine(y+1).set(x, (walls & Brick.DOWN) != 0); + getColumn(x+1).set(y, (walls & Brick.RIGHT) != 0); + } + + public void setMoves(int x, int y, short moves) + { + short walls = (short) ~ moves; + setWalls(x,y,walls); + } + +} \ No newline at end of file diff --git a/java/org/artisanlogiciel/games/maze/persist/HalfSquareRasterModelPersistRaw.java b/java/org/artisanlogiciel/games/maze/persist/HalfSquareRasterModelPersistRaw.java new file mode 100644 index 0000000..eb32895 --- /dev/null +++ b/java/org/artisanlogiciel/games/maze/persist/HalfSquareRasterModelPersistRaw.java @@ -0,0 +1,77 @@ +package org.artisanlogiciel.games.maze.persist; + +import org.artisanlogiciel.games.maze.model.HalfSquareRasterModel; + +import java.io.*; + +public class HalfSquareRasterModelPersistRaw { + private HalfSquareRasterModel model; + + private static byte HEADER[] = new byte[]{(byte) 'L', (byte) 'A', (byte) 'B', (byte) '1'}; + + public HalfSquareRasterModelPersistRaw(HalfSquareRasterModel model) + { + this.model = model; + } + + public HalfSquareRasterModelPersistRaw() + { + this.model = model; + } + + + public void streamOut(String pFormat, OutputStream pOut) throws IOException { + if ((pFormat == null) || (pFormat.equals("sraw"))) { + // first raw format, not smart. + DataOutputStream dataOut = new DataOutputStream(pOut); + // should dump this to stream. + dataOut.write(HEADER); + dataOut.writeInt(model.getWidth()); + dataOut.writeInt(model.getHeight()); + dataOut.flush(); + long[][] t = model.getLines(); + for (int y = 0; y < model.getHeight(); y++) { + for (int x = 0; x < model.getLongs(); x++) { + dataOut.writeLong(t[y][x]); + } + } + dataOut.flush(); + } else { + throw new IOException("Format " + pFormat + " Not yet implemented."); + } + } + + + public HalfSquareRasterModel parseInputStream(String pFormat, InputStream pIn) throws IOException { + if ((pFormat == null) || (pFormat.equals("sraw"))) { + // 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; + model= new HalfSquareRasterModel(width, height); + // SHOULD CHECK max width and max height... + // CLEAR == 0 and array is initialized with 0s + long[][] t = model.getLines(); + for (int y = 0; y < height; y++) { + for (int x = 0; x < model.getLongs(); x++) { + t[y][x] = in.readLong(); + } + } + 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/maze/persist/MazePersistRaw.java b/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java index eef055f..c3c49f4 100644 --- a/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java +++ b/java/org/artisanlogiciel/games/maze/persist/MazePersistRaw.java @@ -4,8 +4,13 @@ import org.artisanlogiciel.games.maze.LabyModel; import java.io.*; +/** + * raw model with short table inner of LabyModel + */ public class MazePersistRaw { + private static byte HEADER[] = new byte[]{(byte) 'L', (byte) 'A', (byte) 'B', (byte) '0'}; + private LabyModel model; public MazePersistRaw(LabyModel model) @@ -24,7 +29,7 @@ public class MazePersistRaw // 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.write(HEADER); dataOut.writeInt(model.getWidth()); dataOut.writeInt(model.getHeight()); dataOut.flush(); @@ -46,6 +51,7 @@ public class MazePersistRaw byte[] header = new byte[4]; DataInputStream in = new DataInputStream(pIn); in.read(header); + // TODO check header == HEADER int rwidth = in.readInt(); int rheight = in.readInt(); if ((rwidth > 0) && (rheight > 0)) {