📄 world.java
字号:
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class World implements KarelJConstants
{
//static private GUI singletonWorld = null;
static private boolean stateChanged = false;
private JFrame jFrame;
private JTextField streetsText;
private JTextField avenuesText;
private JTextField delayText;
private JButton pauseButton;
/**
*
* @uml.property name="singletonWorld"
* @uml.associationEnd multiplicity="(0 1)"
*/
private static World singletonWorld;
/**
* Get the only World instance. If no instance yet exists, it creates a new
* instance of World. Subclasses can set the protected field <code>singletonWorld</code>
* so that an instance of the subclass will be used.
* @return the only World instance
*/
static protected World getWorld()
{
if( singletonWorld == null )
{
singletonWorld = new World();
if(System.getProperty("text", "false").equals("ide"))
singletonWorld.init();
else if(!new Boolean(System.getProperty("text", "false")).booleanValue()) {
singletonWorld.init();
singletonWorld.makeFrame();
}
try {
setDelay(new Integer(System.getProperty("delay", "0")).intValue());
} catch (NumberFormatException e) {
}
try {
setAvenues(new Integer(System.getProperty("avenues", "10")).intValue());
} catch (NumberFormatException e1) {
}
try {
setStreets(new Integer(System.getProperty("streets", "15")).intValue());
} catch (NumberFormatException e2) {
}
}
return singletonWorld;
}
public void makeFrame() {
if(jFrame != null)
return;
jFrame = new JFrame();
jFrame.getContentPane().add(worldPanel);
Dimension ScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
int height = ScreenSize.height * 3 / 4;
int width = ScreenSize.width * 3 / 4;
int x = ScreenSize.width / 8;
int y = ScreenSize.height / 8;
jFrame.setSize( new Dimension( width, height ) );
jFrame.setLocation( x, y );
if(!new Boolean(System.getProperty("karelj.nogui", "false")).booleanValue())
jFrame.show();
jFrame.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowDeactivated(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
});
getStopButton().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
}
/**
*
* @uml.property name="worldPanel"
*/
public JPanel getWorldPanel() {
return worldPanel;
}
/**
*
* @uml.property name="stopButton"
*/
public JButton getStopButton() {
return stopButton;
}
/**
* For internal use. The world maintains a list of World.Robots to keep track of
* all robots in the world. This class also offers the toString() method to
* receive a String representation of the Robot's state, which is used by the
* trace() method.
*/
static protected class Robot
{
public int id;
public boolean on = true;
public int avenue;
public int street;
public int beepers;
public int direction;
public String toString()
{
String result = "RobotId " + id + " at (street: " + street + ") (avenue: " + avenue + ") (beepers: ";
if( beepers < 0 )
result += "infinite";
else
result += beepers;
result += ") (direction: ";
if( direction == North.getValue() )
result += "North ";
else if( direction == South.getValue() )
result += "South ";
else if( direction == West.getValue() )
result += "West ";
else if( direction == East.getValue() )
result += "East ";
result += ") ";
if( on )
result += "on";
else
result += "off";
return result;
}
}
/**
* For internal use. Keeps track of the Beepers lying in the world. It is not
* used to represent Beepers kept by robots. There may never exist a Beepers
* object with less than one beeper.
*/
static protected class Beepers
{
public int avenue;
public int street;
public int count;
}
/**
* For internal use. Keeps track of the walls standing in the world. If isEastWest
* is true, the wall runs from east to west, thereby blocking an avenue. In this case the
* the avenue <code>avenue</code> is blocked and it cannot be crossed to move from
* street <code>street</code> the the one north of <code>street</code>. If isNorthSouth
* is true, a street is blocked respectively, which cannot be used to move from
* <code>avenue</code> to east of <code>avenue</code>.
*/
static protected class Wall
{
public boolean isEastWest;
public boolean isNorthSouth;
public int avenue;
public int street;
}
protected class DelayThread extends Thread
{
volatile boolean paused = false;
boolean doDelay = true;
public DelayThread()
{
}
public DelayThread( boolean doDelay )
{
this.doDelay = doDelay;
}
public void run()
{
if( doDelay )
{
try
{
Thread.sleep( delay );
while( paused )
{
Thread.sleep( 50 );
}
}
catch( InterruptedException exception )
{
exception.printStackTrace();
}
}
}
public void pause()
{
paused = true;
}
public void unPause()
{
paused = false;
}
}
private boolean trace = true;
private int nextRobotId = 0;
protected Hashtable robots = new Hashtable();
protected Vector walls = new Vector ( ) ;
protected Vector beepers = new Vector ( ) ;
protected int avenues = 15 ;
protected int streets = 10 ;
protected int delay = 1;
/**
*
* @uml.property name="delayThread"
* @uml.associationEnd multiplicity="(0 1)"
*/
protected DelayThread delayThread = new DelayThread(false);
private JPanel worldPanel;
private JButton stopButton;
private World() {
}
/**
* Used when a Robot's state changed. If tracing is enabled, the Robot's state
* is printed to stanard out.
*/
protected void trace( Robot robot )
{
stateChanged = true;
if( trace )
System.out.println( robot );
}
/**
* Used to receive the Robot for an Id. This method also assures that there is a delay
* between Robot motions. This is mostly for displaying purposes in this class. A subclass
* could use this method to synchronize different Threads of Robots of differen
* processes using RMI, though.
*/
protected Robot getRobot( Integer robotId, boolean sync )
{
Robot result = (Robot) robots.get( robotId );
if( result == null )
throw new RuntimeException( "No such robot." );
if( !result.on )
throw new RuntimeException( "Robot is turned off." );
if( !sync )
return result;
sync();
return result;
}
protected void sync()
{
DelayThread delayThread = this.delayThread;
try
{
delayThread.join();
}
catch( InterruptedException exception )
{
exception.printStackTrace();
}
synchronized( this )
{
if( this.delayThread == delayThread )
{
this.delayThread = new DelayThread();
this.delayThread.start();
}
}
}
// methods for handling the world
public static void resetWalls()
{
getWorld().resetWallsInternal();
}
protected void resetWallsInternal()
{
walls = new Vector();
update();
}
public static void resetBeepers()
{
getWorld().resetBeepersInternal();
}
protected void resetBeepersInternal()
{
beepers = new Vector();
update();
}
public static void resetRobots()
{
getWorld().resetRobotsInternal();
}
protected void resetRobotsInternal()
{
robots = new Hashtable();
nextRobotId = 0;
update();
}
/**
* Adds <code>count</code> beepers the the crossroad denoted by <code>street</code>
* and <code>avenue</code>.
*/
static public void placeBeepers( int street, int avenue, int count )
{
getWorld().placeBeepersInternal( street, avenue, count );
}
protected synchronized void placeBeepersInternal( int street, int avenue, int count )
{
Enumeration enumeration = beepers.elements();
while( enumeration.hasMoreElements() )
{
Beepers current = (Beepers) enumeration.nextElement();
if( ( current.avenue == avenue ) && ( current.street == street ) )
{
current.count += count;
return;
}
}
Beepers newBeepers = new Beepers();
newBeepers.avenue = avenue;
newBeepers.street = street;
newBeepers.count = count;
beepers.add( newBeepers );
update();
}
/**
* Starting at the avenue <code>atAvenue</code> and continuing to the east, this method
* places <code>lengthTowardEast</code> walls north of the street <code>northOfStreet</code>.
*/
static public void placeEWWall( int northOfStreet, int atAvenue, int lengthTowardEast )
{
getWorld().placeEWWallInternal( northOfStreet, atAvenue, lengthTowardEast );
}
protected synchronized void placeEWWallInternal( int northOfStreet, int atAvenue, int lengthTowardEast )
{
for( ; lengthTowardEast > 0; lengthTowardEast--, atAvenue++ )
{
Wall wall = new Wall();
wall.isEastWest = true;
wall.avenue = atAvenue;
wall.street = northOfStreet;
walls.add( wall );
}
update();
}
/**
* starting at the street <code>atStreet</code> and continuing to the north, this method
* places <code>lengthTowardNorth</code> walls east of the avenue <code>eastOfAvenue</code>.
*/
static public void placeNSWall( int atStreet, int eastOfAvenue, int lengthTowardNorth )
{
getWorld().placeNSWallInternal( atStreet, eastOfAvenue, lengthTowardNorth );
}
protected synchronized void placeNSWallInternal( int atStreet, int eastOfAvenue, int lengthTowardNorth )
{
for( ; lengthTowardNorth > 0; lengthTowardNorth--, atStreet++ )
{
Wall wall = new Wall();
wall.isNorthSouth = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -