Files
EMARS/mars/tools/ScavengerHunt.java
T
adolphenom 0da1c5dcca Source code of MARS Assembler
First commit of the 4.5 version (latest version available)
2014-12-21 12:49:28 +01:00

972 lines
46 KiB
Java

package mars.tools;
import mars.*;
import mars.mips.hardware.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import javax.swing.JOptionPane;
import mars.util.*;
/**
* Demo of Mars tool capability. Ken Vollmar, 27 Oct 2006 KenVollmar@missouristate.edu
* This tool displays movements by a series of players in a game of ScavengerHunt.
* Players will read and write MIPS memory-mapped locations to move and regain energy.
* See accompanying documentation for memory-mapped addresses, rules of the game, etc.
*/
public class ScavengerHunt implements Observer, MarsTool
{
private static final int GRAPHIC_WIDTH = 712;
private static final int GRAPHIC_HEIGHT = 652;
private static final int NUM_PLAYERS = 22; // Number of players in the game, including "baseline" player
private static final int MAX_X_MOVEMENT = 2; // Max. movement in X direction
private static final int MAX_Y_MOVEMENT = 2; // Max. movement in X direction
private static final double MAX_MOVE_DISTANCE = 2.5; // Max. distance (Euclidean measure)
private static final int ENERGY_AWARD = 20; // Energy awarded for each task completion
private static final int ENERGY_PER_MOVE = 1; // Energy used in making each move (regardless of distance)
private static final int SIZE_OF_TASK = 20; // Number of elements in the task
private static final int NUM_LOCATIONS = 7; // Number of locations to which ScavengerHunt players travel.
// The first (n-1) locations are "random" locations, the last is START_AND_END_LOCATION
private static final int START_AND_END_LOCATION = 255; // Start and end location of the ScavengerHunt
private static final int ADMINISTRATOR_ID = 999; // Special ID for administrator
// MIPS addresses of administrative memory space.
// The administrator MIPS program writes a value to the Authentication field prior to writing a new
// value to the PlayerID field. The value of the Authentication field is not itself verified until
// the PlayerID field changes. Each new value of the Authentication field is one of some sequence
// known to the Tool program (one-time pad system).
// Each change of data in the PlayerID field is a signal for the Tool to check the value of the Authentication
// field. If the value of the Authentication field is correct, the value of the PlayerID field is used
// for memory bounds checking. A new value of the Authentication field is expected at each change of the
// PlayerID field (one-time pad system).
private static final int ADDR_AUTHENTICATION = 0xffffe000; // MIPS byte address of Authentication field
private static final int ADDR_PLAYER_ID = 0xffffe004; // MIPS byte address of PlayerID field
private static final int ADDR_GAME_ON = 0xffffe008; // MIPS byte address of signal that administration has initialized data
private static final int ADDR_NUM_TURNS = 0xffffe00c; // MIPS byte address of number of turns remaining in the game
// MIPS addresses of various data in each player's memory space.
// Each player's assigned memory is the MEM_PER_PLAYER bytes which begin at
// location ADDR_BASE + (ID * MEM_PER_PLAYER)
private static final int ADDR_BASE = 0xffff8000; // MIPS byte address of memory space for first player
private static final int MEM_PER_PLAYER = 0x400; // MIPS bytes of memory space given to each player
private static final int OFFSET_WHERE_AM_I_X = 0x0; // MIPS byte offset to this field
private static final int OFFSET_WHERE_AM_I_Y = 0x4; // MIPS byte offset to this field
private static final int OFFSET_MOVE_TO_X = 0x8; // MIPS byte offset to this field
private static final int OFFSET_MOVE_TO_Y = 0xc; // MIPS byte offset to this field
private static final int OFFSET_MOVE_READY = 0x10; // MIPS byte offset to this field
private static final int OFFSET_ENERGY = 0x14; // MIPS byte offset to this field
private static final int OFFSET_NUMBER_LOCATIONS = 0x18; // MIPS byte offset to this field
private static final int OFFSET_PLAYER_COLOR = 0x1c; // MIPS byte offset to this field
private static final int OFFSET_SIZE_OF_TASK = 0x20; // MIPS byte offset to this field
private static final int OFFSET_LOC_ARRAY = 0x24; // MIPS byte offset to this field
private static final int OFFSET_TASK_COMPLETE = 0x124; // MIPS byte offset to this field
private static final int OFFSET_TASK_ARRAY = 0x128; // MIPS byte offset to this field
// Other MIPS memory locations are available to the player's use.
private ScavengerHuntDisplay graphicArea;
private int authenticationValue = 0;
private boolean GameOn = false; // MIPS programs readiness
private static int SetWordCounter = 0;
private static int accessCounter = 0;
private static int playerID = ADMINISTRATOR_ID; // Range 0...(NUM_PLAYERS-1), plus ADMINISTRATOR_ID
private boolean KENVDEBUG = false;
// Used to define (X,Y) coordinate of a location to which ScavengerHunt players
// will travel.
private class Location
{
public int X;
public int Y;
}
// private inner class to provide the data on each player needed for display
private class PlayerData
{
int whereAmIX = START_AND_END_LOCATION; // Read only. Memory Address: Base
int whereAmIY = START_AND_END_LOCATION; // Read only. Memory Address: Base + 0x4
//int moveToX; // Memory Address: Base + 0x8
//int moveToY; // Memory Address: Base + 0xc
//int goalX; // Read only. Memory Address: Base + 0x10
//int goalY; // Read only. Memory Address: Base + 0x14
int energy = 20; // Read only. Memory Address: Base + 0x18
int color = 0; // Memory Address: Base + 0x1c
long finishTime;
//int locID; // ID of the location to which ScavengerHunt players are headed. Not used by player.
boolean hasVisitedLoc[] = new boolean[NUM_LOCATIONS]; // boolean: player has visited each location
boolean finis = false;
// Class PlayerData has no constructor
public void setWhereAmI(int gX, int gY) { whereAmIX = gX; whereAmIY = gY; }
//public void setGoal(int gX, int gY) { goalX = gX; goalY = gY; }
public void setEnergy(int e) { energy = e; }
public void setColor(int c) { color = c; }
public int getWhereAmIX() {
return whereAmIX; }
public int getWhereAmIY() {
return whereAmIY; }
public int getColor() {
return color; }
public boolean hasVisited(int i) {
return hasVisitedLoc[i]; }
public void setVisited(int i) { hasVisitedLoc[i] = true; }
public void setFinished() { finis = true; }
public boolean isFinished() {
return finis; }
public long getFinishTime() {
return finishTime; }
public long getFinishMin() {
return (finishTime / 60000); } // Minutes portion of finishTime
public long getFinishSec() {
return (finishTime % 60000) / 1000; // Seconds portion of finishTime
} // Seconds portion of finishTime
public long getFinishMillisec() {
return (finishTime % 1000); } // Millisec portion of finishTime
public void setFinishTime(long t) { finishTime = t; }
//public int getGoalX() { return goalX; }
//public int getGoalY() { return goalY; }
//public int getMoveToX() { return moveToX; }
//public int getMoveToY() { return moveToY; }
public int getEnergy() {
return energy; }
//public int getLocationID() { return locID; }
} // end class PlayerData
private static PlayerData[] pd = new PlayerData[NUM_PLAYERS];
private static Location[] loc = new Location[NUM_LOCATIONS];
private Random randomStream;
private long startTime;
// private inner class
private class ScavengerHuntRunnable implements Runnable
{
JPanel panel;
public ScavengerHuntRunnable() // constructor
{
// final JFrame frame = new JFrame("ScavengerHunt");
// Recommended by Pete Sanderson, 2 Nov. 2006, so that the Tool window and
// MARS window can be on the screen at the same time.
final JDialog frame = new JDialog(Globals.getGui(),"ScavengerHunt");
// System.out.println("ScavengerHuntRunnable.constructor: starting....");
panel = new JPanel(new BorderLayout());
graphicArea = new ScavengerHuntDisplay(GRAPHIC_WIDTH, GRAPHIC_HEIGHT);
JPanel buttonPanel = new JPanel();
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
graphicArea.clear();
// TBD ------- TBD
// Reset actions here
initializeScavengerData();
//JOptionPane.showMessageDialog(null, "Reset needs to be implemented!" );
}
});
buttonPanel.add(resetButton);
panel.add(graphicArea, BorderLayout.CENTER);
panel.add(buttonPanel, BorderLayout.SOUTH);
// Snippet by Pete Sanderson, 2 Nov. 2006, to be a window-closing sequence
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
frame.setVisible(false);
frame.dispose();
}
});
frame.getContentPane().add(panel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
frame.setTitle(" This is the ScavengerHunt");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // TBD --- This should close only the Tool, not the entire MARS
frame.setPreferredSize(new Dimension(GRAPHIC_WIDTH, GRAPHIC_HEIGHT)); // TBD SIZE
frame.setVisible(true); // show();
} // end ScavengerHuntRunnable() constructor
public void run()
{
double tempAngle;
// infinite loop: play the Scavenger Hunt game
do
{
// Pause to slow down the redisplay of the game. This is separate from
// the execution speed of the MIPS program, so the display may lag behind
// the state of the MIPS program.
try
{
// System.out.println(" Hello from the ScavengerHuntRunnable runner, sleeping here ...");
// System.out.print(".");
Thread.sleep(100); // millisec
}
catch (InterruptedException exception)
{// no action
}
panel.repaint(); // show new ScavengerHunt position
} while (true);
} // end run method of ScavengerHuntRunnable class
} // end ScavengerHuntRunnable class
/* ------------------------------------------------------------------------- */
/** ScavengerHuntDisplay does not have access to the same MIPS Memory class object used by
* the ScavengerHunt class object. Need read-only access to a similar data structure maintained
* within ScavengerHunt.
*
*/
private class ScavengerHuntDisplay extends JPanel
{
private int width;
private int height;
private boolean clearTheDisplay = true;
public ScavengerHuntDisplay(int tw, int th)
{
// System.out.println("ScavengerHuntDisplay.constructor: starting....");
width = tw;
height = th;
}
public void redraw()
{
repaint();
}
public void clear()
{
// clear the graphic display
clearTheDisplay = true;
//System.out.println("ScavengerHuntDisplay.clear: called to clear the display");
repaint();
}
/** paintComponent does not have access to the same MIPS Memory class object used by
* the ScavengerHunt class object. Need read-only access to a similar data structure maintained
* within ScavengerHunt.
*
*/
public void paintComponent(Graphics g)
{
long tempN;
int xCoord;
int yCoord;
// System.out.println("ScavengerHuntDisplay.paintComponent: I'm painting! n is " + n);
// Recover Graphics2D
Graphics2D g2 = (Graphics2D) g;
if (! GameOn) // Make sure game is ready before continuing
{
g2.setColor(Color.lightGray);
g2.fillRect(0, 0, width - 1, height - 1); // Clear all previous drawn information
g2.setColor(Color.black);
g2.drawString(" ScavengerHunt not yet initialized by MIPS administrator program.",
100, 200);
return;
}
// Clear all previous drawn information
g2.setColor(Color.lightGray);
g2.fillRect(0, 0, width - 1, height - 1);
// Draw the locations to which the players will be moving
// All players have the same location data.
for (int i = 0; i < NUM_LOCATIONS; i++)
{
xCoord = loc[i].X; // toolReadPlayerData(0, OFFSET_LOC_ARRAY + (i*8) + 0);
yCoord = loc[i].Y; // toolReadPlayerData(0, OFFSET_LOC_ARRAY + (i*8) + 4);
g2.setColor(Color.blue);
g2.fillRect( xCoord, yCoord, 20, 20); // coord is upper left corner of oval
g2.setColor(Color.white);
g2.drawString(" " + i, xCoord + 4, yCoord + 15); // coord is lower left corner of string text box
/*
System.out.println("ScavengerHuntDisplay.paintComponent: drew loc " + i + " at (" +
xCoord +
", " +
yCoord +
")" );
*/
}
//System.out.println("ScavengerHuntDisplay.paintComponent: special exit!");
//System.exit(0);
// Draw scoreboard
g2.setColor(Color.black);
g2.drawString("Player", width - 160, 30);
g2.drawString("Locations", width - 110, 30);
g2.drawString("Energy", width - 50, 30);
g2.drawLine( width - 160, 35, width - 10, 35); // line under column headings
g2.drawLine( width - 120, 35, width - 120, 35 + (NUM_PLAYERS * 15)); // vertical line for location-visited marks
g2.drawLine( width - 50, 35, width - 50, 35 + (NUM_PLAYERS * 15)); // vertical line for location-visited marks
for (int i = 0; i < NUM_PLAYERS; i++)
{
// Draw player's symbol
g2.setColor( new Color(pd[i].getColor()) );
// g2.setColor(Color.red); // TBD hardcoded
xCoord = pd[i].getWhereAmIX();
yCoord = pd[i].getWhereAmIY();
// ystem.out.println("paintComponent loop " + i + ": Loc coord is (" + xCoord + ", " + yCoord);
// Draw player symbol and label it with player ID number.
// Hardcoded size of location graphic and label.
g2.drawOval( xCoord, yCoord, 20, 20); // coord is upper left corner of oval
g2.drawString(" " + i, xCoord + 4, yCoord + 15); // coord is lower left corner of string text box
// Draw player's info on scoreboard
g2.setColor(Color.black);
g2.drawString(" " + i, width - 150, 50 + (i*15)); // Player's ID on scoreboard
g2.drawString(" " + pd[i].getEnergy(), width - 40, 50 + (i*15)); // Player's energy on scoreboard
// Display player's progress or finishing time, whichever is applicable
if (pd[i].isFinished())
{
// Display finishing time
// This doesn't display leading zeroes to align time components (e.g. 27 millisec ought to print as 027)
g2.drawString (pd[i].getFinishMin() + ":" + // Minutes
pd[i].getFinishSec() + ":" + // Seconds
pd[i].getFinishMillisec() , // Milliseconds
width - 115, 50 + (i*15));
// System.out.println("Time is " + pd[i].getFinishTime());
//g2.drawString (" " + pd[i].getFinishTime(),
// width - 255, 50 + (i*15));
}
else // player either has not finished or is just now finishing
{
int visCount = 0;
for (int j = 0; j < NUM_LOCATIONS; j++)
{
if (pd[i].hasVisited(j)) // count number of locations that player has visited
{
visCount++;
}
}
if (visCount == NUM_LOCATIONS) // player has visited every location -- finished!
{
pd[i].setFinished();
pd[i].setFinishTime( System.currentTimeMillis() - startTime );
}
else // player has not yet visited every location
{
// Display locations that the player has actually visited
for (int j = 0; j < NUM_LOCATIONS; j++)
{
if (pd[i].hasVisited(j)) // Player has visited this location
{
g2.fillRect ((width -120)+(j*10), 42 + (i*15), 10, 8);
}
}
}
} // end player had not previously finished
} // end display score/results for each player
// System.out.println("paintComponent: Player " + 0 + " is at (" + pd[0].getWhereAmIX() + ", " + pd[0].getWhereAmIY() + ")" );
/*
g2.setColor(Color.blue);
g2.setFont(new Font(g2.getFont().getName(), g2.getFont().getStyle(), 20) ); // same font and style in larger size
g2.drawOval( width/2 - 30, // TBD Hardcoded oval size
height/2 - 30,
60,
60);
g2.drawString(" " + n, width/2, height/2);
*/
}
} // end private inner class ScavengerHuntDisplay
/* ------------------------------------------------------------------------- */
// A constructor for ScavengerHunt would be called immediately on MARS startup, perhaps
// before all MARS classes have been created. Do not include any action in a constructor
// but rather postpone any action until the action() class,
// at which time all MARS classes will be ready for use.
public ScavengerHunt()
{
// System.out.println("ScavengerHunt.constructor: starting....");
}
public String getName()
{
return "ScavengerHunt";
}
/*
* This will set up the ScavengerHunt's GUI. Invoked when ScavengerHunt menu item selected.
*/
public void action()
{
ScavengerHuntRunnable shr = new ScavengerHuntRunnable();
Thread t1 = new Thread(shr);
t1.start();
// Register as observer for a particular MIPS data range. Other ranges
// are not used by this Tool.
try {
Globals.memory.addObserver(this, 0xffff8000, 0xfffffff0); // must be on word boundaries
}
catch (AddressErrorException e)
{
System.out.println("\n\nScavengerHunt.action: Globals.memory.addObserver caused AddressErrorException.\n\n");
System.exit(0);
}
} // end ScavengerHunt.action()
/*
* This method observes MIPS memory for directives to modify ScavengerHunt activity (that is,
* MIPS program write to MMIO) and updates instance variables to reflect that directive.
* This method takes action when it "observes" MIPS memory changes -- but this method
* must not write to those memory locations in order to prevent an infinite cycle of events.
* This method observes certain locations and then may (and does) write to OTHER locations.
*/
public void update(Observable o, Object arg)
{
MemoryAccessNotice notice;
int address;
int data;
boolean isWrite;
boolean isRead;
int energyLevel;
// Here we are only interested in MemoryAccessNotice. For anything else, just return.
if ( ! (arg instanceof MemoryAccessNotice))
return;
// Get pertinent information about this MemoryAccessNotice.
notice = (MemoryAccessNotice) arg;
address = notice.getAddress();
data = notice.getValue();
isWrite = (notice.getAccessType() == AccessNotice.WRITE);
isRead = ! isWrite;
// If we are only interested in MIPS memory WRITES, then just return on READS.
// That's a matter of policy: perhaps players should be prohibited from
// reading each other's memory spaces.
if ( ! isWrite)
return;
//System.out.println("ScavengerHunt.update: observed write access by player " + playerID + " on Mem[ " +
// Binary.intToHexString(address) + " ]");
// TBD TBD DEBUGGING SPECIAL
/*
accessCounter++;
if (accessCounter > 100000)
{
System.out.println("\n\nScavengerHunt.update: hardcoded exit to prevent runaway" );
System.exit(0);
}
*/
// TBD TBD DEBUGGING SPECIAL
// Take the appropriate action, depending on data written and priority of user.
if (isWrite && playerID == ADMINISTRATOR_ID && address == ADDR_GAME_ON)
{
// ADMINISTRATOR_ID can write to any location, because it's trusted software
//System.out.println( "ScavengerHunt.update(): Administrator wrote to Mem[ " +
// Binary.intToHexString(address) + " ] == " + Binary.intToHexString(data) );
// No need to authenticate since administrator runs first, then
// this location has no effect thereafter.
GameOn = true;
// System.out.println( "ScavengerHunt.update(): Administrator wrote GAME_ON!" );
initializeScavengerData();
}
else if (isWrite && address == ADDR_AUTHENTICATION)
{
// Anyone is allowed to write to the authentication location -- but if that value is not
// correct (authentic) then action can be taken.
// NO ACTION HERE
}
else if (isWrite && address == ADDR_NUM_TURNS)
{
// Anyone is allowed to write to the "number of turns" location
// NO ACTION HERE
}
else if (isWrite && address == ADDR_PLAYER_ID) // if the data written will change the PlayerID, authenticate the write
{
// 2006 Oct 31 dummy validation scheme, suitable for distribution
// to students for development: Initial authentication value is zero.
// Each successive authentication value is one greater
// than the preceding value, modulo 0xffffffff.
authenticationValue += 1; // "server's" updated version of the authenticationValue
if (toolGetWord(ADDR_AUTHENTICATION) == authenticationValue) // Compare to "client's" version of the authenticationValue
{
playerID = toolGetWord(ADDR_PLAYER_ID); // Use the new player ID
//System.out.println( "ScavengerHunt.update(): New playerID of " + playerID);
}
else
{
System.out.println( "ScavengerHunt.update(): Invalid write of player ID! \nPlayer " +
playerID + " tried to write. Expected: " +
Binary.intToHexString(authenticationValue) +
", got: " + Binary.intToHexString(toolGetWord(ADDR_AUTHENTICATION)) + "\n" );
}
}
else if (isWrite &&
address == (ADDR_BASE + (playerID * MEM_PER_PLAYER) + OFFSET_MOVE_READY) &&
data != 0) // Player wrote data to his/her assigned MoveReady location
{
/*
System.out.println(" ******** ScavengerHunt.update: Player " + playerID + " requests move to (" +
toolReadPlayerData(playerID, OFFSET_MOVE_TO_X) + ", " +
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y) + ")" );
*/
energyLevel = toolReadPlayerData(playerID, OFFSET_ENERGY); // find if player has energy
if (energyLevel <= 0) // No energy. Player not allowed to move
{
//JOptionPane.showMessageDialog(null, "Player " + playerID + " can't move -- no energy.\n" +
// "(This msg. in ScavengerHunt.update()" );
// System.out.println("Player " + playerID + " can't move -- no energy.");
return;
}
if (toolReadPlayerData(playerID, OFFSET_MOVE_TO_X) < 0 ||
toolReadPlayerData(playerID, OFFSET_MOVE_TO_X) > GRAPHIC_WIDTH ||
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y) < 0 ||
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y) > GRAPHIC_HEIGHT
) // Out of bounds. Player not allowed to move
{
//JOptionPane.showMessageDialog(null, "Player " + playerID + " can't move -- out of bounds.\n" +
// "(This msg. in ScavengerHunt.update()" );
System.out.println("Player " + playerID + " can't move -- out of bounds.");
return;
}
// Verify movement is allowed (does not exceed maximum movement)
if (Math.sqrt(
Math.pow( toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_X) -
toolReadPlayerData(playerID, OFFSET_MOVE_TO_X), 2.0)
+
Math.pow( toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_Y) -
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y), 2.0) )
<= MAX_MOVE_DISTANCE)
{
// Write the new position of the player
toolWritePlayerData(playerID, OFFSET_WHERE_AM_I_X,
toolReadPlayerData(playerID, OFFSET_MOVE_TO_X));
toolWritePlayerData(playerID, OFFSET_WHERE_AM_I_Y,
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y));
pd[playerID].setWhereAmI( toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_X),
toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_Y) );
// Write the new (reduced) energy of the player
// Policy: Constant ENERGY_PER_MOVE for any move regardless of length.
toolWritePlayerData(playerID, OFFSET_ENERGY,
toolReadPlayerData(playerID, OFFSET_ENERGY) - ENERGY_PER_MOVE);
pd[playerID].setEnergy( toolReadPlayerData(playerID, OFFSET_ENERGY) );
// TBD FUTURE --- need to keep track of locations that the player has actually got to
// -- be able to tell that the player has reached a certain location
// -- be able to tell that the player has reached every location
for (int i = 0; i < NUM_LOCATIONS; i++)
{
if (toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_X) == loc[i].X &&
toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_Y) == loc[i].Y )
{
pd[playerID].setVisited(i); // Player has visited this location
}
}
// Write 0 to "move ready" location, signifying that the move request was processed
// Here we must write to the same location that we're now reading from, and we
// can't cause an infinite loop. Temporarily switch player ID to that of the administrator,
// and restore ID after the write. With the playerID set to administrator, the event
// caused by the write will not go through this same logic.
int tempPlayerID = playerID;
playerID = ADMINISTRATOR_ID;
toolWritePlayerData(tempPlayerID, OFFSET_MOVE_READY, 0);
playerID = tempPlayerID;
}
else
{
System.out.println( "Player " + playerID + " can't move -- exceeded max. movement." );
System.out.println(" Player is at (" +
toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_X) + ", " +
toolReadPlayerData(playerID, OFFSET_WHERE_AM_I_Y) + "), wants to go to (" +
toolReadPlayerData(playerID, OFFSET_MOVE_TO_X) + "," +
toolReadPlayerData(playerID, OFFSET_MOVE_TO_Y) + ")" );
return;
}
} // end if Player wrote nonzero data to his/her assigned MoveReady location
else if (isWrite &&
address == (ADDR_BASE + (playerID * MEM_PER_PLAYER) + OFFSET_TASK_COMPLETE) &&
data != 0) // Player wrote data to his/her assigned TaskComplete location
{
// System.out.println(" ******** ScavengerHunt.update: Player " + playerID + " requests more energy (task complete)" );
// Player indicates he/she has completed a task. Check to see if task is completed correctly.
// Task for this assignment: Numbers are sorted in ascending order.
int prevData, currentData;
prevData = toolReadPlayerData(playerID, OFFSET_TASK_ARRAY);
for (int i = 1; i < SIZE_OF_TASK; i++)
{
currentData = toolReadPlayerData(playerID, OFFSET_TASK_ARRAY + (i*4));
if (prevData > currentData)
{
// Task failure! Task not completed correctly!
System.out.println("Whoops! Player has NOT completed task correctly");
return;
}
prevData = currentData; // update for next iteration
}
// If program flow has reached this point, the task is completed correctly.
// Award energy, reset TaskComplete, and set new task values for future use.
toolWritePlayerData(playerID, OFFSET_ENERGY, ENERGY_AWARD);
toolWritePlayerData(playerID, OFFSET_TASK_COMPLETE, 0);
for (int j = 0; j < SIZE_OF_TASK; j++) // Initialize the task data for this player
{
toolWritePlayerData(playerID, OFFSET_TASK_ARRAY + (j * 4),
(int)(randomStream.nextDouble() * Integer.MAX_VALUE) ); // Set a random number for the task (sort them)
}
// System.out.println("Player has completed task correctly and been awarded energy");
pd[playerID].setEnergy( ENERGY_AWARD );
} // end if Player wrote nonzero data to his/her assigned TaskComplete location
else if (isWrite &&
address == (ADDR_BASE + (playerID * MEM_PER_PLAYER) + OFFSET_PLAYER_COLOR))
// Player wrote data to his/her assigned PlayerColor location
{
// PPlayer indicates he/she has changed the color of display
pd[playerID].setColor( toolReadPlayerData(playerID, OFFSET_PLAYER_COLOR) );
}
// TBD TBD TBD
// TBD TBD TBD
// TBD TBD TBD
// Yet to be implemented: Enforce only one write of MoveRequest per player per turn
else if (isWrite &&
address >= (ADDR_BASE + (playerID * MEM_PER_PLAYER)) &&
address < (ADDR_BASE + ((playerID + 1) * MEM_PER_PLAYER)) )
// Player wrote data elsewhere within his/her assigned location
{
// Player can write to any location within his/her assigned location
//System.out.println( "ScavengerHunt.update(): Player " + playerID + " wrote to valid location");
}
else if (isWrite && playerID == ADMINISTRATOR_ID)
{
// ADMINISTRATOR_ID can write to any location, because it's trusted software
//System.out.println( "ScavengerHunt.update(): Administrator wrote to Mem[ " +
// Binary.intToHexString(address) + " ] == " + Binary.intToHexString(data) );
}
else if (isWrite)
{
// This player is writing outside his/her assigned memory location
/*
System.out.println("ScavengerHunt.update(): Player " + playerID + " writing outside assigned mem. loc. at address " +
Binary.intToHexString(address) +
" -- not implemented!");
*/
JOptionPane.showMessageDialog(null,
"ScavengerHunt.update(): Player " + playerID + " writing outside assigned mem. loc. at address " +
Binary.intToHexString(address) +
" -- not implemented!");
}
else if (isRead)
{
// Policy: anyone can read any location.
}
} // end ScavengerHunt.update()
// Write one word to MIPS memory. This is a wrapper to isolate the try..catch blocks.
private void toolSetWord(int address, int data)
{
if (KENVDEBUG)
{
System.out.println(" ScavengerHunt.toolSetWord: Setting MIPS Memory[" +
Binary.intToHexString(address) + "] to " + Binary.intToHexString(data) + " = " + data );
}
SetWordCounter++;
try {
Globals.memory.setWord(address, data); // Write
}
catch ( AddressErrorException e) {
System.out.println("ScavengerHunt.toolSetWord: deliberate exit on AEE exception.");
System.out.println(" SetWordCounter = " + SetWordCounter);
System.out.println(" address = " + Binary.intToHexString(address) );
System.out.println(" data = " + data );
System.exit(0);
}
catch ( Exception e) {
System.out.println("ScavengerHunt.toolSetWord: deliberate exit on " + e.getMessage() + " exception.");
System.out.println(" SetWordCounter = " + SetWordCounter);
System.out.println(" address = " + Binary.intToHexString(address) );
System.out.println(" data = " + data );
System.exit(0);
}
if (KENVDEBUG)
{
// Verify data written correctly
int verifyData = toolGetWord(address);
if (verifyData != data)
{
System.out.println("\n\nScavengerHunt.toolSetWord: Can't verify data! Special exit.");
System.out.println(" address = " + Binary.intToHexString(address) );
System.out.println(" data = " + data);
System.out.println(" verifyData = " + verifyData);
System.exit(0);
}
else
System.out.println(" ScavengerHunt.toolSetWord: Mem[" +
Binary.intToHexString(address) +
" verified as " + Binary.intToHexString(data));
}
} // end toolSetWord
// Read one word from MIPS memory. This is a wrapper to isolate the try..catch blocks.
private int toolGetWord(int address)
{
int returnValue;
//System.out.println("ScavengerHunt.toolGetWord: called with address " +
// Binary.intToHexString(address) );
try {
/*
System.out.println("ScavengerHunt.toolGetWord: returning " +
Binary.intToHexString(Globals.memory.getWord(address)) +
" which is at MIPS Memory[" + Binary.intToHexString(address) + "]" );
*/
returnValue = Globals.memory.getWord(address);
/*
System.out.println("ScavengerHunt.toolGetWord: Mem[" +
Binary.intToHexString(address) + "] = " +
Binary.intToHexString(returnValue) + " --- returning normally");
*/
return returnValue;
}
catch ( AddressErrorException e) {
System.out.println("ScavengerHunt.toolGetWord: deliberate exit on AEE exception.");
System.out.println(" SetWordCounter = " + SetWordCounter);
System.out.println(" address = " + Binary.intToHexString(address) );
System.exit(0);
}
catch ( Exception e) {
System.out.println("ScavengerHunt.toolGetWord: deliberate exit on " + e.getMessage() + " exception.");
System.out.println(" SetWordCounter = " + SetWordCounter);
System.out.println(" address = " + Binary.intToHexString(address) );
System.exit(0);
}
return 0; // Must have return statement
} // end toolGetWord
// Read player's data field.
private int toolReadPlayerData(int p, int offset)
{
if (KENVDEBUG)
{
System.out.println("ScavengerHunt.toolReadPlayerData: called with player " + p +
", offset = " +
Binary.intToHexString(offset) + " ---> address " +
Binary.intToHexString(ADDR_BASE + (p * MEM_PER_PLAYER) + offset)
);
}
int returnValue = toolGetWord( ADDR_BASE + (p * MEM_PER_PLAYER) + offset);
if (KENVDEBUG)
{
//if ((ADDR_BASE + (p * MEM_PER_PLAYER) + offset) >= 0xffff8000 &&
// (ADDR_BASE + (p * MEM_PER_PLAYER) + offset) < 0xffff8800) // Show debug for player 0 and 1 only
//{
//System.out.println(" ScavengerHunt.toolReadPlayerData: Reading MIPS Memory[" +
// Binary.intToHexString(ADDR_BASE + (p * MEM_PER_PLAYER) + offset) +
// "] which is " + Binary.intToHexString(returnValue) +
// " = " + Binary.intToHexString( returnValue) );
//}
System.out.println("ScavengerHunt.toolReadPlayerData: Mem[" +
Binary.intToHexString(ADDR_BASE + (p * MEM_PER_PLAYER) + offset) + "] = " +
Binary.intToHexString(returnValue) + " --- returning normally");
}
return returnValue;
} // end toolReadPlayerData
// Write player's data field.
private void toolWritePlayerData(int p, int offset, int data)
{
int address = ADDR_BASE + (p * MEM_PER_PLAYER) + offset;
if (KENVDEBUG)
{
System.out.println("ScavengerHunt.toolWritePlayerData: called with player " + p +
", offset = " + Binary.intToHexString(offset) +
", data = " + Binary.intToHexString(data) );
}
toolSetWord( address, data);
if (KENVDEBUG)
{
int verifyData = toolGetWord(address);
if (data != verifyData)
{
System.out.println("\n\nScavengerHunt.toolWritePlayerData: MAYDAY data not verified !");
System.out.println(" requested data to be written was " + Binary.intToHexString(data));
System.out.println(" actual data at that loc is " + Binary.intToHexString(toolGetWord(address)));
System.exit(0);
}
else
System.out.println(" ScavengerHunt.toolWritePlayerData: Mem[" +
Binary.intToHexString(address) +
" verified as " + Binary.intToHexString(data));
}
} // end toolWritePlayerData
private void initializeScavengerData()
{
//GameOn = false; // MIPS programs readiness
authenticationValue = 0;
playerID = ADMINISTRATOR_ID;
startTime = System.currentTimeMillis(); // Clock time for program run
// This is a dubious use of the tool (this Java program) to initialize data values for the game.
// The administrator portion of the MIPS program should initialize all data for each
// player -- but it's easier to work with random numbers in the Java program
// Initialize the locations and task data for each player
randomStream = new Random(42); // TBD Use a seed for development. Remove seed for randomizing.
for (int j = 0; j < NUM_LOCATIONS - 1; j++) // The first (n-1) locations are "random"
{ // Two coordinates (x and y) for each location
loc[j] = new Location(); // Initialize each location element
loc[j].X = (int)(randomStream.nextDouble() * GRAPHIC_WIDTH); // X coord.
loc[j].Y = (int)(randomStream.nextDouble() * (GRAPHIC_HEIGHT - 50)); // Y coord. (leave room for buttons in window)
/*
System.out.println("ScavengerHunt.update(): set up a location at (" +
loc[j].X +
", " +
loc[j].Y +
")" );
*/
}
loc[NUM_LOCATIONS - 1] = new Location(); // The last location is a return to the starting position
loc[NUM_LOCATIONS - 1].X = START_AND_END_LOCATION;
loc[NUM_LOCATIONS - 1].Y = START_AND_END_LOCATION;
for (int i = 0; i < NUM_PLAYERS; i++) // Initialize data for each player
{
//System.out.println("ScavengerHunt.update(): Player loop " + i);
pd[i] = new PlayerData(); // Initialize each player data structure.
for (int j = 0; j < NUM_LOCATIONS; j++) // Initialize the locations this player goes to
{
toolWritePlayerData(i, OFFSET_LOC_ARRAY + (j * 8) + 0, loc[j].X); // Set the same locations for each player
toolWritePlayerData(i, OFFSET_LOC_ARRAY + (j * 8) + 4, loc[j].Y); // Set the same locations for each player
}
for (int j = 0; j < SIZE_OF_TASK; j++) // Initialize the task data for this player
{
toolWritePlayerData(i, OFFSET_TASK_ARRAY + (j * 4),
(int)(randomStream.nextDouble() * Integer.MAX_VALUE) ); // Set a random number for the task (sort them)
}
}
} // end initializeScavengerData
} // end ScavengerHunt