From 49a68ff07eaa6492e92129cc8fc37377c9dd717b Mon Sep 17 00:00:00 2001 From: Alex Benitez Date: Mon, 24 Nov 2025 12:04:20 -0800 Subject: [PATCH 1/5] Add files via upload --- src/main/java/ChosenOne.java | 2 + src/main/java/Entity.java | 2 + src/main/java/Human.java | 2 + src/main/java/Medic.java | 2 + src/main/java/Zombie.java | 2 + src/main/java/ZombieGUI.java | 197 +++++++++++++++++++++++++ src/main/java/ZombieInvasionModel.java | 151 +++++++++++++++++++ 7 files changed, 358 insertions(+) create mode 100644 src/main/java/ChosenOne.java create mode 100644 src/main/java/Entity.java create mode 100644 src/main/java/Human.java create mode 100644 src/main/java/Medic.java create mode 100644 src/main/java/Zombie.java create mode 100644 src/main/java/ZombieGUI.java create mode 100644 src/main/java/ZombieInvasionModel.java diff --git a/src/main/java/ChosenOne.java b/src/main/java/ChosenOne.java new file mode 100644 index 0000000..37ce1f1 --- /dev/null +++ b/src/main/java/ChosenOne.java @@ -0,0 +1,2 @@ +public class ChosenOne extends Human{ +} diff --git a/src/main/java/Entity.java b/src/main/java/Entity.java new file mode 100644 index 0000000..3c1efbd --- /dev/null +++ b/src/main/java/Entity.java @@ -0,0 +1,2 @@ +public class Entity { +} diff --git a/src/main/java/Human.java b/src/main/java/Human.java new file mode 100644 index 0000000..500bb91 --- /dev/null +++ b/src/main/java/Human.java @@ -0,0 +1,2 @@ +public class Human extends Entity{ +} diff --git a/src/main/java/Medic.java b/src/main/java/Medic.java new file mode 100644 index 0000000..95e5fab --- /dev/null +++ b/src/main/java/Medic.java @@ -0,0 +1,2 @@ +public class Medic extends Human{ +} diff --git a/src/main/java/Zombie.java b/src/main/java/Zombie.java new file mode 100644 index 0000000..e90d335 --- /dev/null +++ b/src/main/java/Zombie.java @@ -0,0 +1,2 @@ +public class Zombie extends Entity{ +} diff --git a/src/main/java/ZombieGUI.java b/src/main/java/ZombieGUI.java new file mode 100644 index 0000000..4722b1f --- /dev/null +++ b/src/main/java/ZombieGUI.java @@ -0,0 +1,197 @@ +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.util.HashMap; +import java.util.Map; +//This is the ZombieInvasionGUI +//ONLY DISPLAY/GRAPHICAL CHANGES +//this class stores and holds user input as well as +public class ZombieGUI { + + public static Map showSettingsDialog(Frame parent, String title, + String[] names, Class[] types, + Object[] initialValues) { + JDialog dialog = new JDialog(parent, title, true); + dialog.setLayout(new BorderLayout()); + + JPanel labelPanel = new JPanel(new GridLayout(names.length, 1, 5, 5)); + JPanel inputPanel = new JPanel(new GridLayout(names.length, 1, 5, 5)); + JComponent[] inputs = new JComponent[names.length]; + + for (int i = 0; i < names.length; i++) { + labelPanel.add(new JLabel(names[i])); + + if (types[i] == Boolean.TYPE) { + JCheckBox checkBox = new JCheckBox(); + if (initialValues != null && initialValues[i] instanceof Boolean) { + checkBox.setSelected((Boolean) initialValues[i]); + } + inputs[i] = checkBox; + inputPanel.add(checkBox); + + } else if (types[i] == Integer.TYPE || types[i] == Double.TYPE || types[i] == String.class) { + JTextField textField = new JTextField(10); + if (initialValues != null && initialValues[i] != null) { + textField.setText(initialValues[i].toString()); + } + inputs[i] = textField; + inputPanel.add(textField); + + } else { + inputPanel.add(new JPanel()); // empty panel for unknown types + } + } + + dialog.add(labelPanel, BorderLayout.WEST); + dialog.add(inputPanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(); + JButton okButton = new JButton("OK"); + JButton cancelButton = new JButton("Cancel"); + + final Map[] result = new Map[]{null}; + + okButton.addActionListener((ActionEvent e) -> { + Map map = new HashMap<>(); + try { + for (int i = 0; i < names.length; i++) { + if (types[i] == Boolean.TYPE) { + map.put(names[i], ((JCheckBox) inputs[i]).isSelected()); + } else if (types[i] == Integer.TYPE) { + map.put(names[i], Integer.parseInt(((JTextField) inputs[i]).getText())); + } else if (types[i] == Double.TYPE) { + map.put(names[i], Double.parseDouble(((JTextField) inputs[i]).getText())); + } else if (types[i] == String.class) { + map.put(names[i], ((JTextField) inputs[i]).getText()); + } + } + } catch (Exception ex) { + JOptionPane.showMessageDialog(dialog, "Invalid input: " + ex.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + return; // don't close the dialog + } + result[0] = map; + openGridWindow(map); + dialog.dispose(); + }); + + cancelButton.addActionListener(e -> { + result[0] = null; + dialog.dispose(); + }); + //adds buttons to JPanel(buttonPanel) + buttonPanel.add(okButton); + buttonPanel.add(cancelButton); + dialog.add(buttonPanel, BorderLayout.SOUTH); + + dialog.pack(); + dialog.setLocationRelativeTo(parent); + dialog.setVisible(true); + + return result[0]; + } + // method that creates JPanel as a grid for Zombie Simulation + private static void openGridWindow(Map settings) { + int width = (int) settings.getOrDefault("Map Width", 5); + int height = (int) settings.getOrDefault("Map Height", 5); + + JFrame gridFrame = new JFrame("Zombie Invasion Simulation"); + gridFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + gridFrame.setLayout(new BorderLayout()); + // NOTE: --------------Model + Day Counter------------------ + final int[] day = {0}; + + JLabel dayLabel = new JLabel("Day: 0"); + dayLabel.setFont(new Font("Arial", Font.BOLD, 16)); + + + // NOTE: ----------------Grid Panel---------------- + JPanel gridPanel = new JPanel(new GridLayout(height, width)); + for (int i = 0; i < height * width; i++) { + JPanel cell = new JPanel(); + cell.setBackground(Color.WHITE); + cell.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + gridPanel.add(cell); + } + + gridFrame.add(gridPanel, BorderLayout.CENTER); + //updates simulation every 500ms (change if needed) + Timer timer = new Timer(500, e -> { + day[0]++; // increment day + dayLabel.setText("Day: " + day[0]); + + // TODO: call your model.updateTick() here when model class is ready. dont forget + //ZombieInvasionModel.updateTick(); + // redrawsw the grid + gridPanel.repaint(); + }); + // NOTE: ----------------Legend Panel---------------- + JPanel legendPanel = new JPanel(); + legendPanel.setLayout(new BoxLayout(legendPanel, BoxLayout.Y_AXIS)); + legendPanel.setBorder(BorderFactory.createTitledBorder("Legend")); + + legendPanel.add(createLegendItem(Color.RED, "Zombie")); + legendPanel.add(createLegendItem(Color.GREEN, "Human")); + legendPanel.add(createLegendItem(Color.YELLOW, "Medic")); + // NOTE: need to create another toggle Legend for ChosenOne if buttonSwitch is on + + gridFrame.add(legendPanel, BorderLayout.EAST); + + // NOTE: ----------------Panel Default Settings---------------- + gridFrame.pack(); + gridFrame.setSize(Math.min(width * 40 + 150, 1000), Math.min(height * 40 + 50, 800)); + gridFrame.setLocationRelativeTo(null); + gridFrame.setVisible(true); + // NOTE: ----------------Control Panel---------------- + JButton startButton = new JButton("Start"); + JButton pauseButton = new JButton("Pause"); + JButton quitButton = new JButton("Quit"); + + // NOTE: ---------------ACTION LISTENERS(buttons)------------- + startButton.addActionListener(e -> timer.start()); + pauseButton.addActionListener(e -> timer.stop()); + quitButton.addActionListener(e -> gridFrame.dispose()); + + JPanel controlPanel = new JPanel(new FlowLayout()); + controlPanel.add(startButton); + controlPanel.add(pauseButton); + controlPanel.add(dayLabel); + controlPanel.add(quitButton); + + gridFrame.add(controlPanel, BorderLayout.SOUTH); + } + + // Helper method to create a color + label legend item + //Color-coded scheme for the blocks on grid + private static JPanel createLegendItem(Color color, String label) { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5)); + JPanel colorBox = new JPanel(); + colorBox.setBackground(color); + colorBox.setPreferredSize(new Dimension(20, 20)); + colorBox.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + + JLabel text = new JLabel(label); + + panel.add(colorBox); + panel.add(text); + return panel; + } + + // main method creates values and invokes swing utilites + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + String[] names = {"Enable ChosenOne", "Map Width", "Map Height", "Infection Rate", "Heal Rate", "Number of Zombies", "Number of Medic"}; + Class[] types = {Boolean.TYPE, Integer.TYPE,Integer.TYPE, Integer.TYPE,Integer.TYPE, Integer.TYPE, Integer.TYPE}; + Object[] defaults = {false, 50, 50, 25, 15,1,5}; + + Map settings = showSettingsDialog(null, "Simulation Settings", + names, types, defaults); + + if (settings != null) { + settings.forEach((k, v) -> System.out.println(k + " = " + v)); + } else { + System.out.println("Settings canceled."); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/ZombieInvasionModel.java b/src/main/java/ZombieInvasionModel.java new file mode 100644 index 0000000..c98d005 --- /dev/null +++ b/src/main/java/ZombieInvasionModel.java @@ -0,0 +1,151 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ZombieInvasionModel { + private Entity[][] grid; + //Size of grid + private int row; + private int column; + //Used to specify where Case Zero can Start + private int xCordinate; + private int yCordinate; + //infection rate/heal rate / otherCustomization + private double infectionRate; + private double healRate; + //checks all possible sorrounding squares with + //each direction. + private static final int[][] DIRECTIONS = { + {-1, 0}, {1, 0}, {0, -1}, {0, 1}, + {-1, 1}, {-1, -1}, {1, 1}, {1, -1} + }; + //Default values for # of zombies and medics and location + private int numOfZombies; + private int numOfMedics; + + //overloaded constructor creats Entity[][] grid + // with specified rows and column + //SHOULD BE SAME SIZE AS DIMESNIONS SET IN SETTINGS + public ZombieInvasionModel(int row, int column) { + this.row = row; + this.column = column; + grid = new Entity[row][column]; + } + //Overloaded constructor that creates Entity[][]grid + //specifies how many humans, zombies, medic, ect. + //And specifies if ChosenOne is available option to put in grid + public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic) { + this(row, column); + intiliazeEntities(); + } + //Overloaded constructor that creates Entity[][]grid + //Specifies all of the above and WHERE CASE ZERO IS + //;where the first zombie starts in simulation + public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic, + boolean humanitySaved){ + this(row,column,numOfZombies,numOfMedic); + + } + //OverLoaded constructor that creates Entity[][]grid + //specifices infection rate, medic rate, ect., if chosen one allowed + public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic, + boolean humanitySaved, double infectionRate, double healRate){ + this(row,column,numOfZombies,numOfMedic, humanitySaved); + } + + public Entity[][] getGrid() { return grid; } + //Update all changes that happen on the grid + //objects are changed but color is changed in ZombieGUI class + public static void updateTick() { + //zombie entity becomes human? + //if trigger/flag call infect + //if trigger/flag call heal + //if trigger/flag call ability + // + } + + //Helper method that creates the grid according to specifications + private void intiliazeEntities(){ + List types = new ArrayList<>(); + + //For loop to add exact number of medics and zombies + for (int i = 0; i < numOfZombies; i++) { types.add(new Zombie()); } + for (int j = 0; j < numOfMedics; j++) { types.add(new Medic()); } + + //Remaining cells are humans + int remainingNumOfHumans = (row * column) - (numOfZombies + numOfMedics); + for (int k = 0; k < remainingNumOfHumans; k++) { types.add(new Human()); } + + //Use collection interface to shuffle grid randomly + Collections.shuffle(types); + + //for loop to create grid + int index = 0; + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++){ + grid[i][j] = types.get(index); + index++; + } + } + } + + //Checks if square is zombie and able to infect + //calls on infectNeighbors method + private void infect(){ + + for (int i = 0; i < row; i++){ + for (int j = 0; j < column; j++) { + Entity entity = grid[row][column]; + //if (entity.isZombie()) { // TODO: NEED BOOLEAN METHOD TO CHECK IF ZOMBIE + //call helpermethod that changes + //} + } + } + } + //helper methods that CHANGE THE ACTUAL GRID OBJECT + //change happens here + private void infectNeighbors(){ + //if infect change this cordinate to be zombie IF ITS NOT ZOMBIE + int[][] possibleAttack = { + {-1, 0}, {1, 0}, {0, -1}, {0, 1}, + {-1,1}, {-1,-1}, {1,1}, {1,-1} + }; + + //if entity[x][y].isHuman() + //use infectionRate( + //create new Zombie at those cordinates) + + } + private void heal(){ + } + private void chosenOne(){ + } + //GETTER & SETTERS + public int getColumn() { + return column; + } + + public void setColumn(int column) { + this.column = column; + } + + public int getRow() { + return row; + } + + public void setRow(int row) { + this.row = row; + } + //create print entity here +} +//This class handles: +// +//The Entity[][] grid +// +//Infecting neighbors +// +//Medics healing zombies +// +//Moving entities (if you have movement) +// +//Any rules of the simulation \ No newline at end of file From 04a0a6dc8a8a17f64ba0f4a1029fd31ef1be4528 Mon Sep 17 00:00:00 2001 From: Tsubasa Ito Date: Wed, 26 Nov 2025 16:41:20 -0800 Subject: [PATCH 2/5] Created it --- src/main/java/Entity.java | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/main/java/Entity.java b/src/main/java/Entity.java index 3c1efbd..c7d2108 100644 --- a/src/main/java/Entity.java +++ b/src/main/java/Entity.java @@ -1,2 +1,78 @@ +import java.awt.Color; + public class Entity { + private int row; + private int col; + private boolean infected; + private boolean immune; + + public Entity(int row, int col) { + this.row = row; + this.col = col; + this.infected = false; + this.immune = false; + } + + public void setRow(int row) { + this.row = row; + } + + public void setCol(int col) { + this.col = col; + } + + public void setInfected(boolean infected) { + this.infected = infected; + } + + public void setImmune(boolean immune) { + this.immune = immune; + } + + public void move(Entity[][] grid) { + } + + public void interact(Entity[][] grid) { + } + + public Color getColor() { + return Color.WHITE; + } + + public boolean isInfected() { + return infected; + } + + public boolean isImmune() { + return immune; + } + + public int getRow() { + return row; + } + + public int getCol() { + return col; + } + + public Entity[][] getNeighbors(Entity[][] grid) { + Entity[][] neighbors = new Entity[3][3]; + for (int r = -1; r <= 1; r++) { + for (int c = -1; c <= 1; c++) { + int newRow = row + r; + int newCol = col + c; + if (isInBounds(newRow, newCol, grid)) { + neighbors[r + 1][c + 1] = grid[newRow][newCol]; + } else { + neighbors[r + 1][c + 1] = null; + } + } + } + return neighbors; + } + + public boolean isInBounds(int r, int c, Entity[][] grid) { + return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length; + } + } From e101a99db43f846e461eefa42d0624c4cfe36927 Mon Sep 17 00:00:00 2001 From: Tsubasa Ito Date: Tue, 2 Dec 2025 03:26:13 -0800 Subject: [PATCH 3/5] src --- src/main/java/Entity.java | 89 ++++++++------------------------------- src/main/java/Human.java | 4 +- 2 files changed, 20 insertions(+), 73 deletions(-) diff --git a/src/main/java/Entity.java b/src/main/java/Entity.java index c7d2108..6be7546 100644 --- a/src/main/java/Entity.java +++ b/src/main/java/Entity.java @@ -1,78 +1,23 @@ -import java.awt.Color; +import java.awt.*; -public class Entity { - private int row; - private int col; - private boolean infected; - private boolean immune; +public abstract class Entity { + //checks all possible sorrounding squares with + //each direction. + protected static final int[][] DIRECTIONS = { + {-1, 0}, {1, 0}, {0, -1}, {0, 1}, + {-1, 1}, {-1, -1}, {1, 1}, {1, -1} + }; - public Entity(int row, int col) { - this.row = row; - this.col = col; - this.infected = false; - this.immune = false; - } + //@override infect or defend depending on object + public abstract void performAction(Entity[][] grid, double effectRate, int row, int column); - public void setRow(int row) { - this.row = row; - } + //each class gets its own unique color + public abstract Color getColor(); - public void setCol(int col) { - this.col = col; - } - public void setInfected(boolean infected) { - this.infected = infected; - } + // default = false, subclasses override what they are. Only zombie classes need to override + public boolean isHuman() { return true; } - public void setImmune(boolean immune) { - this.immune = immune; - } - - public void move(Entity[][] grid) { - } - - public void interact(Entity[][] grid) { - } - - public Color getColor() { - return Color.WHITE; - } - - public boolean isInfected() { - return infected; - } - - public boolean isImmune() { - return immune; - } - - public int getRow() { - return row; - } - - public int getCol() { - return col; - } - - public Entity[][] getNeighbors(Entity[][] grid) { - Entity[][] neighbors = new Entity[3][3]; - for (int r = -1; r <= 1; r++) { - for (int c = -1; c <= 1; c++) { - int newRow = row + r; - int newCol = col + c; - if (isInBounds(newRow, newCol, grid)) { - neighbors[r + 1][c + 1] = grid[newRow][newCol]; - } else { - neighbors[r + 1][c + 1] = null; - } - } - } - return neighbors; - } - - public boolean isInBounds(int r, int c, Entity[][] grid) { - return r >= 0 && r < grid.length && c >= 0 && c < grid[0].length; - } - -} + //only chosen one is immune + public boolean isImmune() { return false;} +} \ No newline at end of file diff --git a/src/main/java/Human.java b/src/main/java/Human.java index 500bb91..7b95bc1 100644 --- a/src/main/java/Human.java +++ b/src/main/java/Human.java @@ -1,2 +1,4 @@ -public class Human extends Entity{ +public class Human extends Entity +{ + } From 4977d74e23c3fb73369907c12c57eca5ac19cc9d Mon Sep 17 00:00:00 2001 From: Tsubasa Ito Date: Sat, 6 Dec 2025 20:35:17 -0800 Subject: [PATCH 4/5] CS142-fall2025 --- src/main/java/ChosenOne.java | 10 +- src/main/java/Entity.java | 2 +- src/main/java/Human.java | 15 ++- src/main/java/Medic.java | 30 +++++- src/main/java/Zombie.java | 31 +++++- src/main/java/ZombieGUI.java | 33 +++++- src/main/java/ZombieInvasionModel.java | 134 ++++++++++--------------- 7 files changed, 163 insertions(+), 92 deletions(-) diff --git a/src/main/java/ChosenOne.java b/src/main/java/ChosenOne.java index 37ce1f1..f6a8fbb 100644 --- a/src/main/java/ChosenOne.java +++ b/src/main/java/ChosenOne.java @@ -1,2 +1,10 @@ -public class ChosenOne extends Human{ +public class ChosenOne extends Human { + // TODO: not sure what action to do *maybe make neighbors immune* + // TODO: needs getColor(), toString(), performAction(), isImmune() + public void performAction(Entity[][] grid, double effectRate, int row, int column){ + + } + @Override + public boolean isImmune() { return true;} + } diff --git a/src/main/java/Entity.java b/src/main/java/Entity.java index 6be7546..c2afcda 100644 --- a/src/main/java/Entity.java +++ b/src/main/java/Entity.java @@ -20,4 +20,4 @@ public abstract class Entity { //only chosen one is immune public boolean isImmune() { return false;} -} \ No newline at end of file +} diff --git a/src/main/java/Human.java b/src/main/java/Human.java index 7b95bc1..9817658 100644 --- a/src/main/java/Human.java +++ b/src/main/java/Human.java @@ -1,4 +1,13 @@ -public class Human extends Entity -{ - +import java.awt.*; + +public class Human extends Entity { + // TODO: not sure what human action is + public void performAction(Entity[][] grid, double effectRate, int row, int column){ + + } + + public Color getColor() { return Color.GREEN; } + + @Override + public String toString() { return "H"; } } diff --git a/src/main/java/Medic.java b/src/main/java/Medic.java index 95e5fab..c3626d9 100644 --- a/src/main/java/Medic.java +++ b/src/main/java/Medic.java @@ -1,2 +1,30 @@ -public class Medic extends Human{ +import java.awt.*; + +public class Medic extends Human { + @Override // TODO: finish + public void performAction(Entity[][] grid, double effectRate, int row, int column){ + + double healRate = effectRate / 100.0; + for (int[] dir : DIRECTIONS) { + int newRow = row + dir[0]; + int newColumn = column + dir[1]; + + // Check bounds of grid + if (newRow < 0 || newRow >= grid.length || newColumn < 0 || newColumn >= grid[0].length) continue; + + Entity neighbor = grid[newRow][newColumn]; + //make sure it's human and NOT immune + if (!neighbor.isHuman()) { + if (Math.random() < effectRate) { + grid[newRow][newColumn] = new Human(); // chance to infect human + } + } + } + } + + @Override + public Color getColor() { return Color.YELLOW; } + + @Override + public String toString() { return "M"; } } diff --git a/src/main/java/Zombie.java b/src/main/java/Zombie.java index e90d335..99056b7 100644 --- a/src/main/java/Zombie.java +++ b/src/main/java/Zombie.java @@ -1,2 +1,31 @@ -public class Zombie extends Entity{ +import java.awt.*; + +public class Zombie extends Entity { + + public void performAction(Entity[][] grid, double effectRate, int row, int column) { + //DIRECTIONS from entity class; checks sorrounding neighbors + //Checks first neighbor {-1, 0} -> {row -1, column + 0}... + double infectionRate = effectRate / 100.0; + for (int[] dir : DIRECTIONS) { + int newRow = row + dir[0]; + int newColumn = column + dir[1]; + + // Check bounds of grid + if (newRow < 0 || newRow >= grid.length || newColumn < 0 || newColumn >= grid[0].length) continue; + + Entity neighbor = grid[newRow][newColumn]; + //make sure it's human and NOT immune + if (!neighbor.isImmune() && neighbor.isHuman()) { + if (Math.random() < effectRate) { + grid[newRow][newColumn] = new Zombie(); // chance to infect human + } + } + } + } + + public Color getColor() { return Color.red; } + + public boolean isHuman() { return false;} + @Override + public String toString() { return "Z"; } } diff --git a/src/main/java/ZombieGUI.java b/src/main/java/ZombieGUI.java index 4722b1f..1e1cb8b 100644 --- a/src/main/java/ZombieGUI.java +++ b/src/main/java/ZombieGUI.java @@ -51,8 +51,10 @@ public static Map showSettingsDialog(Frame parent, String title, final Map[] result = new Map[]{null}; + //user input is stored here okButton.addActionListener((ActionEvent e) -> { Map map = new HashMap<>(); + // TODO: add validation input here try { for (int i = 0; i < names.length; i++) { if (types[i] == Boolean.TYPE) { @@ -113,7 +115,23 @@ private static void openGridWindow(Map settings) { cell.setBorder(BorderFactory.createLineBorder(Color.BLACK)); gridPanel.add(cell); } - + boolean chosenOne = (boolean) settings.get("Enable ChosenOne"); + int infectionRate = (int) settings.get("Infection Rate"); + int healRate = (int) settings.get("Heal Rate"); + int numZombies = (int) settings.get("Number of Zombies"); + int numMedic = (int) settings.get("Number of Medic"); + + // Create the model with the correct argument order + ZombieInvasionModel model = new ZombieInvasionModel( + height, // row + width, // column + numZombies, + numMedic, + chosenOne, // boolean + infectionRate / 100.0, // convert to % if needed + healRate / 100.0 // convert to % if needed + ); + model.printEntity(); gridFrame.add(gridPanel, BorderLayout.CENTER); //updates simulation every 500ms (change if needed) Timer timer = new Timer(500, e -> { @@ -121,7 +139,18 @@ private static void openGridWindow(Map settings) { dayLabel.setText("Day: " + day[0]); // TODO: call your model.updateTick() here when model class is ready. dont forget - //ZombieInvasionModel.updateTick(); + model.updateTick(); + // redraw the grid based on current entity states + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + Entity entity = model.getGrid()[i][j]; + if (entity != null) { + gridPanel.getComponent(i * width + j).setBackground(entity.getColor()); + } else { + gridPanel.getComponent(i * width + j).setBackground(Color.WHITE); + } + } + } // redrawsw the grid gridPanel.repaint(); }); diff --git a/src/main/java/ZombieInvasionModel.java b/src/main/java/ZombieInvasionModel.java index c98d005..4411408 100644 --- a/src/main/java/ZombieInvasionModel.java +++ b/src/main/java/ZombieInvasionModel.java @@ -1,69 +1,38 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; - +//This class handles: +//Any rules of the simulation public class ZombieInvasionModel { private Entity[][] grid; //Size of grid private int row; private int column; - //Used to specify where Case Zero can Start + //Used to specify where Case Zero can Start NOTE: maybe scrap private int xCordinate; private int yCordinate; - //infection rate/heal rate / otherCustomization - private double infectionRate; - private double healRate; - //checks all possible sorrounding squares with - //each direction. - private static final int[][] DIRECTIONS = { - {-1, 0}, {1, 0}, {0, -1}, {0, 1}, - {-1, 1}, {-1, -1}, {1, 1}, {1, -1} - }; //Default values for # of zombies and medics and location private int numOfZombies; private int numOfMedics; + private double infectionRate; + private double healRate; + //Default value chosenOne being enabled + private boolean humanitySaved; + - //overloaded constructor creats Entity[][] grid - // with specified rows and column - //SHOULD BE SAME SIZE AS DIMESNIONS SET IN SETTINGS - public ZombieInvasionModel(int row, int column) { + //overloaded constructor creates Entity[][] grid + // with specified settings set in GUI + public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic, boolean humanitySaved, double infectionRate,double healRate){ this.row = row; this.column = column; + this.numOfZombies = numOfZombies; + this.numOfMedics = numOfMedic; + this.humanitySaved = humanitySaved; + this.infectionRate = infectionRate; + this.healRate = healRate; grid = new Entity[row][column]; - } - //Overloaded constructor that creates Entity[][]grid - //specifies how many humans, zombies, medic, ect. - //And specifies if ChosenOne is available option to put in grid - public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic) { - this(row, column); intiliazeEntities(); } - //Overloaded constructor that creates Entity[][]grid - //Specifies all of the above and WHERE CASE ZERO IS - //;where the first zombie starts in simulation - public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic, - boolean humanitySaved){ - this(row,column,numOfZombies,numOfMedic); - - } - //OverLoaded constructor that creates Entity[][]grid - //specifices infection rate, medic rate, ect., if chosen one allowed - public ZombieInvasionModel(int row, int column, int numOfZombies,int numOfMedic, - boolean humanitySaved, double infectionRate, double healRate){ - this(row,column,numOfZombies,numOfMedic, humanitySaved); - } - - public Entity[][] getGrid() { return grid; } - //Update all changes that happen on the grid - //objects are changed but color is changed in ZombieGUI class - public static void updateTick() { - //zombie entity becomes human? - //if trigger/flag call infect - //if trigger/flag call heal - //if trigger/flag call ability - // - } - //Helper method that creates the grid according to specifications private void intiliazeEntities(){ List types = new ArrayList<>(); @@ -88,37 +57,36 @@ private void intiliazeEntities(){ } } } - + //Update all changes that happen on the grid + //objects are changed but color is changed in ZombieGUI class + // BECAUSE OF ORDER OF METHOD CALLS INFECT TAKES PRIORITY + // I.E zombie will change grid first before humans + public void updateTick() { + infect(); + heal(); + } //Checks if square is zombie and able to infect - //calls on infectNeighbors method + //calls on performAction method polymorphism private void infect(){ - for (int i = 0; i < row; i++){ for (int j = 0; j < column; j++) { - Entity entity = grid[row][column]; - //if (entity.isZombie()) { // TODO: NEED BOOLEAN METHOD TO CHECK IF ZOMBIE - //call helpermethod that changes - //} + Entity entity = grid[i][j]; + if (!entity.isHuman()) { + entity.performAction(grid, infectionRate, i, j); + } } } } - //helper methods that CHANGE THE ACTUAL GRID OBJECT - //change happens here - private void infectNeighbors(){ - //if infect change this cordinate to be zombie IF ITS NOT ZOMBIE - int[][] possibleAttack = { - {-1, 0}, {1, 0}, {0, -1}, {0, 1}, - {-1,1}, {-1,-1}, {1,1}, {1,-1} - }; - - //if entity[x][y].isHuman() - //use infectionRate( - //create new Zombie at those cordinates) - - } - private void heal(){ - } - private void chosenOne(){ + //Check if square is zombie and able to heal + private void heal() { + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++) { + Entity entity = grid[i][j]; + if (entity instanceof Medic) { // TODO: need action for humans side + entity.performAction(grid,healRate, i, j); + } + } + } } //GETTER & SETTERS public int getColumn() { @@ -136,16 +104,16 @@ public int getRow() { public void setRow(int row) { this.row = row; } - //create print entity here + public Entity[][] getGrid() { return grid; } + //debug method + public void printEntity() { + for (int i = 0; i < row; i++){ + for (int j = 0; j < column; j++) { + Entity entity = grid[i][j]; + System.out.print("[" + entity.toString() + "]"); + if (j < column - 1) System.out.print(","); + } + System.out.println(); // new row + } + } } -//This class handles: -// -//The Entity[][] grid -// -//Infecting neighbors -// -//Medics healing zombies -// -//Moving entities (if you have movement) -// -//Any rules of the simulation \ No newline at end of file From 10050412a62035e01b4664a149c2e0cf7b0587c9 Mon Sep 17 00:00:00 2001 From: Tsubasa Ito Date: Wed, 10 Dec 2025 09:40:28 -0800 Subject: [PATCH 5/5] Cleanup the debug --- pom.xml | 12 +++++-- src/main/java/ChosenOne.java | 24 ++++++++++++++ src/main/java/Entity.java | 13 ++++++-- src/main/java/Human.java | 28 ++++++++++++++-- src/main/java/Medic.java | 11 +++++-- src/main/java/Zombie.java | 2 +- src/main/java/ZombieGUI.java | 25 ++++++-------- src/main/java/ZombieInvasionModel.java | 45 +++++++++++++++++++------- 8 files changed, 122 insertions(+), 38 deletions(-) diff --git a/pom.xml b/pom.xml index 16e46b4..419e2d7 100644 --- a/pom.xml +++ b/pom.xml @@ -23,8 +23,8 @@ 2.26.0 5.5.2 - 1.8 - 1.8 + 21 + 21 UTF-8 3.1.1 3.2.0 @@ -67,6 +67,14 @@ + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 21 + + org.apache.maven.plugins maven-surefire-plugin diff --git a/src/main/java/ChosenOne.java b/src/main/java/ChosenOne.java index f6a8fbb..f034a4c 100644 --- a/src/main/java/ChosenOne.java +++ b/src/main/java/ChosenOne.java @@ -1,10 +1,34 @@ +import java.awt.*; + public class ChosenOne extends Human { // TODO: not sure what action to do *maybe make neighbors immune* // TODO: needs getColor(), toString(), performAction(), isImmune() public void performAction(Entity[][] grid, double effectRate, int row, int column){ + for (int[] dir : DIRECTIONS) { + int newRow = row + dir[0]; + int newColumn = column + dir[1]; + + // Check bounds of grid + if (newRow < 0 || newRow >= grid.length || newColumn < 0 || newColumn >= grid[0].length) continue; + + Entity neighbor = grid[newRow][newColumn]; + + if (neighbor instanceof Human) { + if (Math.random() < effectRate) { + grid[newRow][newColumn].setImmune(true); + } + } + } } @Override public boolean isImmune() { return true;} + + @Override + public Color getColor() { return Color.BLUE; } + + @Override + public String toString() { return "C"; } + } diff --git a/src/main/java/Entity.java b/src/main/java/Entity.java index c2afcda..eec39a6 100644 --- a/src/main/java/Entity.java +++ b/src/main/java/Entity.java @@ -17,7 +17,16 @@ public abstract class Entity { // default = false, subclasses override what they are. Only zombie classes need to override public boolean isHuman() { return true; } - + // TODO: move to human class //only chosen one is immune - public boolean isImmune() { return false;} + + protected boolean immune = false; // default: not immune + + public boolean isImmune() { + return immune; + } + + public void setImmune(boolean immune) { + this.immune = immune; + } } diff --git a/src/main/java/Human.java b/src/main/java/Human.java index 9817658..1395fce 100644 --- a/src/main/java/Human.java +++ b/src/main/java/Human.java @@ -2,12 +2,34 @@ public class Human extends Entity { // TODO: not sure what human action is - public void performAction(Entity[][] grid, double effectRate, int row, int column){ + private boolean immune = false; - } + @Override + public void performAction(Entity[][] grid, double effectRate, int row, int column){ + for (int[] dir : DIRECTIONS) { + int newRow = row + dir[0]; + int newCol = column + dir[1]; - public Color getColor() { return Color.GREEN; } + if (newRow < 0 || newRow >= grid.length || newCol < 0 || newCol >= grid[0].length) continue; + Entity neighbor = grid[newRow][newCol]; + if (neighbor.isHuman()) { + if (Math.random() < effectRate) { + neighbor.setImmune(true); + } + } + } + } + @Override + public Color getColor() { + if (this.isImmune()) + return Color.ORANGE; + return Color.GREEN; + } @Override public String toString() { return "H"; } + + public boolean isImmune() { return immune;} + + public void setImmune(boolean immune) { this.immune = immune;} } diff --git a/src/main/java/Medic.java b/src/main/java/Medic.java index c3626d9..790ad4f 100644 --- a/src/main/java/Medic.java +++ b/src/main/java/Medic.java @@ -4,7 +4,7 @@ public class Medic extends Human { @Override // TODO: finish public void performAction(Entity[][] grid, double effectRate, int row, int column){ - double healRate = effectRate / 100.0; + //double healRate = effectRate / 100.0; for (int[] dir : DIRECTIONS) { int newRow = row + dir[0]; int newColumn = column + dir[1]; @@ -16,14 +16,19 @@ public void performAction(Entity[][] grid, double effectRate, int row, int colum //make sure it's human and NOT immune if (!neighbor.isHuman()) { if (Math.random() < effectRate) { - grid[newRow][newColumn] = new Human(); // chance to infect human + grid[newRow][newColumn] = new Human(); // chance to heal zombie } } } } @Override - public Color getColor() { return Color.YELLOW; } + public Color getColor() { + if (this.isImmune()) + return Color.CYAN; + return Color.YELLOW; + } + @Override public String toString() { return "M"; } diff --git a/src/main/java/Zombie.java b/src/main/java/Zombie.java index 99056b7..11ee6ad 100644 --- a/src/main/java/Zombie.java +++ b/src/main/java/Zombie.java @@ -5,7 +5,7 @@ public class Zombie extends Entity { public void performAction(Entity[][] grid, double effectRate, int row, int column) { //DIRECTIONS from entity class; checks sorrounding neighbors //Checks first neighbor {-1, 0} -> {row -1, column + 0}... - double infectionRate = effectRate / 100.0; + //double infectionRate = effectRate / 100.0; for (int[] dir : DIRECTIONS) { int newRow = row + dir[0]; int newColumn = column + dir[1]; diff --git a/src/main/java/ZombieGUI.java b/src/main/java/ZombieGUI.java index 1e1cb8b..3d6cadc 100644 --- a/src/main/java/ZombieGUI.java +++ b/src/main/java/ZombieGUI.java @@ -54,7 +54,6 @@ public static Map showSettingsDialog(Frame parent, String title, //user input is stored here okButton.addActionListener((ActionEvent e) -> { Map map = new HashMap<>(); - // TODO: add validation input here try { for (int i = 0; i < names.length; i++) { if (types[i] == Boolean.TYPE) { @@ -100,14 +99,14 @@ private static void openGridWindow(Map settings) { JFrame gridFrame = new JFrame("Zombie Invasion Simulation"); gridFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); gridFrame.setLayout(new BorderLayout()); - // NOTE: --------------Model + Day Counter------------------ + //-------------Model + Day Counter------------------ final int[] day = {0}; JLabel dayLabel = new JLabel("Day: 0"); dayLabel.setFont(new Font("Arial", Font.BOLD, 16)); - // NOTE: ----------------Grid Panel---------------- + //----------------Grid Panel---------------- JPanel gridPanel = new JPanel(new GridLayout(height, width)); for (int i = 0; i < height * width; i++) { JPanel cell = new JPanel(); @@ -131,14 +130,13 @@ private static void openGridWindow(Map settings) { infectionRate / 100.0, // convert to % if needed healRate / 100.0 // convert to % if needed ); - model.printEntity(); + gridFrame.add(gridPanel, BorderLayout.CENTER); //updates simulation every 500ms (change if needed) Timer timer = new Timer(500, e -> { day[0]++; // increment day dayLabel.setText("Day: " + day[0]); - // TODO: call your model.updateTick() here when model class is ready. dont forget model.updateTick(); // redraw the grid based on current entity states for (int i = 0; i < height; i++) { @@ -154,7 +152,7 @@ private static void openGridWindow(Map settings) { // redrawsw the grid gridPanel.repaint(); }); - // NOTE: ----------------Legend Panel---------------- + //---------------Legend Panel---------------- JPanel legendPanel = new JPanel(); legendPanel.setLayout(new BoxLayout(legendPanel, BoxLayout.Y_AXIS)); legendPanel.setBorder(BorderFactory.createTitledBorder("Legend")); @@ -162,21 +160,23 @@ private static void openGridWindow(Map settings) { legendPanel.add(createLegendItem(Color.RED, "Zombie")); legendPanel.add(createLegendItem(Color.GREEN, "Human")); legendPanel.add(createLegendItem(Color.YELLOW, "Medic")); - // NOTE: need to create another toggle Legend for ChosenOne if buttonSwitch is on + if (chosenOne) { legendPanel.add(createLegendItem(Color.BLUE, "Chosen One")); } + legendPanel.add(createLegendItem(Color.ORANGE, "Immune")); + legendPanel.add(createLegendItem(Color.CYAN, "Super Doctor")); gridFrame.add(legendPanel, BorderLayout.EAST); - // NOTE: ----------------Panel Default Settings---------------- + //---------------Panel Default Settings---------------- gridFrame.pack(); gridFrame.setSize(Math.min(width * 40 + 150, 1000), Math.min(height * 40 + 50, 800)); gridFrame.setLocationRelativeTo(null); gridFrame.setVisible(true); - // NOTE: ----------------Control Panel---------------- + //----------------Control Panel---------------- JButton startButton = new JButton("Start"); JButton pauseButton = new JButton("Pause"); JButton quitButton = new JButton("Quit"); - // NOTE: ---------------ACTION LISTENERS(buttons)------------- + //--------------ACTION LISTENERS(buttons)------------- startButton.addActionListener(e -> timer.start()); pauseButton.addActionListener(e -> timer.stop()); quitButton.addActionListener(e -> gridFrame.dispose()); @@ -216,11 +216,6 @@ public static void main(String[] args) { Map settings = showSettingsDialog(null, "Simulation Settings", names, types, defaults); - if (settings != null) { - settings.forEach((k, v) -> System.out.println(k + " = " + v)); - } else { - System.out.println("Settings canceled."); - } }); } } \ No newline at end of file diff --git a/src/main/java/ZombieInvasionModel.java b/src/main/java/ZombieInvasionModel.java index 4411408..5e09c20 100644 --- a/src/main/java/ZombieInvasionModel.java +++ b/src/main/java/ZombieInvasionModel.java @@ -40,9 +40,10 @@ private void intiliazeEntities(){ //For loop to add exact number of medics and zombies for (int i = 0; i < numOfZombies; i++) { types.add(new Zombie()); } for (int j = 0; j < numOfMedics; j++) { types.add(new Medic()); } - + if (humanitySaved) { types.add(new ChosenOne()); } //Remaining cells are humans - int remainingNumOfHumans = (row * column) - (numOfZombies + numOfMedics); + int totalEntities = types.size(); + int remainingNumOfHumans = (row * column) - totalEntities; for (int k = 0; k < remainingNumOfHumans; k++) { types.add(new Human()); } //Use collection interface to shuffle grid randomly @@ -62,28 +63,48 @@ private void intiliazeEntities(){ // BECAUSE OF ORDER OF METHOD CALLS INFECT TAKES PRIORITY // I.E zombie will change grid first before humans public void updateTick() { - infect(); - heal(); + // Optional snapshot for reference + Entity[][] snapshot = new Entity[row][column]; + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++) { + snapshot[i][j] = grid[i][j]; + } + } + + // Let entities act + infect(snapshot); // read from snapshot, modify grid + heal(snapshot); // read from snapshot, modify grid + immune(snapshot); } //Checks if square is zombie and able to infect //calls on performAction method polymorphism - private void infect(){ - for (int i = 0; i < row; i++){ + private void infect(Entity[][] snapshot) { + for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { - Entity entity = grid[i][j]; + Entity entity = snapshot[i][j]; // read from snapshot if (!entity.isHuman()) { - entity.performAction(grid, infectionRate, i, j); + entity.performAction(grid, infectionRate, i, j); // modify real grid } } } } //Check if square is zombie and able to heal - private void heal() { + private void heal(Entity[][] snapshot) { for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { - Entity entity = grid[i][j]; - if (entity instanceof Medic) { // TODO: need action for humans side - entity.performAction(grid,healRate, i, j); + Entity entity = snapshot[i][j]; // read from snapshot + if (entity instanceof Medic) { + entity.performAction(grid, healRate, i, j); // modify real grid + } + } + } + } + private void immune(Entity[][] snapshot) { + for (int i = 0; i < row; i++) { + for (int j = 0; j < column; j++) { + Entity entity = snapshot[i][j]; // read from snapshot + if (entity.isImmune()) { + entity.performAction(grid, .2, i, j); // modify real grid } } }