// This class represents rooms in which robots can move about. // // History: // // July 2003 -- Created by Doug Baldwin. // // March 2004 -- Extended by Doug Baldwin to accept "K" (black) as a // color specification for tiles in room descriptions. package geneseo.cs.sc; import java.util.StringTokenizer; import javax.swing.JFrame; import java.awt.*; /** * Represents a room in which Science of Computing robots can move. A room consists * of a tiled floor and walls. The floor tiles can be colored. Within the room, * tiles provide a coordinate system for describing the positions of robots, walls, * etc. The coordinate system's origin is the upper left corner of the room, with * horizontal coordinates increasing to the right and vertical coordinates increasing * down. Coordinates start at 0, i.e., the left-most side of the room is horizontal * coordinate 0, and the top side is row 0. Every room has walls around its edges * (so that robots can't fall out of the room), and a room may have other walls * (or fragments of wall) in its interior. * @see geneseo.cs.sc.Robot */ public class RobotRoom extends Canvas { // Robot rooms use an internal class to represent tiles. This class // is basically just a simple record that stores a tile's color, whether // it has a wall on it, and whether it has a robot on it (and which robot, // if so). It also provides some simple support for things like initializing // and drawing tiles. private static class Tile { public static final int WIDTH = 30; // The width of a tile when drawn, in pixels public static final int HEIGHT = 30; // A tile's height, in pixels public static final Color wallColor = new Color( (float)0.4, (float)0.32, (float)0.08 ); public Color color; // The tile's color public Robot occupant; // The robot on this tile, or null public boolean isWall; // True if there is a wall on this tile public Tile( Color color, Robot occupant, boolean isWall ) { if ( isWall ) { this.color = wallColor; } else { this.color = color; } this.occupant = occupant; this.isWall = isWall; } public void draw( Graphics context, int left, int top ) { context.setColor( color ); context.fillRect( left, top, WIDTH, HEIGHT ); if ( occupant != null ) { occupant.draw( context, left+WIDTH/2, top+HEIGHT/2 ); } } } // Internally, robot rooms record their width and height, and an array // of their tiles. They also have a frame in which they appear on the // screen: private int width; private int height; private Tile[][] tiles; private JFrame window; // Internal parameters for drawing robot rooms: private final int inset = 20; // Number of pixels room is inset from frame's sides /** * Initialize a robot's room with default size and contents. The default * is a square room 10 tiles on a side, with all tiles white and no * interior walls. For example *
RobotRoom room = new RobotRoom();
RobotRoom room = new RobotRoom( "5 5 2 1 Y" );
9 5 4 2 * 3 2 r
* specifies a 9-tile wide by 5-tile high room whose middle tile is
* a wall, the tile to its left is red. The outer-most rows and columns of
* the room always contain walls, and any tiles not defined by the description
* are white.
*/
public RobotRoom( String description ) {
super();
// Initialize the frame in which this world will appear:
window = new JFrame( "Robot Room" );
window.getContentPane().add( this );
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
// Get the requested width and height:
final int minWidth = 3;
final int maxWidth = 25;
final int minHeight = 3;
final int maxHeight = 25;
width = minWidth; // Width and height start with their
height = minHeight; // default values
StringTokenizer tokens = new StringTokenizer( description );
try {
width = Integer.parseInt( tokens.nextToken() );
if ( width < minWidth || width > maxWidth ) {
width = minWidth;
}
height = Integer.parseInt( tokens.nextToken() );
if ( height < minHeight || height > maxHeight ) {
height = minHeight;
}
}
catch ( Exception error ) {
// Ignore exceptions in processing width and height, width and/or
// height variables will come out with their default values when
// there are errors.
}
// Create the tile array, filling it with empty white tiles everywhere except
// the outer rows and columns, which have walls on them:
tiles = new Tile[height][width];
for ( int row = 0; row < height; row++ ) {
for ( int col = 0; col < width; col++ ) {
boolean isWall = ( row == 0 || row == height-1 || col == 0 || col == width-1 );
tiles[row][col] = new Tile( Color.white, null, isWall );
}
}
// Go through the rest of the room's description, changing any tiles that it mentions
// to the color and wall status it requests. But don't allow changes in the border wall,
// or outside the room:
while ( tokens.hasMoreTokens() ) {
try {
int col = Integer.parseInt( tokens.nextToken() );
int row = Integer.parseInt( tokens.nextToken() );
char colorCode = tokens.nextToken().charAt(0);
if ( row > 0 && row < height-1 && col > 0 && col < width-1 ) {
switch ( colorCode ) {
case 'r':
case 'R':
tiles[row][col].color = Color.red;
tiles[row][col].isWall = false;
break;
case 'g':
case 'G':
tiles[row][col].color = Color.green;
tiles[row][col].isWall = false;
break;
case 'b':
case 'B':
tiles[row][col].color = Color.blue;
tiles[row][col].isWall = false;
break;
case 'y':
case 'Y':
tiles[row][col].color = Color.yellow;
tiles[row][col].isWall = false;
break;
case 'k':
case 'K':
tiles[row][col].color = Color.black;
tiles[row][col].isWall = false;
break;
case '*':
tiles[row][col].isWall = true;
tiles[row][col].color = Tile.wallColor;
break;
}
}
}
catch ( Exception error ) {
// Do nothing on an error, try to continue with the next tile, if any.
}
}
// Size the window to display the room, and make it visible to the user. Note that
// the window width and height reflect the space needed for the window's border, an
// inset between each side of the room and the window border, and space for the room's
// tiles, each of which has a 1-pixel border between it and the previous tile, plus
// a one-pixel border after the last tile:
window.pack();
Insets borders = window.getInsets();
int windowWidth = borders.left + borders.right + 2 * inset + width * ( Tile.WIDTH + 1 ) + 1;
int windowHeight = borders.top + borders.bottom + 2 * inset + height * (Tile.HEIGHT + 1 ) + 1;
window.setSize( windowWidth, windowHeight );
this.setVisible( true );
window.setVisible( true );
}
/**
* Put a robot in a room. This will put the robot at the requested
* position if possible. If not possible, because the requested
* position is outside the room, because there is a wall at the
* requested position, or because another robot is already at the
* requested position, then the new robot is not placed in the room
* at all. For example
* room.addRobot( someRobot, 3, 5 );
int w = room.getRoomWidth();
int h = room.getRoomHeight();