add Critter game assignment from WCC CS 145 Spring 2019.
This commit is contained in:
parent
63d3de5191
commit
fd6cfb770d
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Matt Jensen
|
||||||
|
* CS145
|
||||||
|
* Lab 2 - Critters
|
||||||
|
* 4/23/19
|
||||||
|
* Partners: Melissa, Devante
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Bear extends Critter {
|
||||||
|
private Color color = Color.BLACK;
|
||||||
|
private String symbol = "/";
|
||||||
|
// white if polar
|
||||||
|
public Bear(boolean polar) {
|
||||||
|
if(polar) {
|
||||||
|
this.color = Color.WHITE;
|
||||||
|
}
|
||||||
|
if( Math.random() > 0.5) {
|
||||||
|
this.changeSymbol();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//getter
|
||||||
|
public Color getColor() {
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
//getter
|
||||||
|
public String toString() {
|
||||||
|
return this.symbol;
|
||||||
|
}
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
this.changeSymbol();
|
||||||
|
Neighbor front = info.getFront();
|
||||||
|
if( front == Neighbor.OTHER ) { // check for enemy in front.
|
||||||
|
return Action.INFECT;
|
||||||
|
}
|
||||||
|
if ( front == Neighbor.EMPTY ) { // check for obstacle.
|
||||||
|
return Action.HOP;
|
||||||
|
}
|
||||||
|
return Action.LEFT;
|
||||||
|
}
|
||||||
|
// toggles between / and \
|
||||||
|
public void changeSymbol() {
|
||||||
|
if(this.symbol.equals("/")) {
|
||||||
|
this.symbol = "\\";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.symbol = "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
// This is the superclass of all of the Critter classes. Your class should
|
||||||
|
// extend this class. The class provides several kinds of constants:
|
||||||
|
//
|
||||||
|
// type Neighbor : WALL, EMPTY, SAME, OTHER
|
||||||
|
// type Action : HOP, LEFT, RIGHT, INFECT
|
||||||
|
// type Direction : NORTH, SOUTH, EAST, WEST
|
||||||
|
//
|
||||||
|
// Override the following methods to change the behavior of your Critter:
|
||||||
|
//
|
||||||
|
// public Action getMove(CritterInfo info)
|
||||||
|
// public Color getColor()
|
||||||
|
// public String toString()
|
||||||
|
//
|
||||||
|
// The CritterInfo object passed to the getMove method has the following
|
||||||
|
// available methods:
|
||||||
|
//
|
||||||
|
// public Neighbor getFront(); neighbor in front of you
|
||||||
|
// public Neighbor getBack(); neighbor in back of you
|
||||||
|
// public Neighbor getLeft(); neighbor to your left
|
||||||
|
// public Neighbor getRight(); neighbor to your right
|
||||||
|
// public Direction getDirection(); direction you are facing
|
||||||
|
// public Direction getFrontDirection(); direction of front neighbor
|
||||||
|
// public Direction getBackDirection(); direction of back neighbor
|
||||||
|
// public Direction getLeftDirection(); direction of left neighbor
|
||||||
|
// public Direction getRightDirection(); direction of right neighbor
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class Critter {
|
||||||
|
public static enum Neighbor {
|
||||||
|
WALL, EMPTY, SAME, OTHER
|
||||||
|
};
|
||||||
|
|
||||||
|
public static enum Action {
|
||||||
|
HOP, LEFT, RIGHT, INFECT
|
||||||
|
};
|
||||||
|
|
||||||
|
public static enum Direction {
|
||||||
|
NORTH, SOUTH, EAST, WEST
|
||||||
|
};
|
||||||
|
|
||||||
|
// This method should be overriden (default action is turning left)
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
return Action.LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method should be overriden (default color is black)
|
||||||
|
public Color getColor() {
|
||||||
|
return Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method should be overriden (default display is "?")
|
||||||
|
public String toString() {
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
// This prevents critters from trying to redefine the definition of
|
||||||
|
// object equality, which is important for the simulator to work properly.
|
||||||
|
public final boolean equals(Object other) {
|
||||||
|
return this == other;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
// Class CritterFrame provides the user interface for a simple simulation
|
||||||
|
// program.
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import javax.swing.event.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class CritterFrame extends JFrame {
|
||||||
|
private CritterModel myModel;
|
||||||
|
private CritterPanel myPicture;
|
||||||
|
private javax.swing.Timer myTimer;
|
||||||
|
private JButton[] counts;
|
||||||
|
private JButton countButton;
|
||||||
|
private boolean started;
|
||||||
|
private static boolean created;
|
||||||
|
|
||||||
|
public CritterFrame(int width, int height) {
|
||||||
|
// this prevents someone from trying to create their own copy of
|
||||||
|
// the GUI components
|
||||||
|
if (created)
|
||||||
|
throw new RuntimeException("Only one world allowed");
|
||||||
|
created = true;
|
||||||
|
|
||||||
|
// create frame and model
|
||||||
|
setTitle("CSE142 critter simulation");
|
||||||
|
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||||
|
myModel = new CritterModel(width, height);
|
||||||
|
|
||||||
|
// set up critter picture panel
|
||||||
|
myPicture = new CritterPanel(myModel);
|
||||||
|
add(myPicture, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
addTimer();
|
||||||
|
|
||||||
|
constructSouth();
|
||||||
|
|
||||||
|
// initially it has not started
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct the controls and label for the southern panel
|
||||||
|
private void constructSouth() {
|
||||||
|
// add timer controls to the south
|
||||||
|
JPanel p = new JPanel();
|
||||||
|
|
||||||
|
final JSlider slider = new JSlider();
|
||||||
|
slider.addChangeListener(new ChangeListener() {
|
||||||
|
public void stateChanged(ChangeEvent e) {
|
||||||
|
double ratio = 1000.0 / (1 + Math.pow(slider.getValue(), 0.3));
|
||||||
|
myTimer.setDelay((int) (ratio - 180));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
slider.setValue(20);
|
||||||
|
p.add(new JLabel("slow"));
|
||||||
|
p.add(slider);
|
||||||
|
p.add(new JLabel("fast"));
|
||||||
|
|
||||||
|
JButton b1 = new JButton("start");
|
||||||
|
b1.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
myTimer.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(b1);
|
||||||
|
JButton b2 = new JButton("stop");
|
||||||
|
b2.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
myTimer.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(b2);
|
||||||
|
JButton b3 = new JButton("step");
|
||||||
|
b3.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
doOneStep();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(b3);
|
||||||
|
|
||||||
|
// add debug button
|
||||||
|
JButton b4 = new JButton("debug");
|
||||||
|
b4.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
myModel.toggleDebug();
|
||||||
|
myPicture.repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(b4);
|
||||||
|
|
||||||
|
// add 100 button
|
||||||
|
JButton b5 = new JButton("next 100");
|
||||||
|
b5.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
multistep(100);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
p.add(b5);
|
||||||
|
|
||||||
|
add(p, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// starts the simulation...assumes all critters have already been added
|
||||||
|
public void start() {
|
||||||
|
// don't let anyone start a second time and remember if we have started
|
||||||
|
if (started) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if they didn't add any critters, then nothing to do
|
||||||
|
if (myModel.getCounts().isEmpty()) {
|
||||||
|
System.out.println("nothing to simulate--no critters");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
started = true;
|
||||||
|
addClassCounts();
|
||||||
|
myModel.updateColorString();
|
||||||
|
pack();
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add right-hand column showing how many of each critter are alive
|
||||||
|
private void addClassCounts() {
|
||||||
|
Set<Map.Entry<String, Integer>> entries = myModel.getCounts();
|
||||||
|
JPanel p = new JPanel(new GridLayout(entries.size() + 1, 1));
|
||||||
|
counts = new JButton[entries.size()];
|
||||||
|
for (int i = 0; i < counts.length; i++) {
|
||||||
|
counts[i] = new JButton();
|
||||||
|
p.add(counts[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add simulation count
|
||||||
|
countButton = new JButton();
|
||||||
|
countButton.setForeground(Color.BLUE);
|
||||||
|
p.add(countButton);
|
||||||
|
|
||||||
|
add(p, BorderLayout.EAST);
|
||||||
|
setCounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCounts() {
|
||||||
|
Set<Map.Entry<String, Integer>> entries = myModel.getCounts();
|
||||||
|
int i = 0;
|
||||||
|
int max = 0;
|
||||||
|
int maxI = 0;
|
||||||
|
for (Map.Entry<String, Integer> entry: myModel.getCounts()) {
|
||||||
|
String s = String.format("%s =%4d", entry.getKey(),
|
||||||
|
(int) entry.getValue());
|
||||||
|
counts[i].setText(s);
|
||||||
|
counts[i].setForeground(Color.BLACK);
|
||||||
|
if (entry.getValue() > max) {
|
||||||
|
max = entry.getValue();
|
||||||
|
maxI = i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
counts[maxI].setForeground(Color.RED);
|
||||||
|
String s = String.format("step =%5d", myModel.getSimulationCount());
|
||||||
|
countButton.setText(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a certain number of critters of a particular class to the simulation
|
||||||
|
public void add(int number, Class<? extends Critter> c) {
|
||||||
|
// don't let anyone add critters after simulation starts
|
||||||
|
if (started) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// temporarily turning on started flag prevents critter constructors
|
||||||
|
// from calling add
|
||||||
|
started = true;
|
||||||
|
myModel.add(number, c);
|
||||||
|
started = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// post: creates a timer that calls the model's update
|
||||||
|
// method and repaints the display
|
||||||
|
private void addTimer() {
|
||||||
|
ActionListener updater = new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
doOneStep();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
myTimer = new javax.swing.Timer(0, updater);
|
||||||
|
myTimer.setCoalesce(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// one step of the simulation
|
||||||
|
private void doOneStep() {
|
||||||
|
myModel.update();
|
||||||
|
setCounts();
|
||||||
|
myPicture.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance the simulation until step % n is 0
|
||||||
|
private void multistep(int n) {
|
||||||
|
myTimer.stop();
|
||||||
|
do {
|
||||||
|
myModel.update();
|
||||||
|
} while (myModel.getSimulationCount() % n != 0);
|
||||||
|
setCounts();
|
||||||
|
myPicture.repaint();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
// The CritterInfo interface defines a set of methods for querying the
|
||||||
|
// state of a critter simulation. You should not alter this file. See
|
||||||
|
// the documentation in the Critter class for a more detailed explanation.
|
||||||
|
|
||||||
|
public interface CritterInfo {
|
||||||
|
public Critter.Neighbor getFront();
|
||||||
|
public Critter.Neighbor getBack();
|
||||||
|
public Critter.Neighbor getLeft();
|
||||||
|
public Critter.Neighbor getRight();
|
||||||
|
public Critter.Direction getDirection();
|
||||||
|
public Critter.Direction getFrontDirection();
|
||||||
|
public Critter.Direction getBackDirection();
|
||||||
|
public Critter.Direction getLeftDirection();
|
||||||
|
public Critter.Direction getRightDirection();
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// CSE 142 Homework 9 (Critters)
|
||||||
|
// Authors: Stuart Reges and Marty Stepp
|
||||||
|
// modified by Kyle Thayer
|
||||||
|
//
|
||||||
|
// CritterMain provides the main method for a simple simulation program. Alter
|
||||||
|
// the number of each critter added to the simulation if you want to experiment
|
||||||
|
// with different scenarios. You can also alter the width and height passed to
|
||||||
|
// the CritterFrame constructor.
|
||||||
|
|
||||||
|
public class CritterMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
CritterFrame frame = new CritterFrame(60, 40);
|
||||||
|
|
||||||
|
// uncomment each of these lines as you complete these classes
|
||||||
|
frame.add(30, Bear.class);
|
||||||
|
frame.add(30, Lion.class);
|
||||||
|
frame.add(30, Giant.class);
|
||||||
|
frame.add(30, Orca.class);
|
||||||
|
|
||||||
|
frame.add(30, FlyTrap.class);
|
||||||
|
frame.add(30, Food.class);
|
||||||
|
|
||||||
|
frame.start();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,327 @@
|
||||||
|
// Class CritterModel keeps track of the state of the critter simulation.
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
|
public class CritterModel {
|
||||||
|
private int height;
|
||||||
|
private int width;
|
||||||
|
private Critter[][] grid;
|
||||||
|
private Map<Critter, PrivateData> info;
|
||||||
|
private SortedMap<String, Integer>critterCount;
|
||||||
|
private boolean debugView;
|
||||||
|
private int simulationCount;
|
||||||
|
private static boolean created;
|
||||||
|
|
||||||
|
public CritterModel(int width, int height) {
|
||||||
|
// this prevents someone from trying to create their own copy of
|
||||||
|
// the GUI components
|
||||||
|
if (created)
|
||||||
|
throw new RuntimeException("Only one world allowed");
|
||||||
|
created = true;
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
grid = new Critter[width][height];
|
||||||
|
info = new HashMap<Critter, PrivateData>();
|
||||||
|
critterCount = new TreeMap<String, Integer>();
|
||||||
|
this.debugView = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Critter> iterator() {
|
||||||
|
return info.keySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getPoint(Critter c) {
|
||||||
|
return info.get(c).p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor(Critter c) {
|
||||||
|
return info.get(c).color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(Critter c) {
|
||||||
|
return info.get(c).string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(int number, Class<? extends Critter> critter) {
|
||||||
|
Random r = new Random();
|
||||||
|
Critter.Direction[] directions = Critter.Direction.values();
|
||||||
|
if (info.size() + number > width * height)
|
||||||
|
throw new RuntimeException("adding too many critters");
|
||||||
|
for (int i = 0; i < number; i++) {
|
||||||
|
Critter next;
|
||||||
|
try {
|
||||||
|
next = makeCritter(critter);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
System.out.println("ERROR: " + critter + " does not have" +
|
||||||
|
" the appropriate constructor.");
|
||||||
|
System.exit(1);
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("ERROR: " + critter + " threw an " +
|
||||||
|
" exception in its constructor.");
|
||||||
|
System.exit(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int x, y;
|
||||||
|
do {
|
||||||
|
x = r.nextInt(width);
|
||||||
|
y = r.nextInt(height);
|
||||||
|
} while (grid[x][y] != null);
|
||||||
|
grid[x][y] = next;
|
||||||
|
|
||||||
|
Critter.Direction d = directions[r.nextInt(directions.length)];
|
||||||
|
info.put(next, new PrivateData(new Point(x, y), d));
|
||||||
|
}
|
||||||
|
String name = critter.getName();
|
||||||
|
if (!critterCount.containsKey(name))
|
||||||
|
critterCount.put(name, number);
|
||||||
|
else
|
||||||
|
critterCount.put(name, critterCount.get(name) + number);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Critter makeCritter(Class critter) throws Exception {
|
||||||
|
Constructor c = critter.getConstructors()[0];
|
||||||
|
if (critter.toString().equals("class Bear")) {
|
||||||
|
// flip a coin
|
||||||
|
boolean b = Math.random() < 0.5;
|
||||||
|
return (Critter) c.newInstance(new Object[] {b});
|
||||||
|
} else {
|
||||||
|
return (Critter) c.newInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAppearance(Critter c) {
|
||||||
|
// Override specified toString if debug flag is true
|
||||||
|
if (!debugView)
|
||||||
|
return info.get(c).string;
|
||||||
|
else {
|
||||||
|
PrivateData data = info.get(c);
|
||||||
|
if (data.direction == Critter.Direction.NORTH) return "^";
|
||||||
|
else if (data.direction == Critter.Direction.SOUTH) return "v";
|
||||||
|
else if (data.direction == Critter.Direction.EAST) return ">";
|
||||||
|
else return "<";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleDebug() {
|
||||||
|
this.debugView = !this.debugView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean inBounds(int x, int y) {
|
||||||
|
return (x >= 0 && x < width && y >= 0 && y < height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean inBounds(Point p) {
|
||||||
|
return inBounds(p.x, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the result of rotating the given direction clockwise
|
||||||
|
private Critter.Direction rotate(Critter.Direction d) {
|
||||||
|
if (d == Critter.Direction.NORTH) return Critter.Direction.EAST;
|
||||||
|
else if (d == Critter.Direction.SOUTH) return Critter.Direction.WEST;
|
||||||
|
else if (d == Critter.Direction.EAST) return Critter.Direction.SOUTH;
|
||||||
|
else return Critter.Direction.NORTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point pointAt(Point p, Critter.Direction d) {
|
||||||
|
if (d == Critter.Direction.NORTH) return new Point(p.x, p.y - 1);
|
||||||
|
else if (d == Critter.Direction.SOUTH) return new Point(p.x, p.y + 1);
|
||||||
|
else if (d == Critter.Direction.EAST) return new Point(p.x + 1, p.y);
|
||||||
|
else return new Point(p.x - 1, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Info getInfo(PrivateData data, Class original) {
|
||||||
|
Critter.Neighbor[] neighbors = new Critter.Neighbor[4];
|
||||||
|
Critter.Direction d = data.direction;
|
||||||
|
Critter.Direction[] neighborDirections = new Critter.Direction[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
neighbors[i] = getStatus(pointAt(data.p, d), original);
|
||||||
|
if (neighbors[i] == Critter.Neighbor.OTHER ||
|
||||||
|
neighbors[i] == Critter.Neighbor.SAME){
|
||||||
|
Point p = pointAt(data.p, d);
|
||||||
|
PrivateData oldData = info.get(grid[p.x][p.y]);
|
||||||
|
neighborDirections[i] = oldData.direction;
|
||||||
|
} else {
|
||||||
|
neighborDirections[i] = Critter.Direction.NORTH;
|
||||||
|
}
|
||||||
|
d = rotate(d);
|
||||||
|
}
|
||||||
|
return new Info(neighbors, data.direction, neighborDirections);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Critter.Neighbor getStatus(Point p, Class original) {
|
||||||
|
if (!inBounds(p))
|
||||||
|
return Critter.Neighbor.WALL;
|
||||||
|
else if (grid[p.x][p.y] == null)
|
||||||
|
return Critter.Neighbor.EMPTY;
|
||||||
|
else if (grid[p.x][p.y].getClass() == original)
|
||||||
|
return Critter.Neighbor.SAME;
|
||||||
|
else
|
||||||
|
return Critter.Neighbor.OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void update() {
|
||||||
|
simulationCount++;
|
||||||
|
Object[] list = info.keySet().toArray();
|
||||||
|
Collections.shuffle(Arrays.asList(list));
|
||||||
|
|
||||||
|
// This keeps track of critters that are locked and cannot be
|
||||||
|
// infected this turn. The happens when:
|
||||||
|
// * a Critter is infected
|
||||||
|
// * a Critter hops
|
||||||
|
Set<Critter> locked = new HashSet<Critter>();
|
||||||
|
|
||||||
|
for (int i = 0; i < list.length; i++) {
|
||||||
|
Critter next = (Critter)list[i];
|
||||||
|
PrivateData data = info.get(next);
|
||||||
|
if (data == null) {
|
||||||
|
// happens when creature was infected earlier in this round
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Point p = data.p;
|
||||||
|
Point p2 = pointAt(p, data.direction);
|
||||||
|
|
||||||
|
|
||||||
|
// try to perform the critter's action
|
||||||
|
Critter.Action move = next.getMove(getInfo(data, next.getClass()));
|
||||||
|
if (move == Critter.Action.LEFT)
|
||||||
|
data.direction = rotate(rotate(rotate(data.direction)));
|
||||||
|
else if (move == Critter.Action.RIGHT)
|
||||||
|
data.direction = rotate(data.direction);
|
||||||
|
else if (move == Critter.Action.HOP) {
|
||||||
|
if (inBounds(p2) && grid[p2.x][p2.y] == null) {
|
||||||
|
grid[p2.x][p2.y] = grid[p.x][p.y];
|
||||||
|
grid[p.x][p.y] = null;
|
||||||
|
data.p = p2;
|
||||||
|
locked.add(next); //successful hop locks a critter from
|
||||||
|
// being infected for the rest of the
|
||||||
|
// turn
|
||||||
|
}
|
||||||
|
} else if (move == Critter.Action.INFECT) {
|
||||||
|
if (inBounds(p2) && grid[p2.x][p2.y] != null
|
||||||
|
&& grid[p2.x][p2.y].getClass() != next.getClass()
|
||||||
|
&& !locked.contains(grid[p2.x][p2.y])) {
|
||||||
|
Critter other = grid[p2.x][p2.y];
|
||||||
|
// remember the old critter's private data
|
||||||
|
PrivateData oldData = info.get(other);
|
||||||
|
// then remove that old critter
|
||||||
|
String c1 = other.getClass().getName();
|
||||||
|
critterCount.put(c1, critterCount.get(c1) - 1);
|
||||||
|
String c2 = next.getClass().getName();
|
||||||
|
critterCount.put(c2, critterCount.get(c2) + 1);
|
||||||
|
info.remove(other);
|
||||||
|
// and add a new one to the grid
|
||||||
|
try {
|
||||||
|
grid[p2.x][p2.y] = makeCritter(next.getClass());
|
||||||
|
// This critter has been infected and is now locked
|
||||||
|
// for the rest of this turn
|
||||||
|
locked.add(grid[p2.x][p2.y]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("" + e);
|
||||||
|
}
|
||||||
|
// and add to the map
|
||||||
|
info.put(grid[p2.x][p2.y], oldData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateColorString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling this method causes each critter to update the stored color and
|
||||||
|
// text for toString; should be called each time update is performed and
|
||||||
|
// once before the simulation begins
|
||||||
|
public void updateColorString() {
|
||||||
|
for (Critter next : info.keySet()) {
|
||||||
|
info.get(next).color = next.getColor();
|
||||||
|
info.get(next).string = next.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Map.Entry<String, Integer>> getCounts() {
|
||||||
|
return Collections.unmodifiableSet(critterCount.entrySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSimulationCount() {
|
||||||
|
return simulationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PrivateData {
|
||||||
|
public Point p;
|
||||||
|
public Critter.Direction direction;
|
||||||
|
public Color color;
|
||||||
|
public String string;
|
||||||
|
|
||||||
|
public PrivateData(Point p, Critter.Direction d) {
|
||||||
|
this.p = p;
|
||||||
|
this.direction = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return p + " " + direction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// an object used to query a critter's state (neighbors, direction)
|
||||||
|
private static class Info implements CritterInfo {
|
||||||
|
private Critter.Neighbor[] neighbors;
|
||||||
|
private Critter.Direction direction;
|
||||||
|
private Critter.Direction[] neighborDirections;
|
||||||
|
|
||||||
|
public Info(Critter.Neighbor[] neighbors, Critter.Direction d,
|
||||||
|
Critter.Direction[] neighborDirections) {
|
||||||
|
this.neighbors = neighbors;
|
||||||
|
this.direction = d;
|
||||||
|
this.neighborDirections = neighborDirections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Neighbor getFront() {
|
||||||
|
return neighbors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Neighbor getBack() {
|
||||||
|
return neighbors[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Neighbor getLeft() {
|
||||||
|
return neighbors[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Neighbor getRight() {
|
||||||
|
return neighbors[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Direction getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Direction getFrontDirection() {
|
||||||
|
return neighborDirections[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Direction getBackDirection() {
|
||||||
|
return neighborDirections[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Direction getLeftDirection() {
|
||||||
|
return neighborDirections[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Critter.Direction getRightDirection() {
|
||||||
|
return neighborDirections[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Class CritterPanel displays a grid of critters
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class CritterPanel extends JPanel {
|
||||||
|
private CritterModel myModel;
|
||||||
|
private Font myFont;
|
||||||
|
private static boolean created;
|
||||||
|
|
||||||
|
public static final int FONT_SIZE = 12;
|
||||||
|
|
||||||
|
public CritterPanel(CritterModel model) {
|
||||||
|
// this prevents someone from trying to create their own copy of
|
||||||
|
// the GUI components
|
||||||
|
if (created)
|
||||||
|
throw new RuntimeException("Only one world allowed");
|
||||||
|
created = true;
|
||||||
|
|
||||||
|
myModel = model;
|
||||||
|
// construct font and compute char width once in constructor
|
||||||
|
// for efficiency
|
||||||
|
myFont = new Font("Monospaced", Font.BOLD, FONT_SIZE + 4);
|
||||||
|
setBackground(Color.CYAN);
|
||||||
|
setPreferredSize(new Dimension(FONT_SIZE * model.getWidth() + 20,
|
||||||
|
FONT_SIZE * model.getHeight() + 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setFont(myFont);
|
||||||
|
Iterator<Critter> i = myModel.iterator();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Critter next = i.next();
|
||||||
|
Point p = myModel.getPoint(next);
|
||||||
|
String appearance = myModel.getAppearance(next);
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.drawString("" + appearance, p.x * FONT_SIZE + 11,
|
||||||
|
p.y * FONT_SIZE + 21);
|
||||||
|
g.setColor(myModel.getColor(next));
|
||||||
|
g.drawString("" + appearance, p.x * FONT_SIZE + 10,
|
||||||
|
p.y * FONT_SIZE + 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
// This defines a simple class of critters that infect whenever they can and
|
||||||
|
// otherwise just spin around, looking for critters to infect. This simple
|
||||||
|
// strategy turns out to be surpisingly successful.
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class FlyTrap extends Critter {
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
if (info.getFront() == Neighbor.OTHER) {
|
||||||
|
return Action.INFECT;
|
||||||
|
} else {
|
||||||
|
return Action.LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return Color.RED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "T";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
// This defines a simple class of critters that sit around waiting to be
|
||||||
|
// taken over by other critters.
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class Food extends Critter {
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
return Action.INFECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return Color.GREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "F";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Matt Jensen
|
||||||
|
* CS145
|
||||||
|
* Lab 2 - Critters
|
||||||
|
* 4/23/19
|
||||||
|
* Partners: Melissa, Devante
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Giant extends Critter {
|
||||||
|
private Color color = Color.GRAY;
|
||||||
|
|
||||||
|
private String symbol;
|
||||||
|
|
||||||
|
public int moveCount;
|
||||||
|
|
||||||
|
|
||||||
|
public Giant() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
this.changeSymbol();
|
||||||
|
return this.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeSymbol() {
|
||||||
|
if( this.moveCount > 24 ) {
|
||||||
|
this.moveCount = 0;
|
||||||
|
}
|
||||||
|
if( this.moveCount <= 6) {
|
||||||
|
this.symbol = "FEE";
|
||||||
|
}
|
||||||
|
if( this.moveCount > 6 && this.moveCount <= 12 ) {
|
||||||
|
this.symbol = "FIE";
|
||||||
|
}
|
||||||
|
if ( this.moveCount > 12 && this.moveCount <= 18) {
|
||||||
|
this.symbol = "FOO";
|
||||||
|
}
|
||||||
|
if ( this.moveCount > 18 ) {
|
||||||
|
this.symbol = "FUM";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
this.moveCount++;
|
||||||
|
Neighbor front = info.getFront();
|
||||||
|
if( front == Neighbor.OTHER) {
|
||||||
|
return Action.INFECT;
|
||||||
|
}
|
||||||
|
if( front == Neighbor.EMPTY) {
|
||||||
|
return Action.HOP;
|
||||||
|
}
|
||||||
|
return Action.RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Matt Jensen
|
||||||
|
* CS145
|
||||||
|
* Lab 2 - Critters
|
||||||
|
* 4/23/19
|
||||||
|
* Partners: Melissa, Devante
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Lion extends Critter {
|
||||||
|
|
||||||
|
private Color color = Color.BLUE;
|
||||||
|
|
||||||
|
private int moves = 0;
|
||||||
|
|
||||||
|
public Lion() {
|
||||||
|
this.changeColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMoveCount() {
|
||||||
|
return this.moves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "L";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeColor() {
|
||||||
|
if(this.getMoveCount() == 0 || this.getMoveCount() % 3 == 0) {
|
||||||
|
int rand = this.randomWithRange(0, 2);
|
||||||
|
if(rand == 0 ) {
|
||||||
|
this.color = Color.RED;
|
||||||
|
}
|
||||||
|
if(rand == 1 ) {
|
||||||
|
this.color = Color.GREEN;
|
||||||
|
}
|
||||||
|
if(rand == 2 ) {
|
||||||
|
this.color = Color.BLUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
this.moves = this.moves++;
|
||||||
|
this.changeColor();
|
||||||
|
|
||||||
|
Neighbor front = info.getFront();
|
||||||
|
|
||||||
|
if( front == Neighbor.OTHER ) { // check for enemy in front.
|
||||||
|
return Action.INFECT;
|
||||||
|
}
|
||||||
|
if ( front == Neighbor.WALL || info.getRight() == Neighbor.WALL ) { // check for obstacle.
|
||||||
|
return Action.LEFT;
|
||||||
|
}
|
||||||
|
if ( front == Neighbor.SAME ) { // check for obstacle.
|
||||||
|
return Action.RIGHT;
|
||||||
|
}
|
||||||
|
return Action.HOP;
|
||||||
|
}
|
||||||
|
public int randomWithRange(int min, int max)
|
||||||
|
{
|
||||||
|
int range = (max - min) + 1;
|
||||||
|
return (int)(Math.random() * range) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Matt Jensen
|
||||||
|
* CS145
|
||||||
|
* Lab 2 - Critters
|
||||||
|
* 4/23/19
|
||||||
|
* Partners: Melissa, Devante
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Orca extends Critter {
|
||||||
|
private Color color = Color.BLACK;
|
||||||
|
|
||||||
|
private String symbol = "0-<";
|
||||||
|
|
||||||
|
public int moveCount;
|
||||||
|
|
||||||
|
|
||||||
|
public Orca() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor() {
|
||||||
|
if( this.color == Color.BLACK) {
|
||||||
|
this.color = Color.WHITE;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
this.color = Color.BLACK;
|
||||||
|
}
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return this.symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action getMove(CritterInfo info) {
|
||||||
|
this.moveCount++;
|
||||||
|
Neighbor front = info.getFront();
|
||||||
|
|
||||||
|
if(front == Neighbor.OTHER) {
|
||||||
|
return Action.INFECT;
|
||||||
|
}
|
||||||
|
if(front == Neighbor.EMPTY) {
|
||||||
|
return Action.HOP;
|
||||||
|
}
|
||||||
|
if(front == Neighbor.WALL) {
|
||||||
|
return Action.RIGHT;
|
||||||
|
}
|
||||||
|
return Action.LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue