共有三個java文件,請根據註釋提醒,補充程序並完成仿真實驗。html
/** * Main class for simulating an epidemic. The simulation consists of a "world" * (a square matrix of cells, or ints). Each cell can be empty or contains an * individual. The state of a cell is denoted by its integer value in the array. * The value {@code Config.EMPTY} (which is 0) indicates an empty cell. * Each individual can be in one of the following states: * <ul> * <li><b>Uninfected</b>. This individual has never been infected with the * disease. This is indicated by the value {@code Config.UNINFECTED}, * which is -1. * <li><b>Recovered</b>. This individual was infected with the disease but is * no longer infected. This is indicated by the value * {@code Config.RECOVERED}, which is. Once recovered, an individual can * never again become infected. * <li><b>Infected</b>. This individual currently has the disease. This is * indicated by an integer value greater than 1. The higher this value, * the longer the period will be before this individual switches to the * RECOVERED state. If the value is less than or equal to * {@code Config.CONTAGIOUS}, the individual is contagious and can * spread their disease to others. * </ul> * * <p><b>Remember to use the constants from the {@code Config} class * directly. DO NOT hard-code constant values from the Config class.</b> You * will lose points if you do this. */
public class Epidemic {
//////////////////////////////////////////////////////////////////////
// A NOTE ON USING THIS SKELETON.
// We have provided many comments below to outline how your program
// should work. We do not, however, provide a comment describing
// every piece of code you will have to write. You may find that you
// need to add additional code to fully support the functionality
// required by the comments.
//////////////////////////////////////////////////////////////////////
/** * Application entry point. Runs an epidemic simulation to completion, * displaying the results after each step using a {@code WorldViewer} * object. Each step in the simulation consists of the following sub-steps: * <ol> * <li>Move individuals around in the world. * <li>Decrement infected individuals to represent the passage of time. * <li>Spread disease from contagious to uninfected individuals. * </ol> * * <p>At the end of each simulation step (that is, after each spread-disease * substep), you should display the current simulation state by calling * {@code Config.VIEWER.showWorld()} and passing the correct arguments. * This will update the picture displayed on the window. * * <p>The simulation is complete once there are no more infected * individuals. * * @param args Command-line arguments (ignored). */
public static void main(String[] args) {
// TODO
// Create a world as a 2-D array of ints. Use Config.WORLD_SIZE as
// the width and height of the world. The cells in the array will
// default to 0, which equals Config.EMPTY.
// Call the populateWorld method to populate the world with individuals.
// You may want to declare some variables to keep track of the
// simulation state. This will help you determine when the simulation is
// complete.
// Loop until there are no more infected individuals in the world.
// Call the move method to move individuals around in the world.
// Call the decrement method to advance the state of all infected
// individuals in the world.
// Call the spreadDisease method to spread disease from contagious
// to uninfected individuals.
// Update the viewer by calling Config.VIEWER.showWorld() and
// passing the appropriate information as arguments.
}
/** * Populates the given world with uninfected and infected individuals, as * specified by {@code Config.INITIAL_UNINFECTED_COUNT} and * {@code Config.INITIAL_INFECTED_COUNT}. * * @param world World to populate. */
public static void populateWorld(int[][] world) {
//world = new int [89][89];
//INITIAL_UNINFECTED_COUNT {@code Config.INITIAL_UNINFECTED_COUNT}
//{@code Config.INITIAL_INFECTED_COUNT}
// TODO
// Populate the world with the correct number
// (Config.INITIAL_UNINFECTED_COUNT) of uninfected individuals. Use
// a loop to call the addIndividual method repeatedly to do this. The
// addIndividual method should be used to add each individual to the
// world.
// Populate world with the correct number
// (Config.INITIAL_INFECTED_COUNT) of infected individuals. Again,
// use a loop to repeatedly call the addInviddual method.
}
/** * Adds an individual to the simulation world. This should be done by * randomly selecting an EMPTY cell in the world. That cell's value should * then be changed to the specified {@code newIndividual} value. * * @param world World to add an individual to. * @param newIndividual The new value to put into the randomly selected * cell. */
public static void addIndividual(int[][] world, int newIndividual) {
// TODO
}
/** * Randomly moves individuals around in the world. This should be done by * randomly selecting pairs of adjacent cells in the array. Each such pair * should then have their values swapped. The number of pairs swapped should * equal half the number of cells in the world. * * @param world The world array. */
public static void move(int[][] world) {
// TODO
// Repeatedly call the swapRandomIndividuals method. The number of times
// you call it should be equal to half (round down) of the total number
// of cells in the world.
}
/** * Randomly swaps two adjacent individuals. * * @param world The world array. */
public static void swapRandomIndividuals(int[][] world) {
// TODO
// Pick a random cell in the world.
// Randomly pick one of the eight cells adjacent to this one. That is,
// if X was the cell picked earlier, randomly pick one of the A's from
// the diagram below:
// A A A
// A X A
// A A A
// Swap the values contained by the two selected cells.
}
/** * Advances the disease state of all infected individuals. If an individual * is infected, his or her state should be decremented by 1 to show the * advancement of the disease towards the RECOVERED state. Individuals who * are not infected should not be affected by the decrement method. * * @param world The world array. */
public static void decrement(int[][] world) {
// TODO
}
/** * Spreads disease from contagious individuals to adjacent UNINFECTED * individuals. For each pair of adjacent individuals, if one of them is * contagious and the other is UNINFECTED, then there is a fixed chance * ({@code Config.INFECTION_PROBABILITY}) that the UNINFECTED individual * will become contagious. * * @param world The world array. */
public static void spreadDisease(int[][] world) {
// TODO
// Loop over all the cells in the world.
// If the cell does not contain a contagious individual (note
// that it could be EMPTY), do nothing.
// If the cell does contain a contagious individual, loop over
// all eight cells that are adjacent to this contagious
// individual. In this loop, you should check each adjacent cell
// to see if it is UNINFECTED. If it is, that cell should have a
// change (Config.INFECTION_PROBABILITY) of becoming
// infected right now. To mark the cell as infected, set its
// value to Config.INFECTED.
}
/** * Wraps a world coordinate around. Using this on all coordinates means that * our world has no boundaries--individuals and infections simply wrap * around from top to bottom and from left to right. This is sometimes * called a "toroidal world". See * <a href="http://en.wikipedia.org/wiki/Torus">Wikipedia</a>. * * <p>You should call this method on any index <b>before</b> you use it to * index into the world array. That way, even cells on the edges of the * array will be considered to have eight adjacent cells. For example, * consider the cell marked "X" below: * <pre> * A * A A * A * A X * A * A A * * * * *</pre> * The cell "X" is adjacent to the eight cells marked "A" because the world * wraps around at the edges. * * @param size Size of the world. * @param coord Coordinate to be wrapped. * @return The wrapped version of the coordinate. */
public static int wrap(int size, int coord) {
// What you want to do here is take an input coord that is potentially
// outside the bounds of the world array and wrap it around so it falls
// within the bounds of the array. There are two ways that the coord can
// be outside the bounds of the world array:
// (1) it can be greater than or equal to size
// (2) it can be less than or equal to -1
// In the first case, we want to subtract the size from the coord to
// bring it within the legal range. In the second case, we want to add
// the size to the coord to bring it within the legal range. You can do
// this with loops and if statements, or you can do it much more
// elegantly using the modulus operator (%), which takes the remainder
// of its first argument after integer division by its second argument.
return 0; // TODO
}
}
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Arrays;
import java.util.concurrent.locks.*;
import javax.swing.*;
/** * Provides a graphical user interface (GUI) for displaying a world in the * epidemic simulation. The world is displayed * as a grid of cells. Empty cells will show up as empty (black) in the grid. * Uninfected individuals appear as small blue dots, infected individuals appear * as large red dots, and recovered individuals appear as small pink dots. * The viewer does not distinguish between contagious and non-contagious * infected individuals; that is, it displays all infected individuals as large * red dots. * * <p>The viewer also shows the integer values passed to its {@link #showWorld} * method: * <ol> * <li>The number of simulation steps executed so far. * <li>The current count of uninfected individuals. * <li>The current count of infected individuals. * <li>The current count of recovered individuals. * </ol></p> * * <p><b>DO NOT EDIT THIS FILE.</b> You should put all your code for this * assighnment in Epidemic.java.</p> * * @author pollen */
public class WorldViewer {
private Snapshot current, previous, next;
private final JFrame frame;
private final JButton stepForwardButton;
private final JButton stepBackButton;
private final JLabel stepsLabel;
private final JLabel uninfectedLabel;
private final JLabel infectedLabel;
private final JLabel recoveredLabel;
/** Number of milliseconds to pause after each showWorld call. */
private final int frameDuration;
private final boolean enable;
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
/** * Creates a new WorldViewer for use in students' code. The window will not * be shown until the showWorld method is called at least once. */
public WorldViewer() {
this(40, true);
}
/** * Creates a new WorldViewer. The window will not be shown until the * showWorld method is called at least once. * * <p><b>Students' code should not call this constructor. It is for testing * purposes only.</b> * * @param frameDuration Number of milliseconds to pause after showing each * frame. */
public WorldViewer(int frameDuration, boolean enable) {
this.frameDuration = frameDuration;
this.enable = enable;
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Epidemic Simulation");
frame.setSize(800, 600);
frame.setLocation(100, 100);
JPanel pane = new JPanel();
pane.setLayout(new BorderLayout());
frame.setContentPane(pane);
pane.add(new WorldPane(), BorderLayout.CENTER);
JPanel status = new JPanel();
status.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
status.setLayout(new GridLayout(1, 6));
pane.add(status, BorderLayout.SOUTH);
stepBackButton = new JButton("<< Step");
stepBackButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
stepBack();
}});
stepBackButton.setEnabled(false);
status.add(stepBackButton);
stepForwardButton = new JButton("Step >>");
stepForwardButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
stepForward();
}});
stepForwardButton.setEnabled(false);
status.add(stepForwardButton);
stepsLabel = new JLabel();
status.add(stepsLabel);
uninfectedLabel = new JLabel();
status.add(uninfectedLabel);
infectedLabel = new JLabel();
status.add(infectedLabel);
recoveredLabel = new JLabel();
status.add(recoveredLabel);
}
private void stepForward() {
if (next != null) {
showWorld(next, true, true);
} else {
runSimulation();
}
}
private void stepBack() {
showWorld(previous, true, false);
}
/** Wakens the sleeping simulation to run another step. */
private void runSimulation() {
lock.lock();
try {
cond.signalAll();
} finally {
lock.unlock();
}
}
/** Pauses the simulation. */
private void pauseSimulation(boolean await) {
if (await) {
lock.lock();
try {
cond.await();
} catch (InterruptedException e) {
// Empty.
} finally {
lock.unlock();
}
} else {
try {
Thread.sleep(frameDuration);
} catch (InterruptedException e) {
// Empty.
}
}
}
/** * Displays the current state of the simulated world on the GUI window. * * @param world Matrix of tiles that make up the world. * @param stepsTaken Number of steps that have been taken so far in this * simulation. * @param numUninfected Current number of uninfected individuals in the * simulation. * @param numInfected Current number of infected individuals in the * simulation. * @param numRecovered Current number of recovered individuals in the * simulation. * @param pause True to pause the simulation until the user hits the "Step" * button. False to keep running without requiring the user to hit * the "Step" button. Feel free to pass either {@code true} or {@code * false} here. The <a href= * "http://pages.cs.wisc.edu/~cs302/programs/p2/example-video.html"> * example video</a> was generated with {@code pause} set to {@code * false}. */
public void showWorld(
int[][] world,
int stepsTaken,
int numUninfected,
int numInfected,
int numRecovered,
boolean pause
) {
showWorld(new Snapshot(
world,
stepsTaken,
numUninfected,
numInfected,
numRecovered),
pause, true);
pauseSimulation(pause);
}
private void showWorld(
Snapshot newSnapshot,
boolean await,
boolean forward) {
if (forward) {
previous = current;
next = null;
} else {
previous = null;
next = current;
}
current = newSnapshot;
stepForwardButton.setEnabled(next != null || await);
stepBackButton.setEnabled(previous != null && await);
update();
}
/** Updates the painted display based on the current Snapshot. */
private void update() {
if (enable) {
stepsLabel.setText(String.format(
" Steps: %d", current.stepsTaken));
uninfectedLabel.setText(String.format(
" Uninfected: %d", current.numUninfected));
infectedLabel.setText(String.format(
" Infected: %d", current.numInfected));
recoveredLabel.setText(String.format(
" Recovered: %d", current.numRecovered));
frame.setVisible(true); // Make sure the window is shown.
frame.repaint();
}
}
/** * Prints a representation of the current state of the world to System.out. * While your program is not required to ever call this method, you may find * it useful for debugging purposes. * <ul> * <li>Empty cells are represented by a space. * <li>Uninfected cells are represented by a period (.). * <li>Recovered cells are represented by a star (*). * <li>Infected cells are represented by an at-sign (@). * </ul> * * @param world World array to print. */
public static void printWorld(int[][] world) {
for (int i = 0; i < world.length; i++) {
for (int j = 0; j < world[i].length; j++) {
char c;
switch (world[i][j]) {
case Config.EMPTY:
c = ' ';
break;
case Config.UNINFECTED:
c = '.';
break;
case Config.RECOVERED:
c = '*';
break;
default:
c = '@';
break;
}
System.out.print(c + " ");
}
System.out.println();
}
}
/** * Gets the current number of uninfected individuals, based on the values * that were passed into {@code showWorld}. * * <p><b>Students' code should not call this method. It is for testing * purposes only.</b> */
public int getUninfectedCount() {
return current == null ? 0 : current.numUninfected;
}
/** * Gets the current number of infected individuals, based on the values that * were passed into {@code showWorld}. * * <p><b>Students' code should not call this method. It is for testing * purposes only.</b> */
public int getInfectedCount() {
return current == null ? 0 : current.numInfected;
}
/** * Gets the current number of recovered individuals, based on the values * that were passed into {@code showWorld}. * * <p><b>Students' code should not call this method. It is for testing * purposes only.</b> */
public int getRecoveredCount() {
return current == null ? 0 : current.numRecovered;
}
/** * Gets the number of simulation steps executed so far, based on the values * that were passed into {@code showWorld}. * * <p><b>Students' code should not call this method. It is for testing * purposes only.</b> */
public int getStepCount() {
return current == null ? 0 : current.stepsTaken;
}
/** JPanel for painting a World on the screen. */
private class WorldPane extends JPanel {
private static final long serialVersionUID = 1L;
public WorldPane() {
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
@Override
public void paint(Graphics graphics) {
int[][] world = current.world;
Graphics2D g = (Graphics2D) graphics;
final Insets insets = getInsets();
final int width = getWidth();
final int height = getHeight();
g.setColor(Color.BLACK);
g.fillRect(0, 0, width, height);
if (world == null) {
// Leave a blank screen.
} else {
// Paint each tile in the proper location.
int size = world.length;
double tileWidth = Math.min(
width - insets.left - insets.right,
height - insets.top - insets.bottom) / (double) size;
// First paint blue and pink individuals (and gray walls, for
// the extra credit portion of the assignment) at a normal size.
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
int tile = world[row][col];
if (tile == Config.EMPTY) {
// Paint nothing.
} else if (tile == Config.WALL) {
// Paint a gray square.
g.setColor(Color.GRAY);
g.fill(new Rectangle2D.Double(
col * tileWidth + insets.left,
row * tileWidth + insets.top,
tileWidth, tileWidth));
} else {
// Choose a color based on the individual's status.
if (tile == Config.UNINFECTED) {
g.setColor(Color.CYAN);
} else if (tile == Config.RECOVERED) {
g.setColor(Color.PINK);
} else { // Infected.
continue;
}
// Paint a circle to represent the individual.
g.fill(new Ellipse2D.Double(
(col + 0.1) * tileWidth + insets.left,
(row + 0.1) * tileWidth + insets.top,
tileWidth * 0.8, tileWidth * 0.8));
}
}
}
// Now paint red individuals at a larger size.
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
int tile = world[row][col];
if (tile == Config.EMPTY) {
// Paint nothing.
} else {
// Choose a color based on the individual's status.
if (tile == Config.UNINFECTED) {
continue;
} else if (tile == Config.RECOVERED) {
continue;
} else if (tile == Config.WALL){
continue;
} else { // Infected.
g.setColor(Color.RED);
}
// Paint a circle to represent the individual.
g.fill(new Ellipse2D.Double(
(col - 0.3) * tileWidth + insets.left,
(row - 0.3) * tileWidth + insets.top,
tileWidth * 1.6, tileWidth * 1.6));
}
}
}
}
}
}
private static class Snapshot {
public final int[][] world;
public final int stepsTaken;
public final int numUninfected;
public final int numInfected;
public final int numRecovered;
public Snapshot(
int[][] world,
int stepsTaken,
int numUninfected,
int numInfected,
int numRecovered) {
this.stepsTaken = stepsTaken;
this.numUninfected = numUninfected;
this.numInfected = numInfected;
this.numRecovered = numRecovered;
this.world = copy(world);
}
/** Creates a copy of a world. */
private static int[][] copy(int[][] world) {
int[][] copy = new int[world.length][];
for (int i = 0; i < world.length; i++) {
copy[i] = Arrays.copyOf(world[i], world[i].length);
}
return copy;
}
}
}
import java.util.Random;
/** * Defines constant simulation configuration values. You should refer to these * constants in your program. Do not put these magic numbers directly into your * program's code. Instead, access them like this: {@code Config.RANDOM}, * {@code Config.INFECTED}, etc. * * <p><b>DO NOT ADD, REMOVE, OR RENAME VARIABLES IN THIS FILE.</b> You may * change values in order to test your program for different configuration * values.</p> * * @author pollen */
public class Config {
private Config() {
// This private constructor prevents anyone from ever creating an
// instance of this class.
}
/** * Random number generator to use for simulation. You may also create your * own Random objects; we just provide this one for your convenience. In * your Epidemic class, you may access it by typing {@code * Config.RANDOM}. */
public static final Random RANDOM = new Random();
/** * WorldViewer object to use for showing simulation results to the user in * a GUI (Graphical User Interface) window. Do not create additional * WorldViewer objects, as doing so will break our grading system. Use this * WorldViewer object for displaying all stages of the simulation. */
public static final WorldViewer VIEWER = new WorldViewer();
/** Value to represent an empty tile in the world. */
public static final int EMPTY = 0;
/** Value to represent an uninfected individual in the world. */
public static final int UNINFECTED = -1;
/** * Value representing a wall in the world. <b>This is only used for the * extra credit portion of the assignment.</b> If you aren't doing extra * credit, then you should ignore this constant. */
public static final int WALL = -2;
/** * Value to represent an individual who has recovered from being infected. */
public static final int RECOVERED = 1;
/** Value to represent an individual who has just become infected. */
public static final int INFECTED = 9;
/** * Value to represent an individual who is infected and contagious. Any * value less than or equal to CONTAGIOUS and greater than RECOVERED is * considered a contagious individual. */
public static final int CONTAGIOUS = 7;
/** * Probability that infection is passed between any two adjacent * individuals. */
public static final double INFECTION_PROBABILITY = 0.06;
/** * Probability that an infected individual dies during any simulation step. * <b>This is only used for the extra credit portion of the assignment.</b> * If you aren't doing extra credit, then you should ignore this constant. */
public static final double DEATH_PROBABILITY = 0.05;
/** Width and height of the world, in cells. */
public static final int WORLD_SIZE = 90;
/** Initial count of uninfected individuals in the simulation. */
public static final int INITIAL_UNINFECTED_COUNT =
(int)(WORLD_SIZE * WORLD_SIZE * 0.8);
/** Initial count of infected individuals in the simulation. */
public static final int INITIAL_INFECTED_COUNT = 5;
/** * Height of walls to create in the world. <b>This is only used for the * extra credit portion of the assignment.</b> If you aren't doing extra * credit, then you should ignore this constant. */
public static final int WALL_HEIGHT = (int)(WORLD_SIZE * 0.80);
/** * Horizontal spacing of walls to create in the world. <b>This is only used * for the extra credit portion of the assignment.</b> If you aren't doing * extra credit, then you should ignore this constant. */
public static final int WALL_SPACING = 8;
}