流行病毒传染模拟仿真实验

流行病毒传染模拟仿真实验

共有三个java文件,请根据注释提醒,补充程序并完成仿真实验。

Epidemic.java(主类)

/**
 * 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
    }

}

2. WorldViewer.java

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;
        }
    }

}

3. Config.java

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;

}

猜你喜欢

转载自blog.csdn.net/cnlht/article/details/81751122
今日推荐