package org.artisanlogiciel.games; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Container; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.LinkedList; import java.util.Scanner; import javax.swing.Action; import javax.swing.AbstractAction; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.KeyStroke; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** Display **/ public class Display extends JFrame { Object param; MazeComponent maze; MazeControler controler; LabyModel model; JPanel controlPanel; Display(LabyModel model, MazeComponent comp) { super("Maze display"); maze=comp; this.param=param; this.model=model; Container con = this.getContentPane(); con.add(new JScrollPane(comp), BorderLayout.CENTER); controler = new MazeControler(); con.add(controler,BorderLayout.NORTH); } void resolve() { 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); } private class MazeControler extends JPanel { public MazeControler() { controlPanel = new JPanel(); JButton button=new JButton("Resolve"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { // System.out.println("Resolving"); resolve(); } }); Action goNorth = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // System.out.println("go North"); goNorth(); } }; JButton north = addDirection(this,"North", "UP", goNorth); Action goEast = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // System.out.println("go East"); goEast(); } }; JButton east = addDirection(this,"East", "RIGHT", goEast); Action goWest = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // System.out.println("go West"); goWest(); } }; JButton west = addDirection(this,"West", "LEFT", goWest); Action goSouth = new AbstractAction() { public void actionPerformed(ActionEvent evt) { // System.out.println("go South"); goSouth(); } }; JButton south = addDirection(this,"South", "DOWN", goSouth); add(button,BorderLayout.CENTER); controlPanel.add(north,BorderLayout.NORTH); controlPanel.add(west,BorderLayout.WEST); controlPanel.add(east,BorderLayout.EAST); controlPanel.add(south,BorderLayout.SOUTH); add(controlPanel,BorderLayout.NORTH); final JSlider slider=new JSlider(2,40); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setWallSize(slider.getValue()); } }); add(slider,BorderLayout.EAST); } } 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); panel.getInputMap().put(keystroke,actionName); panel.getActionMap().put(actionName,goAction); controlPanel.getInputMap().put(keystroke,actionName); controlPanel.getActionMap().put(actionName,goAction); return button; } private static class MazeComponent extends JComponent implements MazeCreationListener, MazeResolutionListener { WallsProvider map; int width = 10; int height = 10; int offsetX = 5; int offsetY = 5; Position current = null; LinkedList solvedPath = null; final Object lockChange = new Object(); // current postion of human resolution int sX = 0; int sY = 0; // goal exit int gX = -1; int gY = -1; void checkExit() { if ((sX == gX) && (sY == gY)) { System.out.println("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(); } } public MazeComponent(WallsProvider map, int width, int height, int offsetX, int offsetY) { super(); this.map=map; this.width=width; this.height=height; this.offsetX=offsetX; this.offsetY=offsetY; setPreferredSize(new Dimension(1+2*offsetX+map.getWidth()*width, 1+2*offsetY+map.getHeight()*height)); gX = map.getWidth() -1; gY = map.getHeight() -1; } public void setWallSize(int size) { width=size; height=size; // should redraw ... invalidate(); repaint(); } 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 !"); } } } private void drawWalls(Graphics g, int x, int y, short walls, boolean full) { if ( (full) && (( walls & Brick.UP ) == Brick.UP )) g.drawLine(x, y, x+width, y); if ( ( walls & Brick.DOWN ) == Brick.DOWN ) g.drawLine(x, y+height, x+width, y+height); if ( ( walls & Brick.RIGHT ) == Brick.RIGHT ) g.drawLine(x+width, y, x+width, y+height); if ( (full) && (( walls & Brick.LEFT ) == Brick.LEFT )) g.drawLine(x, y, x, y+height); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int x = 0; int y = 0; short walls=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() / width); int mY = (int) ( (double) r.getHeight() / height); int pX = (int) ( (double) (r.getX() - offsetX) / width); int pY = (int) ( (double) (r.getY() - offsetY) / height); 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.blue); } drawDot(g,new Position(sX,sY),pX,pY,mX,mY); synchronized(lockChange) { g.setColor(Color.red); if ( current != null) { drawDot(g,current,pX,pY,mX,mY); } if (solvedPath != null) { for ( Position resolved : solvedPath ) { drawDot(g,resolved,pX,pY,mX,mY); } } } g.setColor(Color.black); for ( ; pY < mY ; pY ++) { for ( pX = 0; pX < mX ; pX ++) { x=offsetX+pX*width; y=offsetY+pY*height; walls = map.getWalls(pX,pY); drawWalls(g,x,y,walls,(pX == 0) || (pY==0)); } } } private void drawDot(Graphics g,Position dot, int pX, int pY, int mX, int mY) { int radius = ( height > width ) ? width : height; int a = radius / 4; if (( dot.getX() >= pX ) && ( dot.getY() >= pY ) && ( dot.getX() < mX ) && ( dot.getY() < mY ) ) { int x=offsetX+dot.getX()*width; int y=offsetY+dot.getY()*height; g.drawOval(x+1,y+1,radius-a,radius-a); //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+pX*width; int y=offsetY+pY*height; g.drawLine(x+1,y+1,x+width-1,y+height-1); } } public boolean notifySearch(Position pPosition) { synchronized(lockChange) { current = pPosition; } // should redraw ... invalidate(); repaint(); return true; } public void notifySearchError(String error) { System.err.println(error); } public void notifyCompletion(LinkedList solvedPath) { LinkedList newPath = (LinkedList) solvedPath.clone(); System.out.println("resolution completed"); synchronized(lockChange) { this.solvedPath = newPath; } // should redraw ... invalidate(); repaint(); } public void resetResolution() { solvedPath = null; } } public static void main(String pArgs[]) { LabyModel model = null; int W = 600; int H = 400; if ( pArgs.length > 0 ) { try { model = new LabyModel("raw",new FileInputStream(pArgs[0])); } catch (IOException io) { io.printStackTrace(System.err); } int w = W / model.getWidth(); int h = H / model.getHeight(); if ( w < 5 ) w = 5; if ( h < 5 ) h = 5; MazeComponent comp = new MazeComponent(model,w,h,3,3); Display display=new Display(model, comp); model.setMazeListener(comp); display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); display.setBounds(W,H,W,H); display.setVisible(true); } else { System.out.println("enter width height and maxdepth"); Scanner console = new Scanner(System.in); int width = console.nextInt(); int height = console.nextInt(); int maxdepth = console.nextInt(); model = new LabyModel(width, height,maxdepth, new java.util.Random()); int w = W / width; int h = H / height; if ( w < 5 ) w = 5; if ( h < 5 ) h = 5; MazeComponent comp = new MazeComponent(model,w,h,3,3); Display display=new Display(model,comp); model.setMazeListener(comp); display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); display.setBounds(W,H,W,H); display.setVisible(true); model.generateWithEntry(0, 0); LinkedList exits = new LinkedList(); model.addEntryOrExit(-1,0); model.addEntryOrExit(width,height -1); System.out.println("Generation completed"); String name="lab" + width + "x" + height; File outfile = new File(new File("lab"), name + ".raw"); if ( ! outfile.exists()) { System.out.println( "Saving to " + outfile + " ..."); try { FileOutputStream out = new FileOutputStream(outfile); model.streamOut("raw",out); out.flush(); out.close(); System.out.println( "... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } else { System.out.println( "" + outfile + " already exists"); } outfile = new File(new File("lab"),name + ".stl"); if ( ! outfile.exists()) { System.out.println( "Saving to " + outfile + " ..."); try { FileOutputStream out = new FileOutputStream(outfile); Wall3d.streamWallsOut(name,(WallsProvider) model,out); out.flush(); out.close(); System.out.println( "... Done."); } catch (IOException io) { io.printStackTrace(System.err); } } else { System.out.println( "" + outfile + " already exists"); } } } }