Files
artloglaby/java/org/artisanlogiciel/games/Display.java
philippe lhardy 9333018aff some eclipse stuff
provide artlogjavaformat to reformat code
2016-03-24 22:01:41 +01:00

615 lines
17 KiB
Java

package org.artisanlogiciel.games;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Scanner;
import javax.swing.AbstractAction;
import javax.swing.Action;
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 javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Display
**/
public class Display extends JFrame
{
// to please eclipse, not supposed to be serialized
private static final long serialVersionUID = 8500214871372184418L;
MazeComponent maze;
MazeControler controler;
LabyModel model;
JPanel controlPanel;
Display(LabyModel model, MazeComponent comp)
{
super("Maze display");
maze = comp;
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 static class MazeParamEditor implements MazeParams
{
int width;
int height;
int maxdepth;
File labdir;
String name;
public MazeParamEditor(File saveDir)
{
name = null;
labdir = saveDir;
}
public void read(Scanner console)
{
width = console.nextInt();
height = console.nextInt();
maxdepth = console.nextInt();
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public int getMaxDepth()
{
return maxdepth;
}
public String getName()
{
if (name == null)
{
name = "lab" + width + "x" + height;
}
return name;
}
public File getSaveDir()
{
return labdir;
}
}
private class MazeControler extends JPanel
{
/**
*
*/
private static final long serialVersionUID = 1L;
public MazeControler()
{
controlPanel = new JPanel();
JButton button = new JButton("Resolve");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
//
System.out.println("Resolving");
resolve();
}
});
@SuppressWarnings("serial")
Action goNorth = new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
//
System.out.println("go North");
goNorth();
}
};
JButton north = addDirection(this, "North", "UP", goNorth);
@SuppressWarnings("serial")
Action goEast = new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
//
System.out.println("go East");
goEast();
}
};
JButton east = addDirection(this, "East", "RIGHT", goEast);
@SuppressWarnings("serial")
Action goWest = new AbstractAction()
{
public void actionPerformed(ActionEvent evt)
{
//
System.out.println("go West");
goWest();
}
};
JButton west = addDirection(this, "West", "LEFT", goWest);
@SuppressWarnings("serial")
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
{
private static final long serialVersionUID = 3163272907991176390L;
WallsProvider map;
int width = 10;
int height = 10;
int offsetX = 5;
int offsetY = 5;
Position current = null;
LinkedList<Position> 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<Position> solvedPath)
{
LinkedList<Position> newPath = new LinkedList<>(solvedPath);
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");
MazeParamEditor params = new MazeParamEditor(new File("lab"));
params.read(new Scanner(System.in));
model = new LabyModel(params, new java.util.Random());
int w = W / params.getWidth();
int h = H / params.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);
model.generateWithEntry(0, 0);
model.addEntryOrExit(-1, 0);
model.addEntryOrExit(params.getWidth(), params.getHeight() - 1);
System.out.println("Generation completed");
File outfile = new File(params.getSaveDir(), params.getName() + ".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(params.getSaveDir(), params.getName() + ".stl");
if (!outfile.exists())
{
System.out.println("Saving to " + outfile + " ...");
try
{
FileOutputStream out = new FileOutputStream(outfile);
Wall3d.streamWallsOut(params.getName(), (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");
}
}
}
}