📄 2023N-HL-Monster
IB CS HL Paper 2 Option D — Monster Battle
Monster
public class Monster { public static final int ICE_MONSTER_TYPE = 1; public static final int WATER_MONSTER_TYPE = 2; public static final int FIRE_MONSTER_TYPE = 3; public String name = "Unknown"; public int health = 100; public int strength = 10; public int monsterType = 0; public Monster(String name, int health, int monsterType) { this.name = name; this.health = health; this.monsterType = monsterType; } // Q15(a): Construct the method attack(Monster defender) public void attack(Monster defender) { int damage = rollDice(); defender.health -= damage; if (defender.health > 0) { output(defender.name + " took " + damage + " damage, health now " + defender.health); } else { defender.health = 0; output(defender.name + " must leave the game"); } } private static int rollDice() { return new java.util.Random().nextInt(12) + 1; } public static void output(String message) { System.out.println(message); } // Q17: Effectiveness table & getAttackingWeight public static int[][] effectiveness = { {0, -4, 2}, // Att: ICE — vs ICE, vs WATER, vs FIRE {-8, 0, 5}, // Att: WATER — vs ICE, vs WATER, vs FIRE {6, -3, 0} // Att: FIRE — vs ICE, vs WATER, vs FIRE }; // Q17(b): return the weight for attacker vs defender public static int getAttackingWeight(Monster attacker, Monster defender) { return effectiveness[attacker.monsterType - 1][defender.monsterType - 1]; } }
WaterMonster
public class WaterMonster extends Monster { public WaterMonster(String name, int health) { super(name, health, Monster.WATER_MONSTER_TYPE); } }
FireMonster
public class FireMonster extends Monster { public FireMonster(String name, int health) { super(name, health, Monster.FIRE_MONSTER_TYPE); } }
Arena
import java.util.LinkedList; public class Arena { public Monster[] monsters = new Monster[10]; int monsterCount = 0; // the number of monsters currently in array public LinkedList<Turn> gameLog = new LinkedList<>(); public void addMonster(Monster M) { if (monsterCount >= monsters.length) { output("Arena is full, cannot add " + M.name); return; } for (int i = 0; i < monsterCount; i++) { if (monsters[i] == M) { output(M.name + " is already in the arena"); return; } } monsters[monsterCount] = M; monsterCount++; } public void removeMonster(Monster M) { int found = -1; for (int i = 0; i < monsterCount; i++) { if (monsters[i] == M) { found = i; break; } } if (found == -1) return; for (int i = found; i < monsterCount - 1; i++) { monsters[i] = monsters[i + 1]; } monsters[monsterCount - 1] = null; monsterCount--; } public void doOneOnOneBattle(Monster A, Monster B) { while (A.health > 0 && B.health > 0) { A.attack(B); B.attack(A); } if (A.health > B.health) { output(A.name + " WINS!"); removeMonster(B); } else if (B.health > A.health) { output(B.name + " WINS!"); removeMonster(A); } else { output("IT IS A DRAW!"); } } public static void output(String message) { System.out.println(message); } // Q17(c): recommendAttackingMonster — returns the best monster to attack defender public Monster recommendAttackingMonster(Monster defender) { Monster best = null; int bestWeight = Integer.MIN_VALUE; int bestHealth = -1; for (int i = 0; i < monsterCount; i++) { Monster m = monsters[i]; int w = Monster.getAttackingWeight(m, defender); if (w > bestWeight || (w == bestWeight && m.health > bestHealth)) { best = m; bestWeight = w; bestHealth = m.health; } } return best; } // Q18(b): rewindTurns — restore health to rewinder from last numberOfTurns turns public void rewindTurns(int numberOfTurns, Monster rewinder) { int checked = 0; for (int i = gameLog.size() - 1; i >= 0 && checked < numberOfTurns; i--) { Turn t = gameLog.get(i); checked++; if (t.to == rewinder) { rewinder.health += t.damage; } } } }
Turn
public class Turn { long timestamp; Monster from; Monster to; int damage; public Turn(Monster from, Monster to, int damage) { this.timestamp = System.currentTimeMillis(); this.from = from; this.to = to; this.damage = damage; } }
+ Add Class
⚡ Java Execution Console
Save HTML
▶ Run All
Clear
public class Main { public static void main(String[] args) { System.out.println("===== Monster Battle - Full Demo ====="); // === Q14(e): Create monster instances === FireMonster flamey = new FireMonster("Flamey", 40); WaterMonster splashy = new WaterMonster("Splashy", 25); FireMonster windy = new FireMonster("Windy", 35); WaterMonster squishy = new WaterMonster("Squishy", 20); Monster.output("Created " + flamey.name + " (FIRE, hp=" + flamey.health + ")"); Monster.output("Created " + splashy.name + " (WATER, hp=" + splashy.health + ")"); Monster.output("Created " + windy.name + " (FIRE, hp=" + windy.health + ")"); // === Q17(b): Test getAttackingWeight === Monster.output("\n--- Q17(b): getAttackingWeight ---"); Monster.output("FIRE->WATER: " + Monster.getAttackingWeight(flamey, splashy) + ", WATER->FIRE: " + Monster.getAttackingWeight(splashy, flamey)); Monster.output("ICE->WATER: " + Monster.getAttackingWeight( new Monster("Dummy", 1, Monster.ICE_MONSTER_TYPE), splashy)); // === Q15(d): Test addMonster === Monster.output("\n--- Q15(d): Arena.addMonster ---"); Arena arena = new Arena(); arena.addMonster(flamey); arena.addMonster(splashy); arena.addMonster(windy); arena.addMonster(squishy); arena.addMonster(flamey); // duplicate — should warn Monster.output("Arena has " + arena.monsterCount + " monster(s): " + arena.monsters[0].name + ", " + arena.monsters[1].name + ", " + arena.monsters[2].name + ", " + arena.monsters[3].name); // === Q17(c): Test recommendAttackingMonster === Monster.output("\n--- Q17(c): recommendAttackingMonster ---"); Monster best = arena.recommendAttackingMonster(flamey); Monster.output("Best vs Flamey: " + best.name + " (weight=" + Monster.getAttackingWeight(best, flamey) + ")"); best = arena.recommendAttackingMonster(splashy); Monster.output("Best vs Splashy: " + best.name + " (weight=" + Monster.getAttackingWeight(best, splashy) + ")"); // === Q15(a): Test attack in one-on-one battle === Monster.output("\n--- Q15(a): Battle - Flamey vs Splashy ---"); arena.doOneOnOneBattle(flamey, splashy); Monster.output("After battle: " + flamey.name + " hp=" + flamey.health + ", " + splashy.name + " hp=" + splashy.health); Monster.output("Arena monsterCount after battle: " + arena.monsterCount); // === Q16(b): Test removeMonster === Monster.output("\n--- Q16(b): removeMonster ---"); arena.addMonster(splashy); // add Splashy back arena.removeMonster(splashy); Monster.output("After removing Splashy, arena has " + arena.monsterCount + " monster(s)"); if (arena.monsterCount > 0) { for (int i = 0; i < arena.monsterCount; i++) { System.out.println(" [" + i + "] " + arena.monsters[i].name); } } // === Q18(b): Test rewindTurns === Monster.output("\n--- Q18(b): rewindTurns demo ---"); Arena arena2 = new Arena(); FireMonster a = new FireMonster("Fuego", 50); WaterMonster b = new WaterMonster("Aqua", 50); arena2.gameLog.add(new Turn(a, b, 10)); arena2.gameLog.add(new Turn(b, a, 8)); arena2.gameLog.add(new Turn(a, b, 6)); arena2.gameLog.add(new Turn(b, a, 4)); Monster.output("Aqua hp before rewind: " + b.health); Monster.output("Windy hp before rewind: " + a.health); // rewindTurns(2, b) — last 2 turns: Turn04(b->a,4), Turn03(a->b,6) // turns where b is receiver: only Turn03(a->b,6) in last 2 turns arena2.rewindTurns(2, b); Monster.output("After rewindTurns(2, Aqua): Aqua hp=" + b.health + " (restored 6)"); Monster.output("gameLog unchanged: " + arena2.gameLog.size() + " turns remain."); System.out.println("\n=== Demo Complete ==="); } }
▶ Run All to execute.