package org.artisanlogiciel.games.maze.gui; import java.awt.BorderLayout; import java.awt.image.BufferedImage; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.io.*; import java.util.LinkedList; import java.util.Locale; import java.util.ResourceBundle; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.artisanlogiciel.games.*; import org.artisanlogiciel.games.stl.Maze3dParams; import org.artisanlogiciel.games.stl.Wall3d; import org.artisanlogiciel.games.stl.Wall3dStream; import org.artisanlogiciel.util.UTF8Control; import org.artisanlogiciel.graphics.Drawing; import org.artisanlogiciel.graphics.DrawingLine; import org.artisanlogiciel.graphics.SvgWriter; /** * Display is Main JFrame for this tool **/ public class Display extends JFrame { // to please eclipse, not supposed to be serialized private static final long serialVersionUID = 8500214871372184418L; public final static ResourceBundle labels = ResourceBundle.getBundle("LabelsBundle", Locale.getDefault(), Display.class.getClassLoader(), new UTF8Control()); MazeComponent maze; MazeControler controler; LabyModel model; boolean autoSize; MazeParams params = null; JTextField statusField = null; Maze3dSettings stlsettings; Display(LabyModel model, int W, int H, MazeParams params) { super(labels.getString("title")); if (params != null) { // fixedParams = new MazeParamsFixed(params.getSaveDir(),params.getWidth(),params.getHeight(),params.getMaxDepth()); this.params = params; } this.model = model; maze = createMazeComponent(model, W, H); Container con = this.getContentPane(); JScrollPane scrollableMaze = new JScrollPane(maze); scrollableMaze.addMouseMotionListener(maze); con.add(scrollableMaze, BorderLayout.CENTER); controler = new MazeControler(params); con.add(controler.getMoveControl(), BorderLayout.NORTH); con.add(controler.getGenerationControl(), BorderLayout.SOUTH); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { if (autoSize) { maze.getAutoSize(); } } }); model.setMazeListener(maze); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(W, H, W, H); setVisible(true); } private MazeComponent createMazeComponent(LabyModel model, int W, int H) { MazeCellParameters cp = new MazeCellParameters(model.getWidth(), model.getHeight(), W, H, 3, 3); MazeComponent comp = new MazeComponent(model, cp); return comp; } void recreateModel() { // recreate labyrinth if (params != null) { // Keep current model to be able to complete a manualy edited one maze.resetWallsProvider(model); model.setMazeListener(maze); model.reset(); // we are in GUI event thread, need to release it and do it outside. new Thread() { public void run() { model.generateWithEntry(0, 0); model.addEntryOrExit(-1, 0); model.addEntryOrExit(params.getWidth(), params.getHeight() - 1); } }.start(); } } void resetModel() { // recreate labyrinth if (params != null) { params = controler.getSettings().resetParams(); model = new LabyModel(params); refresh(); } } void refresh() { // reinit labyrinth view if (params != null) { maze.resetWallsProvider(model); model.setMazeListener(maze); // we are in GUI event thread, need to release it and do it outside. new Thread() { public void run() { maze.changed(null, null, model); } }.start(); } } void resolve() { model.reset(); model.resolve(model.getWidth() - 1, model.getHeight() - 1, maze); } void goNorth() { maze.goNorth(); } void goSouth() { maze.goSouth(); } void goEast() { maze.goEast(); } void goWest() { maze.goWest(); } void setWallSize(int size) { maze.setWallSize(size); } void setAutoSize(boolean autoSize) { this.autoSize = autoSize; if (autoSize) { maze.getAutoSize(); } } void addWallInDrawing(int pX, int pY, Drawing d) { short walls = model.getWalls(pX, pY); short wdrawn = 0; // todo int w = 2; int h = 2; int ox = 0; int oy = 0; int x = ox + (int) (pX * w); int y = oy + (int) (pY * h); DrawingLine dl = new DrawingLine(); // order matters since all points are linked if ((pY == 0) && LabyModel.isFlagSet(walls, Brick.UP)) { dl.addPoint(new Point(x, y)); dl.addPoint(new Point(x + (int) w, y)); wdrawn |= Brick.UP; } if (LabyModel.isFlagSet(walls, Brick.RIGHT)) { if (!LabyModel.isFlagSet(wdrawn, Brick.UP)) { dl.addPoint(new Point(x + (int) w, y)); } dl.addPoint(new Point(x + (int) w, y + (int) h)); wdrawn |= Brick.RIGHT; } if (LabyModel.isFlagSet(walls, Brick.DOWN)) { if (!LabyModel.isFlagSet(wdrawn, Brick.RIGHT)) { if (wdrawn != 0) { d.addLine(dl); dl = new DrawingLine(); } dl.addPoint(new Point(x + (int) w, y + (int) h)); } dl.addPoint(new Point(x, y + (int) h)); wdrawn |= Brick.DOWN; } if ((pX == 0) && LabyModel.isFlagSet(walls, Brick.LEFT)) { if (!LabyModel.isFlagSet(wdrawn, Brick.DOWN)) { if (wdrawn != 0) { d.addLine(dl); dl = new DrawingLine(); } dl.addPoint(new Point(x, y + (int) h)); } dl.addPoint(new Point(x, y)); wdrawn |= Brick.LEFT; } if (wdrawn != 0) { d.addLine(dl); } } Drawing createDrawing() { Drawing d = new Drawing(); { short walls; // draw all walls within clip bounds horiz first then lines for (int y = 0; y < model.getHeight(); y++) { for (int x = 0; x < model.getWidth(); x++) { addWallInDrawing(x, y, d); } } } return d; } // to allow to log / write somewher into screen... void writeSentence(String pSentence) { // TODO addStatus(pSentence); } void writeError(String pError) { System.err.println(pError); } void saveImc() { Drawing d = createDrawing(); if (d != null) { File outfile = getFileForExtension("imc"); writeSentence("Saving to " + outfile + " ..."); try { DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile)); d.saveLinesKompressed(out); out.flush(); out.close(); writeSentence("... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } } File getFileForExtension(final String extension) { return new File(params.getSaveDir(), params.getName() + "." + extension); } void saveSvg() { Drawing d = createDrawing(); if (d != null) { File outfile = getFileForExtension("svg"); writeSentence("Saving to " + outfile + " ..."); try { DataOutputStream out = new DataOutputStream(new FileOutputStream(outfile)); SvgWriter writer = new SvgWriter(d.getInternLines()); writer.writeTo(out); out.flush(); out.close(); writeSentence("... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } else { writeError("drawing creation failed"); } } void savePng() { File file = getFileForExtension("png"); // BufferedImage bi = new BufferedImage(this.getSize().width, this.getSize().height, BufferedImage.TYPE_INT_ARGB); BufferedImage bi = new BufferedImage(maze.getSize().width, maze.getSize().height, BufferedImage.TYPE_INT_ARGB); Graphics g = bi.createGraphics(); // this.paint(g); maze.paint(g); g.dispose(); try { ImageIO.write(bi, "png", file); } catch (Exception e) { e.printStackTrace(); } } void addStatus(String pStatus) { statusField.setText(pStatus); } private class MazeControler extends JPanel { /** * */ private static final long serialVersionUID = 1L; private MazeSettings settings = null; private JPanel resizecontrol = null; private void setMazeName(String pName) { MazeParamsFixed p = (MazeParamsFixed) params; p.setName(pName); } private JMenu createLoadingMenu() { JMenu loadMenu = new JMenu(labels.getString("load") ); final JTextField loadName = new JTextField("newlaby"); loadMenu.add(loadName); Action loadRawAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("load raw"); String filename = loadName.getText(); if ((filename.length() > 0)) { setMazeName(filename); loadRaw(); refresh(); } } }; JButton loadRawButton = new JButton(labels.getString("load" ) + " raw"); loadRawButton.addActionListener(loadRawAction); loadMenu.add(loadRawButton); return loadMenu; } private JMenu createSavingMenu() { final JTextField saveName = new JTextField("newlaby"); final JButton savePngButton = new JButton(labels.getString("save") + " png"); Action savePngAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("save png"); setMazeName(saveName.getText()); savePng(); } }; savePngButton.addActionListener(savePngAction); final JButton saveSvgButton = new JButton(labels.getString("save") + " svg"); Action saveSvgAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { writeSentence("save svg"); setMazeName(saveName.getText()); saveSvg(); } }; saveSvgButton.addActionListener(saveSvgAction); final JButton saveButton = new JButton(labels.getString("save") + " raw"); Action saveAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("save"); setMazeName(saveName.getText()); MazeParamsFixed p = (MazeParamsFixed) params; save(p, model); } }; saveButton.addActionListener(saveAction); final JButton saveImcButton = new JButton(labels.getString("save") + " imc"); Action saveImcAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("save imc"); setMazeName(saveName.getText()); saveImc(); } }; saveImcButton.addActionListener(saveImcAction); final JButton saveStlButton = new JButton(labels.getString("save") + " stl"); Action saveStlAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("save stl"); setMazeName(saveName.getText()); MazeParamsFixed p = (MazeParamsFixed) params; saveStl(p, model,stlsettings.createParams()); } }; saveStlButton.addActionListener(saveStlAction); stlsettings = new Maze3dSettings(new Maze3dParams()); JMenu saveMenu = new JMenu(labels.getString("save") ); saveMenu.add(saveName); saveMenu.add(saveSvgButton); saveMenu.add(savePngButton); saveMenu.add(saveButton); saveMenu.add(stlsettings); saveMenu.add(saveStlButton); saveMenu.add(saveImcButton); return saveMenu; } private JPanel createResolveQuitBar() { JPanel resolveQuitBar = new JPanel(new FlowLayout()); JButton buttonCreate = new JButton(labels.getString("create")); buttonCreate.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { recreateModel(); } }); resolveQuitBar.add(buttonCreate); JButton resolveButton = new JButton(labels.getString("resolve")); resolveButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { // addStatus("Resolving"); resolve(); } }); resolveQuitBar.add(resolveButton); final JButton quitButton = new JButton(labels.getString("quit")); Action quitAction = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("quit"); System.exit(0); } }; quitButton.addActionListener(quitAction); resolveQuitBar.add(quitButton); JButton buttonReset = new JButton("reset");//labels.getString("reset")); buttonReset.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { resetModel(); } }); resolveQuitBar.add(buttonReset); return resolveQuitBar; } public MazeControler(MazeParams params) { // super(new BorderLayout()); super(); BoxLayout layout = new BoxLayout(this, BoxLayout.Y_AXIS); setLayout(layout); JMenuBar menuBar = new JMenuBar(); menuBar.add(createSavingMenu()); menuBar.add(createLoadingMenu()); add(menuBar); add(createResolveQuitBar()); JPanel controlMovesPanel = new JPanel(new BorderLayout()); settings = new MazeSettings(params); @SuppressWarnings("serial") Action goNorth = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("go North"); goNorth(); } }; JButton north = addDirection(this, labels.getString("north"), "UP", goNorth); @SuppressWarnings("serial") Action goEast = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("go East"); goEast(); } }; JButton east = addDirection(this, labels.getString("east"), "RIGHT", goEast); @SuppressWarnings("serial") Action goWest = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("go West"); goWest(); } }; JButton west = addDirection(this, labels.getString("west"), "LEFT", goWest); @SuppressWarnings("serial") Action goSouth = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // addStatus("go South"); goSouth(); } }; JButton south = addDirection(this, labels.getString("south"), "DOWN", goSouth); controlMovesPanel.add(north, BorderLayout.NORTH); controlMovesPanel.add(west, BorderLayout.WEST); controlMovesPanel.add(east, BorderLayout.EAST); controlMovesPanel.add(south, BorderLayout.SOUTH); JPanel controlPanel = new JPanel(); controlPanel.add(controlMovesPanel,BorderLayout.LINE_START); statusField = new JTextField("",20); controlPanel.add(statusField, BorderLayout.CENTER); add(controlPanel, BorderLayout.NORTH); // control display panel contains controls for display // zoom , autozoom. final JPanel controlDisplayPanel = new JPanel(new BorderLayout()); final JCheckBox showAll = new JCheckBox("show all"); showAll.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { maze.setShowAll(showAll.isSelected()); } }); final JSlider slider = new JSlider(2, 40); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setWallSize(slider.getValue()); } }); final JCheckBox autoSlide = new JCheckBox("autoslide"); autoSlide.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setAutoSize(autoSlide.isSelected()); } }); resizecontrol = new JPanel(new FlowLayout()); resizecontrol.add(showAll); resizecontrol.add(slider); resizecontrol.add(autoSlide); add(controlDisplayPanel, BorderLayout.SOUTH); add(resizecontrol, BorderLayout.WEST); add(settings, BorderLayout.EAST); } private JPanel getMoveControl() { return this; } private JPanel getResizeControl() { return resizecontrol; } private JPanel getGenerationControl() { return settings; } public MazeSettings getSettings() { return settings; } } private void loadRaw() { File infile = new File(params.getSaveDir(), params.getName() + ".raw"); FileInputStream inputStream = null; try { inputStream = new FileInputStream(infile); model = new LabyModel("raw", inputStream); } catch (IOException io) { io.printStackTrace(System.err); statusField.setText("[ERROR] Can't load " + infile.getAbsolutePath()); } finally { if (inputStream != null ) { // cleanup try { inputStream.close(); } catch (Exception any) { // don't care really } } } } private JButton addDirection(final JPanel panel, final String direction, String key, Action goAction) { String actionName = "go" + direction; JButton button = new JButton(direction); button.addActionListener(goAction); KeyStroke keystroke = KeyStroke.getKeyStroke(key); // attach keys to maze maze.getInputMap().put(keystroke, actionName); maze.getActionMap().put(actionName, goAction); return button; } private static class MazeCellParameters { double width = 10; // width of one cell double height = 10; // height of one cell int offsetX = 5; // x offset of upper corner left int offsetY = 5; // y offset of upper corner left int mapWidth = 0; int mapHeight = 0; public MazeCellParameters(int mapw, int maph, int W, int H, int x, int y) { double w = (W - x) / mapw; double h = (H - y) / maph; mapWidth = mapw; mapHeight = maph; if (w < 5) w = 5; if (h < 5) h = 5; setCellSize(w, h); offsetX = x; offsetY = y; } public void resetMazeWidthHeight(int mapw, int maph) { mapWidth = mapw; mapHeight = maph; } public void adaptTo(double W, double H) { double w = (W - offsetX) / mapWidth; double h = (H - offsetY) / mapHeight; mapWidth = mapWidth; mapHeight = mapHeight; if (w < 5) w = 5; if (h < 5) h = 5; setCellSize(w, h); } public void setCellSize(double w, double h) { width = w; height = h; } public double getWidth() { return width; } public double getHeight() { return height; } public int getOffsetX() { return offsetX; } public int getOffsetY() { return offsetY; } public Dimension getDimension() { return new Dimension(offsetX + (int) (mapWidth * width), offsetY + (int) (mapHeight * height)); } 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)) g.drawLine(x, y, x + (int) width, y); if ((walls & Brick.DOWN) == Brick.DOWN) g.drawLine(x, y + (int) height, x + (int) width, y + (int) height); if ((walls & Brick.RIGHT) == Brick.RIGHT) g.drawLine(x + (int) width, y, x + (int) width, y + (int) height); if ((pX == 0) && ((walls & Brick.LEFT) == Brick.LEFT)) g.drawLine(x, y, x, y + (int) height); } public void drawPath(Graphics g, DirectionPosition dp, int pX, int pY, int mX, int mY) { if (dp != null) { Position dot = dp.getPosition(); if ((dot.getX() >= pX) && (dot.getY() >= pY) && (dot.getX() < mX) && (dot.getY() < mY)) { int x = offsetX + (int) (dot.getX() * width); int y = offsetY + (int) (dot.getY() * height); short path = dp.getDirection(); int xm = x + (int) (width / 2); int ym = y + (int) (height / 2); if ((path & LabyModel.HORIZONTAL) == LabyModel.HORIZONTAL) { if ((path & LabyModel.POSITIVE) == LabyModel.POSITIVE) { g.drawLine(xm, ym, x + (int) width, ym); g.drawLine(xm, ym + (int) (height / 4), x + (int) width, ym); } // LEFT /_ if ((path & LabyModel.NEGATIVE) == LabyModel.NEGATIVE) { g.drawLine(x, ym, xm, ym); g.drawLine(x, ym, xm, ym - (int) (height / 4)); } } if ((path & LabyModel.VERTICAL) == LabyModel.VERTICAL) { if ((path & LabyModel.POSITIVE) == LabyModel.POSITIVE) { g.drawLine(xm, ym, xm, y + (int) height); g.drawLine(xm - (int) (width / 4), ym, xm, y + (int) height); } // UP |\ if ((path & LabyModel.NEGATIVE) == LabyModel.NEGATIVE) { g.drawLine(xm, ym, xm, y); g.drawLine(xm + (int) (width / 4), ym, xm, y); } } } } } public void drawDot(Graphics g, Position dot, int pX, int pY, int mX, int mY) { double radius = (height > width) ? width : height; int a = (int) (radius / 4); if ((dot.getX() >= pX) && (dot.getY() >= pY) && (dot.getX() < mX) && (dot.getY() < mY)) { int x = offsetX + (int) (dot.getX() * width); int y = offsetY + (int) (dot.getY() * height); int r2 = (int) ((radius * 3) / 4); g.drawOval(x + 1, y + 1, r2, r2); // g.drawLine(x+a,y+a,x+width-a,y+height-a); // g.drawLine(x+a,y+height-a,x+width-a,y+a); } else { int x = offsetX + (int) (pX * width); int y = offsetY + (int) (pY * height); g.drawLine(x + 1, y + 1, x + (int) width - 1, y + (int) height - 1); } } } private class MazeComponent extends JComponent implements MazeCreationListener, MazeResolutionListener, MouseMotionListener { private static final long serialVersionUID = 3163272907991176390L; // WallsProvider map; LabyModel map; final MazeCellParameters cp; Position current = null; LinkedList solvedPath = null; LinkedList drawingPath = null; final Object lockChange = new Object(); // current postion of human resolving int sX = 0; int sY = 0; // goal exit int gX = -1; int gY = -1; // not set by default for debug, will show any path boolean showAll = false; // for a given (x,y) pixel return cell position. Position getPosition(int x, int y) { int pX = (int) ((double) (x - cp.getOffsetX()) / cp.getWidth()); int pY = (int) ((double) (y - cp.getOffsetY()) / cp.getHeight()); return new Position(pX, pY); } @Override public void mouseDragged(MouseEvent e) { // should find the cell ... DirectionPosition last = null; short path = 0; Position newPosition = getPosition(e.getX(), e.getY()); if (drawingPath == null) { drawingPath = new LinkedList<>(); last = new DirectionPosition((short) 0, newPosition); addStatus("Mouse dragged Cell " + newPosition + " Button " + e.getModifiersEx() + " " + InputEvent.BUTTON1_DOWN_MASK); drawingPath.addLast(last); } else { // setShowAll(true); DirectionPosition first = drawingPath.getLast(); last = first; // construct as many move form last to new position as needed. while (!last.getPosition().equals(newPosition)) { path = LabyModel.getDirection(last.getPosition(), newPosition); last.setDirection(path); // button 1 : add direction; button 2 : replace with direction. if ((e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) { map.addDirection(last.getPosition().getX(), last.getPosition().getY(), path); } else { map.setDirection(last.getPosition().getX(), last.getPosition().getY(), path); } last = last.moveToAdjacentDirection(); drawingPath.addLast(last); } addStatus("Mouse dragged from Cell " + first.getPosition() + "To" + newPosition + " Button " + e.getModifiersEx() + " " + InputEvent.BUTTON1_DOWN_MASK); } changed(null, null, map); } @Override public void mouseMoved(MouseEvent e) { // addStatus("Mouse moved (" + e.getX() + ',' + e.getY() + ')'); Position newPosition = getPosition(e.getX(), e.getY()); if ((newPosition.getX() >= 0) && (newPosition.getY() >= 0)) { requestFocus(); } } public void setShowAll(boolean showall) { this.showAll = showall; addStatus(showAll ? "show all" : "X"); } void checkExit() { if ((sX == gX) && (sY == gY)) { addStatus("Exit found by human !"); } } void goNorth() { resetResolution(); if ((map.getWalls(sX, sY) & Brick.UP) == 0) { sY = sY - 1; // should redraw ... invalidate(); repaint(); checkExit(); } } void goSouth() { resetResolution(); if ((map.getWalls(sX, sY) & Brick.DOWN) == 0) { sY = sY + 1; // should redraw ... invalidate(); repaint(); checkExit(); } } void goEast() { resetResolution(); if ((map.getWalls(sX, sY) & Brick.RIGHT) == 0) { sX = sX + 1; // should redraw ... invalidate(); repaint(); checkExit(); } } void goWest() { resetResolution(); if ((map.getWalls(sX, sY) & Brick.LEFT) == 0) { sX = sX - 1; // should redraw ... invalidate(); repaint(); checkExit(); } } /** * width, height of one cell, * offsetX, offsetY of upper left corner **/ // public MazeComponent(WallsProvider map, MazeCellParameters cp) public MazeComponent(LabyModel map, MazeCellParameters cp) { super(); this.cp = cp; this.map = map; setPreferredSize(cp.getDimension()); gX = map.getWidth() - 1; gY = map.getHeight() - 1; } // public void resetWallsProvider(WallsProvider map) public void resetWallsProvider(LabyModel map) { this.map = map; solvedPath = null; // could be kept drawingPath = null; sX = 0; sY = 0; cp.resetMazeWidthHeight(map.getWidth(), map.getHeight()); setPreferredSize(cp.getDimension()); } public void setWallSize(int size) { cp.setCellSize((double) size, (double) size); // should redraw ... invalidate(); repaint(); } public int getAutoSize() { Rectangle r = getBounds(); cp.adaptTo((int) r.getWidth(), (int) r.getHeight()); // should redraw ... invalidate(); repaint(); return 50; } public void changed(Position cl, Position cr, WallsProvider map) { // should redraw ... invalidate(); repaint(); Object waiter = new Object(); synchronized (waiter) { try { waiter.wait(10); } catch (InterruptedException e) { System.err.println("Interrupted !"); } } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int x = 0; int y = 0; short walls = 0; short path = 0; // try to display only visible part... // should compute pX, pY, mX, mY based on clip... // Shape s=g.getClip(); Rectangle r = g.getClipBounds(); int mX = (int) ((double) r.getWidth() / cp.getWidth()); int mY = (int) ((double) r.getHeight() / cp.getHeight()); int pX = (int) ((double) (r.getX() - cp.getOffsetX()) / cp.getWidth()); int pY = (int) ((double) (r.getY() - cp.getOffsetY()) / cp.getHeight()); if (pX < 0) pX = 0; if (pY < 0) pY = 0; if (pX >= map.getWidth()) return; if (pY >= map.getHeight()) return; mX = mX + pX; mY = mY + pY; if (mX > map.getWidth()) { mX = map.getWidth(); } if (mY > map.getHeight()) { mY = map.getHeight(); } if ((sX == gX) && (sY == gY)) { g.setColor(Color.red); } else { g.setColor(Color.green); cp.drawDot(g, new Position(gX, gY), pX, pY, mX, mY); g.setColor(Color.blue); } cp.drawDot(g, new Position(sX, sY), pX, pY, mX, mY); synchronized (lockChange) { g.setColor(Color.red); if (current != null) { cp.drawDot(g, current, pX, pY, mX, mY); } if (solvedPath != null) { for (DirectionPosition resolved : solvedPath) { // cp.drawDot(g, resolved.getPosition(), pX, pY, mX, mY); cp.drawPath(g, resolved, pX, pY, mX, mY); } } } int aX = pX; int aY = pY; g.setColor(Color.black); // draw all walls within clip bounds horiz first then lines for (; pY < mY; pY++) { for (pX = 0; pX < mX; pX++) { walls = map.getWalls(pX, pY); cp.drawWalls(g, pX, pY, walls); } } if (this.showAll) { addStatus("*"); pX = aX; pY = aY; // draw all path within clip bounds horiz first then lines for (; pY < mY; pY++) { for (pX = 0; pX < mX; pX++) { path = map.getPath(pX, pY); if ((path & LabyModel.SOLVED) == LabyModel.SOLVED) { g.setColor(Color.green); } else { g.setColor(Color.blue); } if (path != 0) { DirectionPosition dp = new DirectionPosition(path, new Position(pX, pY)); cp.drawPath(g, dp, pX, pY, pX + 1, pY + 1); } } } } } public boolean notifySearch(DirectionPosition pPosition) { synchronized (lockChange) { current = pPosition.getPosition(); } // should redraw ... invalidate(); repaint(); return true; } public void notifySearchError(String error) { System.err.println(error); } public void notifyCompletion(LinkedList solvedPath) { LinkedList newPath = new LinkedList<>(solvedPath); addStatus("resolution completed"); synchronized (lockChange) { this.solvedPath = newPath; } // should redraw ... invalidate(); repaint(); } public void resetResolution() { solvedPath = null; } } private static void setupDisplay(LabyModel model, int W, int H, MazeParams params) { Display display = new Display(model, W, H, params); } public void saveStl(MazeParamsFixed params, LabyModel model, Maze3dParams wallparams) { File outfile = getFileForExtension("stl"); if (!outfile.exists()) { addStatus("Saving to " + outfile + " ..."); try { FileOutputStream out = new FileOutputStream(outfile); new Wall3dStream(params.getName(), model, out, wallparams).stream(); out.close(); addStatus("... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } else { addStatus("" + outfile + " already exists"); } } public void save(MazeParamsFixed params, LabyModel model) { File outfile = getFileForExtension("raw"); if (!outfile.exists()) { addStatus("Saving to " + outfile + " ..."); try { FileOutputStream out = new FileOutputStream(outfile); model.streamOut("raw", out); out.flush(); out.close(); addStatus("... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } else { addStatus("" + outfile + " already exists"); } } public static void main(String pArgs[]) { LabyModel model = null; int W = 600; int H = 400; System.out.println("Default Locale " + Locale.getDefault()); if ((pArgs.length > 0) && (pArgs[0].length() > 0)) { try { model = new LabyModel("raw", new FileInputStream(pArgs[0])); } catch (IOException io) { io.printStackTrace(System.err); System.exit(1); } setupDisplay(model, W, H, null); } else { MazeParamsFixed params = new MazeParamsFixed(new File("lab"), 20, 20, 12,1024L); model = new LabyModel(params); setupDisplay(model, W, H, params); /* model.generateWithEntry(0, 0); model.addEntryOrExit(-1, 0); model.addEntryOrExit(params.getWidth(), params.getHeight() - 1); addStatus("Generation completed"); */ /* */ } } }