sim.app.hexabugs.HexaBugsWithUI Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mason Show documentation
Show all versions of mason Show documentation
MASON is a fast discrete-event multiagent simulation library core in Java, designed to be the foundation for large custom-purpose Java simulations, and also to provide more than enough functionality for many lightweight simulation needs. MASON contains both a model library and an optional suite of visualization tools in 2D and 3D.
The newest version!
/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package sim.app.hexabugs;
import sim.engine.*;
import sim.display.*;
import sim.portrayal.grid.*;
import sim.portrayal.simple.*;
import java.awt.*;
import javax.swing.*;
import sim.util.gui.*;
import sim.portrayal.*;
public class HexaBugsWithUI extends GUIState
{
public Display2D display;
public JFrame displayFrame;
HexaSparseGridPortrayal2D bugPortrayal = new HexaSparseGridPortrayal2D();
// we have heat as EITHER hexagons OR rectangles. The current portrayal is always
// currentHeatPortrayal, which can be changed in the model inspector (see
// getInspector() below)
FastHexaValueGridPortrayal2D heatPortrayal= new FastHexaValueGridPortrayal2D("Heat");
HexaValueGridPortrayal2D heatPortrayal2 = new HexaValueGridPortrayal2D("Heat");
HexaValueGridPortrayal2D currentHeatPortrayal = heatPortrayal;
public static void main(String[] args)
{
new HexaBugsWithUI().createController();
}
public HexaBugsWithUI() { super(new HexaBugs(System.currentTimeMillis())); }
public HexaBugsWithUI(SimState state) { super(state); }
public static String getName() { return "HexaBugs"; }
public Object getSimulationInspectedObject() { return state; }
// One approach to creating the Hexagons/Rectangles popup menu is to hand-code the
// menu ourselves in a wrapper inspector. This requires some knowledge of Java's
// event handling etc.
// Another approach to doing the Hexagon/Rectangle code is to create a class which has a single
// readable, writable integer property called DisplayGridCellsAs. If the property is set to 0 or 1
// the object changes the heat portrayal appropriately just like was done above. We make the
// popup menu appear by providing a domain in the form of an array (for the values 0 and 1).
// Then we just make an inspector which encapsulates the previous inspector and a new SimpleInspector
// on an instance of this object.
public class HexagonChoice
{
int cells = 0;
public Object domDisplayGridCellsAs() { return new Object[] { "Rectangles", "Hexagons"}; }
public int getDisplayGridCellsAs() { return cells; }
public void setDisplayGridCellsAs(int val)
{
if (val == 0)
{
cells = val;
currentHeatPortrayal = heatPortrayal;
}
else if (val == 1)
{
cells = val;
currentHeatPortrayal = heatPortrayal2;
}
// reattach the portrayals
display.detatchAll();
display.attach(currentHeatPortrayal,"Heat");
display.attach(bugPortrayal,"Bugs");
// redisplay
display.repaint();
}
}
public Inspector getInspector()
{
// we'll make a fancy inspector which has a nicely arranged update button and
// two subinspectors. In fact the inspector doesn't need an update button --
// there's nothing that ever changes on update. But since the inspector
// has been declared non-volatile, just to be consistent, we'll add an update
// button up top to show how it's done. First we get our two subinspectors,
// one for the hexagon choice menu and one for the model inspector proper.
final Inspector originalInspector = super.getInspector();
final SimpleInspector hexInspector = new SimpleInspector(new HexagonChoice(),this);
// The originalInspector is non-volatile. It's a SimpleInspector, which shows
// its update-button automagically when non-volatile. We WANT it to be non-volatile,
// but not show its update button because that just updates the inspector and nothing
// else. So we declare the inspector to be volatile. It won't matter because it'll
// NEVER receive updateInspector() calls except via the outer inspector we're
// constructing next (which will be NON-volatile).
originalInspector.setVolatile(true);
// our wrapper inspector
Inspector newInspector = new Inspector()
{
public void updateInspector() { originalInspector.updateInspector(); } // don't care about updating hexInspector
};
newInspector.setVolatile(false);
// NOW we want our outer inspector to be NON-volatile, but show an update button.
// While SimpleInspectors add their own buttons automagically, plain Inspectors
// do not. Instead we have to add it manually. We grab an update-button from
// the inspector, put it in a box so it doesn't stretch when the inspector does.
// And we want to move it in a bit border-wise because that's what the SimpleInspector
// does.
Box b = new Box(BoxLayout.X_AXIS)
{
public Insets getInsets() { return new Insets(2,2,2,2); } // in a bit
};
b.add(newInspector.makeUpdateButton());
b.add(Box.createGlue());
// okay, great. But we want the button to be up top, followed by the hex inspector,
// and then the originalInspector taking up the rest of the room. Sadly, there's
// no layout manager to do that. So we do it thus:
Box b2 = new Box(BoxLayout.Y_AXIS);
b2.add(b);
b2.add(hexInspector);
b2.add(Box.createGlue());
// all one blob now. We can add it at NORTH.
newInspector.setLayout(new BorderLayout());
newInspector.add(b2,BorderLayout.NORTH);
newInspector.add(originalInspector,BorderLayout.CENTER);
return newInspector;
}
public void start()
{
super.start();
// set up our portrayals
setupPortrayals();
}
public void load(SimState state)
{
super.load(state);
// we now have new grids. Set up the portrayals to reflect that
setupPortrayals();
}
// This is called by start() and by load() because they both had this code
// so I didn't have to type it twice :-)
public void setupPortrayals()
{
// tell the portrayals what to portray and how to portray them
ColorMap map = new sim.util.gui.SimpleColorMap(0,HexaBugs.MAX_HEAT,Color.black,Color.red);
heatPortrayal.setField(((HexaBugs)state).valgrid);
heatPortrayal.setMap(map);
heatPortrayal2.setField(((HexaBugs)state).valgrid);
heatPortrayal2.setMap(map);
bugPortrayal.setField(((HexaBugs)state).buggrid);
bugPortrayal.setPortrayalForAll(new MovablePortrayal2D(
new sim.portrayal.simple.OvalPortrayal2D(Color.white))); // all the HexaBugs will be white ovals
// reschedule the displayer
display.reset();
// redraw the display
display.repaint();
}
/** The ratio of the width of a hexagon to its height: 1 / Sin(60 degrees), otherwise known as 2 / Sqrt(3) */
public static final double HEXAGONAL_RATIO = 2/Math.sqrt(3);
public void init(Controller c)
{
super.init(c);
// Make the Display2D. We'll have it display stuff later.
// Horizontal hexagons are staggered. This complicates computations. Thus
// if you have a M x N grid scaled to SCALE, then
// your height is (N + 0.5) * SCALE
// and your width is ((M - 1) * (3/4) + 1) * HEXAGONAL_RATIO * SCALE
// You might need to adjust by 1 or 2 pixels in each direction to get circles
// which usually come out as circles and not as ovals.
final double scale = 4;
final double m = 100;
final double n = 100;
final int height = (int) ( (n + 0.5) * scale );
final int width = (int) ( ((m - 1) * 3.0 / 4.0 + 1) * HEXAGONAL_RATIO * scale );
display = new Display2D(width, height, this);
displayFrame = display.createFrame();
c.registerFrame(displayFrame); // register the frame so it appears in the "Display" list
displayFrame.setVisible(true);
// attach the portrayals
display.attach(currentHeatPortrayal,"Heat");
display.attach(bugPortrayal,"Bugs");
// specify the backdrop color -- what gets painted behind the displays
display.setBackdrop(Color.black);
}
public void quit()
{
super.quit();
if (displayFrame!=null) displayFrame.dispose();
displayFrame = null; // let gc
display = null; // let gc
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy