DTANK source code FILE from dtank42 from bil lewis and Matteo Pedrotti on 1/28/2008 created by Jerimiah Hiam, 1 Feb 2008 *************************************************************************************** dTank.java *************************************************************************************** import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.battle.BattleInitializer; import acsl.dTank.ui.StartupMenu; public class dTank { public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { if (args.length == 0) { StartupMenu.main(args); return; } BattleInitializer.main(args); } } *************************************************************************************** HumanCommander.java *************************************************************************************** import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.communicator.CommanderSocketCommunicator; // java HumanCommander Localhost Blue Sherman Display 1 public class HumanCommander { public static void main(String[] args) throws UnknownHostException, IOException { String serverName = CommanderSocketCommunicator.LOOPBACK; String[] args2 = new String[0]; if (args.length > 0) { serverName = args[0]; args2 = new String[args.length - 1]; for (int i = 1; i < args.length; i++) args2[i - 1] = args[i]; } CommanderSocketCommunicator.setServerName(serverName); acsl.dTank.commander.HumanCommander.main(args2); } } *************************************************************************************** AFV.java *************************************************************************************** /** * All vehicles know about themselves, who their controller is, and nothing else. * A Mover object takes care of moving them. This allows us to change the physical * behavior of the system (eg, moving over hills slows you down) without touching * the definition of the tanks. */ package acsl.dTank.afv; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.Utility; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.AFVController; import acsl.dTank.projectile.Projectile; public abstract class AFV { private static int idCounter = 0; public static final double MAX_TURNING_DEGREES_PER_SECOND = 90.0; private final String name; private AFVType afvType; private Location location = new Location(0.0, 0.0); private Heading heading = new Heading(); private Heading desiredHeading = new Heading(); private Velocity velocity = new Velocity(); private double throttle = 0.0; private Heading turretHeading = new Heading(); // 0-259 private Heading desiredTurretHeading = new Heading(); // 0-259 private double gunElevation = 0; // -5.0 - +20.0 private int ammunitionRemaining; private AFVController controller; private double fuelRemaining; private double desiredGunElevation; private long reloadStartTime = 0; private int reloadDelay = 60000; // ms private long stationarySince; private boolean treadOperational = true; boolean gunOperational = true, radioOperational = true, crewHealthy = true, destroyed = false; private double armorDamage = 0.0; private int successfulShots; private double intendedRange = Double.MAX_VALUE; // Cheap way of faking gun elevation public AFV(AFVType afvType, AFVController controller) { this.afvType = afvType; name = controller.getNationality().getName() + "_" + afvType.getName() + idCounter; if (!Parameters.isTesting()) idCounter++; this.controller = controller; ammunitionRemaining = afvType.getAmmunitionCapacity(); fuelRemaining = afvType.getFuelCapacity(); } public String getName() { return name; } public AFVType getAFVType() { return afvType; } public double getHeading() { return heading.getHeading(); } public double getTurretHeading() { return turretHeading.getHeading(); } public double getGunElevation() { return gunElevation; } public int getAmmunitionRemaining() { return ammunitionRemaining; } public Nationality getNationality() { Nationality nationality = controller.getNationality(); return nationality; } public double getFuelRemaining() { return fuelRemaining; } public void turn(double seconds) { double desired = desiredHeading.getHeading(); double current = heading.getHeading(); double delta = desired - current; double newHeading = 0.0; if (delta < -180.0) delta += 360.0; if (delta > 180.0) delta -= 360.0; double possibleRotation = seconds * MAX_TURNING_DEGREES_PER_SECOND; if (delta >= 0.0) { if (possibleRotation > delta) newHeading = desired; else newHeading = current + delta; } else { if (possibleRotation < delta) newHeading = desired; else newHeading = current + delta; } heading.setHeading(newHeading); } public double getDesiredSpeedMPS() { return afvType.getMaxSpeedMPS() * throttle; } public double getThrottle() { return throttle; } public void setThrottle(double throttle) { if ((throttle < -1.0) || (throttle > 1.0)) throw new RuntimeException("throttle out of bounds " + throttle); this.throttle = throttle; } public String toString() { return "<" + name + " " + location + ">"; } public double getMaxSpeed() { return afvType.getMaxSpeedMPS(); } public double getSpeed() { return velocity.getSpeedMPS(); } public double getSpeedKPH() { return velocity.getSpeedKPH(); } public boolean atLocation(double x, double y) { if ((Math.abs(x - location.getX())) > 0.1) return false; if ((Math.abs(y - location.getY())) > 0.1) return false; return true; } public void setLocation(double x, double y) { // if (x < 0.0 || y < 0.0 || x > (Battlefield.getWidth() - 1.0) // || y > (Battlefield.getWidth() - 1.0)) // throw new RuntimeException("Illegal location " + x + "x" + y); if (isDestroyed()) return; location.set(x, y); } public void setSpeedMPS(double speed) { if (isDestroyed()) return; if (speed == 0.0) stationarySince = Battlefield.getGameTime(); velocity.setSpeedMPS(speed); } public void setSpeedKPH(double speed) { if (isDestroyed()) return; if (speed == 0.0) stationarySince = Battlefield.getGameTime(); velocity.setSpeedKPH(speed); } public AFVController getController() { return controller; } public void setHeading(double heading) { if (isDestroyed()) return; this.heading.setHeading(heading); } public double getY() { return location.getY(); } public double getX() { return location.getX(); } public void fire(double heading) { if (isDestroyed() || ammunitionRemaining == 0 || (!isLoaded())) { Logger.log(name + " not ready to fire"); return; } ammunitionRemaining--; Projectile p = Projectile.create(this, heading, intendedRange); Battlefield.addProjectile(p); reloadStartTime = Battlefield.getGameTime(); } public boolean isLoaded() { if (ammunitionRemaining == 0) return false; return ((reloadStartTime + reloadDelay) < Battlefield.getGameTime()); } public void setTurretHeading(double d) { if (isDestroyed()) { Logger.log(name + " destroyed"); return; } turretHeading.setHeading(d); } public void receivedHit(Projectile projectile) { if (isDestroyed()) { return; } setDestroyed(); setSpeedMPS(0.0); } public void setDesiredHeading(double heading) { if (isDestroyed()) { Logger.log(name + " destroyed"); return; } desiredHeading.setHeading(heading); } public void setDesiredTurretHeading(double desiredTurretHeading) { if (isDestroyed()) { Logger.log(name + " destroyed"); return; } this.desiredTurretHeading.setHeading(desiredTurretHeading); } public static AFV create(String afvType, AFVController c) { return create(AFVType.lookup(afvType), c); } public static Tank create(AFVType afvType, AFVController controller) { Tank t = new Tank(afvType, controller); return t; } public void setGunElevation(double gunElevation) { if (isDestroyed()) { Logger.log(name + " destroyed"); return; } this.gunElevation = gunElevation; } public void setAmmunitionRemaining(int ammunitionRemaining) { this.ammunitionRemaining = ammunitionRemaining; } public double getDesiredHeading() { return desiredHeading.getHeading(); } public double getDesiredTurretHeading() { return desiredTurretHeading.getHeading(); } public double getDesiredGunElevation() { return desiredGunElevation; } public void setDesiredGunElevation(double desiredGunElevation) { this.desiredGunElevation = desiredGunElevation; } public void updateLocation(double deltaX, double deltaY) { if (isDestroyed()) return; location.update(deltaX, deltaY); } public void sendRadioMessage(String radioMessage) { controller.sendRadioMessage(radioMessage); } public double getArmorThickness(boolean isSideImpact) { if (isSideImpact) return afvType.getFrontArmorThickness() / 2.0; return afvType.getFrontArmorThickness(); } public double getProjectileMass() { return afvType.getProjectileMass(); } public double getConsumptionRate() { return afvType.getConsumptionRate(); } public void updateFuelRemaining(double fuelConsumed) { if (fuelRemaining < fuelConsumed) { fuelRemaining = 0.0; return; } fuelRemaining -= fuelConsumed; } public boolean isStabilized() { return afvType.isStabilized(); } public long stationarySince() { return stationarySince; } public double getVisibilityArc() { return afvType.getTurretVisibilityArc(); } public void setTreadDamaged() { treadOperational = false; } public boolean isTreadOperational() { return treadOperational; } public String getStatusString() { return getNationality().getName() + ":\t" + getName() + " AFV_is:" + getOperationalStatusString() + " Tread:" + (isTreadOperational() ? "Operational" : "Nonoperational") + " Shells_Fired:" + (afvType.getAmmunitionCapacity() - ammunitionRemaining) + " Successful_Shots:" + successfulShots; } private String getOperationalStatusString() { return isDestroyed() ? "Destroyed" : "Operational" + " Damage:" + Utility.shorten(getArmorDamage()) + " Radio:" + (isRadioOperational() ? "Operational" : "Nonoperational"); } public boolean isDestroyed() { return destroyed; } public boolean isFullyOperational() { if (gunOperational && radioOperational && crewHealthy && !destroyed) return true; return false; } public void setDestroyed() { destroyed = true; } public boolean getOperational() { return !isDestroyed(); } public boolean isCrewHealthy() { return crewHealthy; } public boolean isRadioOperational() { return radioOperational; } public boolean isDamaged() { if (destroyed) return true; if (armorDamage > 0.0) return true; if (gunOperational && radioOperational && crewHealthy) return false; return true; } public double getArmorDamage() { return armorDamage; } public double incArmorDamage(double d) { armorDamage += d; return armorDamage; } public void setRadioDestroyed() { radioOperational = false; } public void setCrewSpacy() { crewHealthy = false; } public void incSuccessfulShot() { successfulShots++; } public void setIntendedRange(double intendedRange) { this.intendedRange = intendedRange; } } *************************************************************************************** AFVType.java *************************************************************************************** /* * This describes the different types of AFVs. */ package acsl.dTank.afv; import java.util.HashMap; public class AFVType { //--- specific weights are in Kg/dm3 --- public static final double LEAD_SPECIFIC_WEIGHT = 11.34; public static final double STEEL_SPECIFIC_WEIGHT = 7.8; //----- public static final AFVType TEST_TANK = new AFVType("Test", 120.0, 800.0, 90, 78.0, true, 125.0, 211.0, 80.0); public static final AFVType MATILDA = new AFVType("Matilda", 40.0, 800.0, 90, 78.0, true, 25.0, 211.0, 80.0); public static final AFVType SHERMAN = new AFVType("Sherman", 75.0, 800.0, 90, 50.0, true, 40.0, 662.0, 200.0); public static final AFVType PANTHER = new AFVType("Panther", 75.0, 1000.0, 88, 100.0, false, 46.0, 730.0, 200.0); public static final AFVType TIGER = new AFVType("Tiger", 88.0, 1000.0, 88, 100.0, false, 38.0, 534.0, 140.0); public static final AFVType KING_TIGER = new AFVType("King_Tiger", 88.0, 1000.0, 80, 180.0, false, 16.0, 860.0, 120.0); public static final AFVType PKW_IV = new AFVType("PKW_IV", 75.0, 800.0, 80, 30.0, false, 40.0, 470.0, 200.0); public static final AFVType SOLDIER = new AFVType("SOLDIER", 10.0, 400.0, 15, 1.0, false, 5.0, 2.0, 100.0, "triangle.gif", "Head.gif"); public static final AFVType OFFICER = new AFVType("OFFICER", 10.0, 400.0, 15, 1.0, false, 5.0, 2.0, 100.0, "cross.gif", "Head.gif"); public static final AFVType CIVILIAN = new AFVType("CIVILIAN", 10.0, 400.0, 2, 1.0, false, 5.0, 2.0, 100.0, "circle.gif", "Head.gif"); private static final double SECONDS_PER_HOUR = 60 * 60; private static HashMap afvsTable = new HashMap(); private final double turretVisibliltyArc = 45.0; private String name; // "Sherman" private double shellSize; // mm private double shellMass; // kg private double muzzleVelocity; // m/s private int ammunitionCapacity; // number of shells carried private double maxSpeed; // m/s private double fuelCapacity; // liters private double fuelConsumptionRateLPS; // ~0.02L/s @ half throttle on road private double frontArmor; private boolean isStabilized; private String bodyImageFilename = "tank.gif", turretImageFilename = "turret.gif"; public AFVType(String name, double shellSize, double muzzleVelocity, int ammunitionCapacity, double frontArmor, boolean isStabilized, double maxSpeedKPH, double fuelCapacity, double range, String bodyImageFilename, String turretImageFilename) { this(name, shellSize, muzzleVelocity, ammunitionCapacity, frontArmor, isStabilized, maxSpeedKPH, fuelCapacity, range); this.bodyImageFilename = bodyImageFilename; this.turretImageFilename = turretImageFilename; } public AFVType(String name, double shellSize, double muzzleVelocity, int ammunitionCapacity, double frontArmor, boolean isStabilized, double maxSpeedKPH, double fuelCapacity, double range) { this.name = name; this.shellSize = shellSize; //this.shellMass = shellSize * shellSize * shellSize / 80000.0; //approx calculate mass of a cube of lead //--- (dm^3)* this.shellMass = Math.pow((shellSize/100.0),3)*LEAD_SPECIFIC_WEIGHT; this.muzzleVelocity = muzzleVelocity; this.ammunitionCapacity = ammunitionCapacity; this.frontArmor = Math.pow(frontArmor,2)*STEEL_SPECIFIC_WEIGHT; this.isStabilized = isStabilized; this.maxSpeed = maxSpeedKPH * Velocity.KPH_TO_MPS; this.fuelCapacity = fuelCapacity; // max range is @ max speed/2. double fuelConsumptionLPH = (fuelCapacity / range) * (maxSpeedKPH / 2); this.fuelConsumptionRateLPS = fuelConsumptionLPH / SECONDS_PER_HOUR; } public static void initializeAll() { TEST_TANK.initialize(); SHERMAN.initialize(); TIGER.initialize(); MATILDA.initialize(); KING_TIGER.initialize(); PANTHER.initialize(); PKW_IV.initialize(); SOLDIER.initialize(); OFFICER.initialize(); CIVILIAN.initialize(); } private void initialize() { afvsTable.put(getName(), this); } public String getName() { return name; } public double getShellSize() { return shellSize; } public double getMuzzleVelocity() { return muzzleVelocity; } public int getAmmunitionCapacity() { return ammunitionCapacity; } public double getMaxSpeedMPS() { return maxSpeed; } public static AFVType lookup(String name) { AFVType type = (AFVType) afvsTable.get(name); if (type == null) throw new RuntimeException("no such tank: " + name); return type; } public double getFrontArmorThickness() { return frontArmor; } public double getProjectileMass() { return shellMass; } public double getConsumptionRate() { return fuelConsumptionRateLPS; } public double getFuelCapacity() { return fuelCapacity; } public boolean isStabilized() { return isStabilized; } public double getBreakdownProbability() { if (this == KING_TIGER) return 0.01; // 1% per hour breakdown return 0.0; } public double getTurretVisibilityArc() { return turretVisibliltyArc; } public String getBodyImageFilename() { return bodyImageFilename; } public String getTurretImageFilename() { return turretImageFilename; } } *************************************************************************************** dTank.java *************************************************************************************** package acsl.dTank.afv; public class Heading { private double heading; // 0.0-359.999 public double getHeading() { return heading; } public void setHeading(double heading) { while (heading >= 360.0) heading -= 360.0; while (heading < 0.0) heading += 360.0; this.heading = heading; } public void turn(double degrees) { double h = heading + degrees; setHeading(h); } } *************************************************************************************** Location.java *************************************************************************************** package acsl.dTank.afv; public class Location { public static Location RIGHT_CENTER; public static Location LEFT_CENTER; private double x, y; // m from {0, 0} -- upper left on display public Location(double x, double y) { this.x = x; this.y = y; } public static void initialize(double width, double height, double fs) { RIGHT_CENTER = new Location(width - (fs + 1), height / 2); LEFT_CENTER = new Location(fs + 1, height / 4); } public void set(Location location) { x = location.getX(); y = location.getY(); } public double getY() { return y; } public double getX() { return x; } public void update(double deltaX, double deltaY) { x += deltaX; y += deltaY; } public String toString() { return "{" + x + ", " + y + "}"; } public void set(double x, double y) { this.x = x; this.y = y; } } *************************************************************************************** Nationality.java *************************************************************************************** /* * Nationality defines the two sides of the battle, along with starting positions and tank colors. */ package acsl.dTank.afv; public class Nationality { public final static Nationality BLUE = new Nationality("Blue"); public final static Nationality RED = new Nationality("Red"); public static final Nationality WHITE = new Nationality("WHITE"); private String name; public Nationality(String name) { this.name = name; } public String getName() { return name; } public double getStartingLocationX() { if (this == BLUE) return Location.RIGHT_CENTER.getX(); if (this == RED) return Location.LEFT_CENTER.getX(); if (this == WHITE) return Location.LEFT_CENTER.getX(); throw new RuntimeException("Immpossible"); } public boolean equals(Object o){ String nat = null; if(o instanceof Nationality){ nat = ((Nationality)o).getName(); }else if(o instanceof String){ nat = (String)o; } if(nat==null) return false; return nat.equals(this.name); } public static Nationality lookup(String nationality) { if (nationality.equals("Blue")) return BLUE; if (nationality.equals("Red")) return RED; if (nationality.equals("WHITE")) return WHITE; throw new RuntimeException("No such nationality " + nationality); } public static Nationality opposite(Nationality nationality) { if (nationality == RED) return BLUE; return RED; } } *************************************************************************************** Tank.java *************************************************************************************** package acsl.dTank.afv; import acsl.dTank.controller.AFVController; public class Tank extends AFV { public Tank(AFVType afvType, AFVController controller) { super(afvType, controller); } } *************************************************************************************** Velocity.java *************************************************************************************** package acsl.dTank.afv; public class Velocity { public static final double RADIANS_PER_DEGREE = Math.PI / 180.0; public static final double KPH_TO_MPS = 1000.0 / 3600.0; private double speed = 0.0;// m/s private double heading = 0.0; // 0.0 - 359.99999 private double elevation = 0.0; // -20.0 - 45.0 public Velocity(double heading, double elevation, double speed) { if (elevation < -20.0 || elevation > 45.0) throw new RuntimeException("Impossible gun elevation " + elevation); this.speed = speed; this.heading = heading; this.elevation = elevation; } public Velocity() { } public Velocity(double heading, double speed) { this.speed = speed; this.heading = heading; this.elevation = 0.0; } public double getSpeedMPS() { return speed; } public void setSpeedMPS(double mps) { speed = mps; } public void setSpeedKPH(double kph) { speed = kph * KPH_TO_MPS; } public void setHeading(double heading) { this.heading = heading; } public double calculateDeltaX(double seconds) { return seconds * speed * Math.sin(heading * RADIANS_PER_DEGREE) * 1.0; } public double calculateDeltaY(double seconds) { return seconds * speed * Math.cos(heading * RADIANS_PER_DEGREE) * -1.0; } public double getSpeedKPH() { return speed / KPH_TO_MPS; } public boolean equals(Object o) { if (!(o instanceof Velocity)) return false; Velocity v = (Velocity) o; if ((Math.abs(v.elevation - elevation)) > 0.01) return false; if ((Math.abs(v.speed - speed)) > 0.01) return false; if ((Math.abs(v.heading - heading)) > 0.01) return false; return true; } public double getHeading() { return heading; } } *************************************************************************************** AFVConfiguration.java *************************************************************************************** package acsl.dTank.battle; public class AFVConfiguration { String battalionCommanderName; String commander; String tank; String number; private String[] commandLineArguments; private String withDisplay; public AFVConfiguration(String battalionCommanderName, String commander, String tank, String number, String withDisplay, String[] commandLineArguments) { this.battalionCommanderName = battalionCommanderName; this.commander = commander; this.tank = tank; this.number = number; this.withDisplay = withDisplay; this.commandLineArguments = commandLineArguments; } public AFVConfiguration(String battalionCommanderName, String commander, String tank, String number, String withDisplay) { this(battalionCommanderName, commander, tank, number, withDisplay, new String[0]); } public String[] getCommandLineArguments() { return commandLineArguments; } public String getNumber() { return number; } public String getBattalionCommanderName() { return battalionCommanderName; } public String getCommander() { return commander; } public String getTank() { return tank; } public String getWithDisplay() { return withDisplay; } public String toString() { StringBuffer ret = new StringBuffer(); ret.append(commander + " " + battalionCommanderName + " " + tank + " " + withDisplay + " " + number); if (commandLineArguments.length > 0) ret.append(" ("); for (int i = 0; i < commandLineArguments.length; i++) ret.append(commandLineArguments[i] + " "); if (commandLineArguments.length > 0) ret.append(")"); return ret.toString(); } } *************************************************************************************** Battalion.java *************************************************************************************** /** * A battalion is the set of AFVs commanded by one side. It is only * used for setup and getting the commander's name (Joe, Jane, etc.) */ package acsl.dTank.battle; import java.util.ArrayList; import java.util.List; public class Battalion { public static final Battalion EMPTY_BATTALION = new Battalion( "Empty Battalion"); String battalionCommanderName; private List afvConfigurations = new ArrayList(); public Battalion(String bcn) { battalionCommanderName = bcn; } public void addAFVConfigurations(AFVConfiguration c) { afvConfigurations.add(c); } public List getAFVConfigurations() { return afvConfigurations; } public String getCommanderName() { return battalionCommanderName; } } *************************************************************************************** Battle.java *************************************************************************************** /** * This describes the battle about to take place and starts and ends * the battle. */ package acsl.dTank.battle; import java.io.FileWriter; import java.util.List; import acsl.dTank.Parameters; import acsl.dTank.afv.Nationality; import acsl.dTank.commander.Commander; public class Battle { Battalion BlueBattalion, RedBattalion, whiteBattalion; public Battle(Battalion b0, Battalion b1, Battalion b2) { BlueBattalion = b0; RedBattalion = b1; whiteBattalion = b2; } public void runBattle() throws InterruptedException { startAFVs(Nationality.RED, RedBattalion.getAFVConfigurations()); startAFVs(Nationality.BLUE, BlueBattalion.getAFVConfigurations()); startAFVs(Nationality.WHITE, whiteBattalion.getAFVConfigurations()); BattleInitializer.pause(Parameters.getStartUpPause()); waitUntilBattleOver(Parameters.getBattleDuration()); } private void startAFVs(Nationality nationality, List afvConfigurations) throws InterruptedException { for (int i = 0, size = afvConfigurations.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) afvConfigurations.get(i); String cName = "acsl.dTank.commander." + c.getCommander(); String[] commandLineArguments = c.getCommandLineArguments(); String[] cmd = new String[commandLineArguments.length + 5]; // RemoteSmartCommander Red Sherman display 2 arg0 arg1 arg2 cmd[0] = cName; cmd[1] = nationality.getName(); cmd[2] = c.getTank(); cmd[3] = c.getWithDisplay(); cmd[4] = c.getNumber(); for (int j = 0; j < commandLineArguments.length; j++) cmd[j + 5] = commandLineArguments[j]; // {"acsl.dTank.commander.SmartCommander", "Blue", "Sherman", // "Display", "3", "arg0", "arg1", "arg2", ..} Commander.createCommanders(cmd); } } private static void waitUntilBattleOver(int battleDuration) { // long timeout = 5000; // the time to wait to bail out // long endTime = 0; // support time for real battle time synchronized (Battlefield.class) { while (!timeExpired(battleDuration)) { try { Battlefield.class.wait(); } catch (InterruptedException e) { } // To allow the debug interface to work, we can't get fancy here. // I suppose you could put a flag in the config file, and allow early termination // if it's set, but that would have to be set false to use the debug interface. // If you want this behavior, have the simulation thread check for your // condition and call endBattle(). That'll be cleaner than doing it here. // force battle to end because all (enemy) tanks destroyed // int dest = 0; // if (Battlefield.getNBlueAFVs() == Battlefield // .getNBlueDestroyed()) // dest++; // if (Battlefield.getNRedAFVs() == // Battlefield.getNRedDestroyed()) // dest++; // if (Battlefield.getNWhiteAFVs() == Battlefield // .getNWhiteDestroyed()) // dest++; // if (dest >= 2) { // if (endTime > 0) { // if (System.currentTimeMillis() - endTime > timeout) { // break; // } // } else { // endTime = System.currentTimeMillis(); // } // } } } } private static boolean timeExpired(int battleDuration) { if (Battlefield.getGameTime() < battleDuration) return false; return true; } public String getRedCommanderName() { return RedBattalion.getCommanderName(); } public String getBlueCommanderName() { return BlueBattalion.getCommanderName(); } public String getWhiteCommanderName() { return whiteBattalion.getCommanderName(); } public Battalion getWhiteBattalion() { return whiteBattalion; } public Battalion getRedBattalion() { return RedBattalion; } public Battalion getBlueBattalion() { return BlueBattalion; } } *************************************************************************************** Battlefield.java *************************************************************************************** /** * The battlefield knows about the AFVs and projectiles. It forwards the * simulation's request for updates to them. */ package acsl.dTank.battle; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.afv.Nationality; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; import acsl.dTank.mover.AFVMover; import acsl.dTank.mover.Mover; import acsl.dTank.mover.ProjectileMover; import acsl.dTank.mover.QuantizedAFVMover; import acsl.dTank.mover.RealisticAFVMover; import acsl.dTank.projectile.Projectile; public class Battlefield { private static List tanks = new ArrayList(), projectiles = new ArrayList(); private static Map map; private static boolean initialized; private Battlefield() { } public static void create(String filename, double physicalWidth, double physicalHeight) { List lines = Map.read(filename); Parameters.setPhysicalDimensions(physicalWidth, physicalHeight); Parameters.setDimensions(lines.size(), lines.size()); create(lines, physicalWidth, physicalHeight); } public static void create(List lines, double physicalWidth, double physicalHeight) { map = Map.create(lines, physicalWidth, physicalHeight); Location .initialize(physicalWidth, physicalHeight, map.getFeatureSize()); tanks.clear(); projectiles.clear(); initialized = true; } public static synchronized void addTank(AFV afv) { if (Parameters.isMagicMode()) { tanks.add(new QuantizedAFVMover(afv)); } else { tanks.add(new RealisticAFVMover(afv)); } } public static synchronized void update(double seconds, boolean timeForMessages) { if (timeForMessages) { for (int i = 0, size = tanks.size(); i < size; i++) { AFVMover m = (AFVMover) tanks.get(i); m.move(seconds); m.sendMessage(getGameTime()); } } List ps = new ArrayList(projectiles); boolean decelerate = true; for (int i = 0, size = ps.size(); i < size; i++) { ProjectileMover m = ps.get(i); m.move(seconds); if (decelerate && !m.isExploded()) decelerate = false; } if (decelerate) Simulation.decelerateClock(); } public static Map getMap() { return map; } public static double getPhysicalWidth() { return map.getWidthPhysical(); } public static double getPhysicalHeight() { return map.getHeightPhysical(); } public static AFVMover getAFVMover(int i) { return (AFVMover) tanks.get(i); } public static double getFeatureSize() { return map.getFeatureSize(); } public static synchronized void addProjectile(Projectile p) { Mover m = ProjectileMover.create(p); projectiles.add(m); Simulation.accelerateClock(); } public static ProjectileMover getProjectile(int i) { return (ProjectileMover) projectiles.get(i); } public static synchronized void removeProjectile(ProjectileMover mover) { projectiles.remove(mover); } public static void update(double seconds) { update(seconds, false); } public static int getNRedAFVs() { return getNAFVs(Nationality.RED); } public static int getNBlueAFVs() { return getNAFVs(Nationality.BLUE); } public static int getNWhiteAFVs() { return getNAFVs(Nationality.WHITE); } public static int getNAFVs(Nationality nationality) { int n = 0; for (int i = 0, size = tanks.size(); i < size; i++) { AFV afv = getAFVMover(i).getAFV(); if (afv.getNationality() == nationality) n++; } return n; } public static int getNBlueDamaged() { return getNDamaged(Nationality.BLUE); } public static int getNRedDamaged() { return getNDamaged(Nationality.RED); } public static int getNWhiteDamaged() { return getNDamaged(Nationality.WHITE); } public static synchronized int getNDamaged(Nationality nationality) { int n = 0; for (int i = 0, size = tanks.size(); i < size; i++) { AFV afv = getAFVMover(i).getAFV(); if (afv.isDestroyed()) continue; if (afv.getNationality() == nationality && afv.isDamaged()) n++; } return n; } public static int getNBlueDestroyed() { return getNDestroyed(Nationality.BLUE); } public static int getNRedDestroyed() { return getNDestroyed(Nationality.RED); } public static int getNWhiteDestroyed() { return getNDestroyed(Nationality.WHITE); } public static synchronized int getNDestroyed(Nationality nationality) { int n = 0; for (int i = 0, size = tanks.size(); i < size; i++) { AFV afv = getAFVMover(i).getAFV(); if (afv.getNationality() == nationality && afv.isDestroyed()) n++; } return n; } public static long getGameTime() { return Simulation.getBattleTime(); } public static boolean isInitialized() { return initialized; } public static int getNAFVs() { return tanks.size(); } public static int getNProjectiles() { return projectiles.size(); } public static synchronized void reset(String filename, double physicalWidth, double physicalHeight) { for (int i = 0, size = tanks.size(); i < size; i++) { AFVMover m = (AFVMover) tanks.get(i); m.sendExitMessage(); } tanks.clear(); projectiles.clear(); map.reset(filename); // map = Map.create(filename, physicalWidth, physicalHeight); TerrainType.initializeAll(); // TerrainType.initializeImages((int)Parameters.getPhysicalWidth()/Parameters.getWidthInFeatures()); Simulation.reset(); } public static void logResults() throws IOException { String Blue = "Blue:\tTotal:" + getNBlueAFVs() + " Damaged:" + getNBlueDamaged() + " Destroyed:" + getNBlueDestroyed(); String Red = "Red:\tTotal:" + getNRedAFVs() + " Damaged:" + getNRedDamaged() + " Destroyed:" + getNRedDestroyed(); String white = "White:\tTotal:" + getNWhiteAFVs() + " Damaged:" + getNWhiteDamaged() + " Destroyed:" + getNWhiteDestroyed(); Logger.logAll(Blue); Logger.logAll(Red); Logger.logAll(white); for (int i = 0, size = getNAFVs(); i < size; i++) { AFVMover m = getAFVMover(i); AFV a = m.getAFV(); Logger.logAll(a.getStatusString()); } Logger.flushAll(); } } *************************************************************************************** BattleInitializer.java *************************************************************************************** /** * This reads the config file and sets up the battle to be fought. It starts * the simulation, the display, etc. */ package acsl.dTank.battle; import java.io.IOException; import java.net.UnknownHostException; import java.util.List; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; import acsl.dTank.mover.DamageController; import acsl.dTank.server.Server; import acsl.dTank.ui.ServerControlPanel; public class BattleInitializer { private static String configurationFilename = "Default.config"; private static ServerControlPanel cp; public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { setParameters(args); fightBattles(); } public static void forceRepaintAll() { cp.setRepaintAll(true); } public static void fightBattles() throws InterruptedException, IOException { cp = setupBattle(); fightBattles(cp); Logger.logAll("========== Battles over =========="); // Logger.close(); Logger.flushAll(); Simulation.stopSimulation(); cp.stopDisplayLoop(); cp.setVisible(false); cp.dispose(); System.exit(0); } private static void fightBattles(ServerControlPanel cp) throws InterruptedException, IOException { List battles = Parameters.getBattles(); if (battles.size() < 1) throw new RuntimeException("No battles to fight."); Logger.logAll("\n========== Starting dTank" + Parameters.getVersion() + " release: " + Parameters.getReleaseDate() + " ==========\n"); for (int r = 0, repeat = Parameters.getRepeat(); r < repeat; r++) { for (int i = 0, size = battles.size(); i < size; i++) { Battle b = (Battle) battles.get(i); String header = "\n========== Starting Battle '" + Parameters.getBattleName() + "' Combattants: Red: " + b.getRedCommanderName() + " vs. Blue: " + b.getBlueCommanderName() + " ==========="; Logger.logAll(header); Logger.logAll(b.getBlueBattalion()); Logger.logAll(b.getRedBattalion()); Logger.logAll(b.getWhiteBattalion()); if (Parameters.getStartUpPause() > 0) Simulation.setPause(true); b.runBattle(); Battlefield.logResults(); Battlefield.reset(Parameters.getMapFilename(), Parameters .getPhysicalWidth(), Parameters.getPhysicalHeight()); Parameters.reset(); cp.reset(); } } } static void pause(final int startUpPause) { if (startUpPause == 0) return; Simulation.setPause(true); Thread t = new Thread() { public void run() { try { Thread.sleep(startUpPause*1000); } catch (Exception e) { } Simulation.setPause(false); } }; t.run(); } private static ServerControlPanel setupBattle() { Server.startPortListener(); List lines = Map.read(Parameters.getMapFilename()); Parameters.setDimensions(lines.size(), lines.size()); DamageController.setDamageController(Parameters.getDamageController()); Logger.initialize(); TerrainType.initializeImages((int) Parameters.getPhysicalWidth() / Parameters.getWidthInFeatures()); Battlefield.create(lines, Parameters.getPhysicalWidth(), Parameters .getPhysicalHeight()); ServerControlPanel cp = ServerControlPanel.create(Battlefield.getMap()); cp.startDisplayLoop(); Simulation.startSimulation(Parameters.getSimulationPeriod(), Parameters .getSecondsPerCycle()); return cp; } private static void setParameters(String[] args) { if (args.length > 0) configurationFilename = args[0]; Configuration config = Configuration.create(configurationFilename); Parameters.setValues(config); } } *************************************************************************************** Configuration.java *************************************************************************************** /** * This reads the config file and builds the list of battle pairings to be fought. */ package acsl.dTank.battle; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.*; import acsl.dTank.informationMessage.InformationMessage; public class Configuration { static public final String DELIMITORS = "[: ]"; private String configurationFilename; private double physicalWidth, physicalHeight; private String mapFilename = "empty50x50.map"; private List afvConfigurations = new ArrayList(); private String battleName = "Unnamed"; private double secondsPerCycle = 0.4; private int simulationPeriod = 40; private int displayPeriod = 40; private boolean logMessagesToTTY = false; private String mode = "Realistic"; // Magic private String logMessagesToFile = null; private int battleDuration = 5000; private int repeat = 1; private boolean recordResults; private String resultsFilename; private int mapWidth; private int mapHeight; private String damageController; private String[] commandLineArguments = new String[0]; private double hitRadius; private Battalion whiteBattalion = new Battalion("WHITE"); private int messagePeriod; private Map battalionMap = new HashMap(); private double maximumVisualDistance; private boolean emptyBoardersRequired = false; private int startUpPause; private boolean allowControlMessages; private Configuration(String configurationFilename) { this.configurationFilename = configurationFilename; } public static Configuration create(String configurationFilename) { Configuration c = new Configuration(configurationFilename); try { c.read(); } catch (IOException e) { e.printStackTrace(); System.exit(1); } return c; } private void read() throws IOException { BufferedReader inStream = getInputStream(); while (true) { String line = inStream.readLine(); if (line == null) return; String[] tokens = InformationMessage.dropBlanks(line .split(DELIMITORS)); parse(tokens, line); } } private BufferedReader getInputStream() throws FileNotFoundException, IOException { File f = new File(configurationFilename); if (f.exists()) { InputStream is = new FileInputStream(f); BufferedReader inStream = new BufferedReader(new InputStreamReader( is)); return inStream; } URL url = ClassLoader.getSystemResource("configurationFiles/" + configurationFilename); if (url != null) { InputStream is = url.openStream(); BufferedReader inStream = new BufferedReader(new InputStreamReader( is)); return inStream; } throw new RuntimeException("Missing conf file: " + configurationFilename); } private void parse(String[] tokens, String line) { if (tokens.length == 0) return; if (tokens[0].startsWith("#")) return; if (tokens[0].equals("PhysicalDimensions")) { physicalHeight = physicalWidth = Double.parseDouble(tokens[1]); // physicalHeight = Double.parseDouble(tokens[2]); return; } if (tokens[0].equals("MapDimensions")) { mapWidth = Integer.parseInt(tokens[1]); mapHeight = Integer.parseInt(tokens[2]); return; } if (tokens[0].equals("SecondsPerSimulationCycle")) { secondsPerCycle = Double.parseDouble(tokens[1]); return; } if (tokens[0].equals("SimulationPeriod")) { simulationPeriod = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("DisplayPeriod")) { displayPeriod = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("MessagePeriod")) { messagePeriod = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("Mapfile")) { mapFilename = tokens[1]; return; } if (tokens[0].equals("BattleName")) { battleName = tokens[1]; return; } if (tokens[0].equals("LogMessagesToTTY")) { logMessagesToTTY = true; return; } if (tokens[0].equals("AllowControlMessages")) { allowControlMessages = true; return; } if (tokens[0].equals("LogMessagesToFile")) { if (tokens.length > 1) logMessagesToFile = tokens[1]; return; } if (tokens[0].equals("ResultsFile")) { recordResults = true; if (tokens.length > 1) resultsFilename = tokens[1]; return; } if (tokens[0].equals("Mode")) { mode = tokens[1]; return; } if (tokens[0].equals("DamageController")) { damageController = tokens[1]; return; } if (tokens[0].equals("BattleDuration")) { battleDuration = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("StartUpPause")) { startUpPause = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("Repeat")) { repeat = Integer.parseInt(tokens[1]); return; } if (tokens[0].equals("HitRadius")) { hitRadius = Double.parseDouble(tokens[1]); return; } if (tokens[0].equals("MaximumVisualDistance")) { maximumVisualDistance = Double.parseDouble(tokens[1]); return; } if (tokens[0].equals("EmptyBoardersRequired")) { emptyBoardersRequired = "true".equals(tokens[1]); return; } if (tokens[0].equals("Combattant")) { String commanderType = tokens[1]; String battalionCommanderName = tokens[2]; String tank = tokens[3]; String withDisplay = tokens[4]; if (!(withDisplay.equals("Display") || withDisplay .equals("NoDisplay"))) throw new RuntimeException("Illegal argument " + withDisplay + " in \"" + line + "\""); String number = tokens[5]; if (tokens.length > 6) { commandLineArguments = new String[tokens.length - 6]; for (int i = 0; i < commandLineArguments.length; i++) commandLineArguments[i] = tokens[i + 6]; } afvConfigurations.add(new AFVConfiguration(battalionCommanderName, commanderType, tank, number, withDisplay, commandLineArguments)); return; } throw new RuntimeException("No such configuration element: " + tokens[0]); } public String getDamageController() { return damageController; } public String getMapFilename() { return mapFilename; } public double getPhysicalWidth() { return physicalWidth; } public double getPhysicalHeight() { return physicalHeight; } public int getMapWidth() { return mapWidth; } public int getMapHeight() { return mapHeight; } public List getAFVConfiguration() { return afvConfigurations; } public double getSecondsPerCycle() { return secondsPerCycle; } public int getSimulationPeriod() { return simulationPeriod; } public int getDisplayPeriod() { return displayPeriod; } public boolean isLoggingToTTY() { return logMessagesToTTY; } public String getBattleName() { return battleName; } public String getMode() { return mode; } public String getLogFilename() { return logMessagesToFile; } public int getRepeat() { return repeat; } public int getBattleDuration() { return battleDuration; } public int getStartUpPause() { return startUpPause; } public boolean isRecordResults() { return recordResults; } public String getResultsFilename() { return resultsFilename; } public Battalion getWhiteBattalion() { return whiteBattalion; } public List getBattalions() { for (int i = 0, size = afvConfigurations.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) afvConfigurations.get(i); String bcn = c.getBattalionCommanderName(); Battalion battalion = getBattalion(bcn); battalion.addAFVConfigurations(c); } whiteBattalion = getBattalion("WHITE"); battalionMap.remove("WHITE"); List battalions = new ArrayList(battalionMap .values()); return battalions; } private Battalion getBattalion(String bcn) { Battalion b = battalionMap.get(bcn); if (b != null) return b; b = new Battalion(bcn); battalionMap.put(bcn, b); return b; } public List getBattles() { List battalions = getBattalions(); List battles = new ArrayList(); if (battalions.size() == 0) { battles.add(new Battle(Battalion.EMPTY_BATTALION, Battalion.EMPTY_BATTALION, whiteBattalion)); return battles; } if (battalions.size() == 1) { battles.add(new Battle(battalions.get(0), Battalion.EMPTY_BATTALION, whiteBattalion)); return battles; } for (int i = 0, size = battalions.size(); i < size; i++) { Battalion b0 = (Battalion) battalions.get(i); for (int j = i + 1; j < size; j++) { Battalion b1 = (Battalion) battalions.get(j); battles.add(new Battle(b0, b1, whiteBattalion)); } } return battles; } public double getHitRadius() { return hitRadius; } public double getMaximumVisualDistance() { return maximumVisualDistance; } public int getMessagePeriod() { return messagePeriod; } public boolean emptyBoardersRequired() { return emptyBoardersRequired; } public boolean getAllowControlMessages() { return allowControlMessages; } } *************************************************************************************** Simulation.java *************************************************************************************** /** * This runs the simulation. On each iteration it updates all the positions of AFVs * and projectiles, each of which takes care of its own details (colliding with objects, * taking hits, etc.) The simulationPeriod (slightly misnamed as it's really the ms * between cycles) must be non-zero to allow all threads to run on each cycle. * * When projectiles are flying, the battlefield seconds/cycle is reduced s that the * fast flying projectiles don't skip over long areas and to allow the displays to keep up. */ package acsl.dTank.battle; import acsl.dTank.Parameters; import acsl.dTank.ui.ServerControlPanel; public class Simulation implements Runnable { private static double oldSecondsPerCycle; private static long timeOfPreviousMessage = 0; private boolean alreadyRunning = false; private static long currentBattleTime = 0; // ms public static int oldSimulationPeriod; private static boolean pause = false; private static boolean stopped = false; private static boolean step = false; private static boolean realTime = false; private static Thread simThread; public Simulation() { } public static void reset() { timeOfPreviousMessage = 0; currentBattleTime = 0; ServerControlPanel.clearDisplayMessage(); } public static boolean isStopped() { return stopped; } public static boolean isPaused() { return pause; } public static void stopSimulation() { if (simThread != null) simThread.interrupt(); simThread = null; } public void run() { try { run1(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public void run1() { if (alreadyRunning) return; alreadyRunning = true; stopped = false; boolean timeForMessages; long increasedTime = 0; while (!stopped) { // for (int i = 0; i < 1000000; i++) { try { timeForMessages = false; synchronized (Battlefield.class) { if (currentBattleTime > Parameters.getBattleDuration()) { Battlefield.class.notifyAll(); } } if (realTime) { if (isAccelerated()) { Thread.sleep(Parameters.getSimulationPeriod()); } else { Thread.sleep(increasedTime); } } else // if(!isAccelerated()) { Thread.sleep(Parameters.getSimulationPeriod()); } if (pause) { synchronized (Simulation.class) { while (!Simulation.step) Simulation.class.wait(); } Simulation.step = false; } if ((currentBattleTime - timeOfPreviousMessage) >= Parameters .getMessagePeriod()) { // if ( (System.currentTimeMillis() - timeOfPreviousMessage) // >= Parameters.getMessagePeriod()){ timeOfPreviousMessage = currentBattleTime; // timeOfPreviousMessage = System.currentTimeMillis(); timeForMessages = true; } Battlefield.update(Parameters.getSecondsPerCycle(), timeForMessages); synchronized (Battlefield.class) { Battlefield.class.notifyAll(); } increasedTime = incrementTime(); } catch (InterruptedException e) { stopped = true; pause = false; step = false; // return; } } } /** * Increases currentBattleTime and return the increased amound in * milliseconds * * @return */ public static long incrementTime() { long step = (long) (Parameters.getSecondsPerCycle() * 1000); currentBattleTime += step; return step; } public static long getBattleTime() { return currentBattleTime; } public static double getBattleSecondsPerCycle() { return Parameters.getSecondsPerCycle(); } public static double getSimulationPeriod() { return Parameters.getSimulationPeriod(); } // Speed up clock so a projectile @ 800 m/s will travel 8m/cycle public static synchronized void accelerateClock() { if (isAccelerated()) return; oldSimulationPeriod = Parameters.getSimulationPeriod(); Parameters.setSimulationPeriod(10); oldSecondsPerCycle = Parameters.getSecondsPerCycle(); Parameters.setSecondsPerCycle(0.03); /* * try { Thread.sleep(oldSimulationPeriod); // Let display speed up // * if necessary--avoid "jumps" } catch (InterruptedException e) { } */ } public static synchronized void decelerateClock() { if (!isAccelerated()) return; Parameters.setSimulationPeriod(oldSimulationPeriod); Parameters.setSecondsPerCycle(oldSecondsPerCycle); oldSimulationPeriod = 0; } public static boolean isAccelerated() { return (oldSimulationPeriod != 0); } public static void startSimulation(int simulationPeriod, double secondsPerCycle) { Parameters.setSimulationPeriod(simulationPeriod); Parameters.setSecondsPerCycle(secondsPerCycle); simThread = new Thread(new Simulation(), "Simulation"); simThread.start(); } public static void startSimulation() { simThread = new Thread(new Simulation(), "Simulation"); simThread.start(); } public static void setGameTime(long i) { currentBattleTime = i; } public static synchronized void togglePause() { pause = !pause; if (!pause) step(); } public static synchronized void step() { step = true; Simulation.class.notifyAll(); } /** * Simulation real time, make it sleep for the increase time * * @param realTime */ public static void setRealTime(boolean realTime) { Simulation.realTime = realTime; } public static synchronized void setPause(boolean b) { pause = b; if (!pause) step(); } public static void endBattle() { if (!Parameters.getAllowControlMessages()) throw new RuntimeException("No Control messages allowed."); currentBattleTime = Parameters.getBattleDuration(); } public static void step(int nSteps) { for (int i = 0; i < nSteps; i++) { step(); } } } *************************************************************************************** AFVModel.java *************************************************************************************** /** * The model is what the commander knows about his/her own AFV. It is analogous to the AFV, * but maintained by the commander. (It would get nasty confusing to use an AFV object for * this purpose as the programmer would be easily confused what object owned what AFV object.) */ package acsl.dTank.commander; import acsl.dTank.Parameters; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Heading; import acsl.dTank.afv.Location; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Velocity; import acsl.dTank.projectile.Projectile; public class AFVModel { private static int idCounter = 0; private String name; private AFVType afvType; private Location location = new Location(0.0, 0.0); private Heading heading = new Heading(); private Velocity velocity = new Velocity(); private double throttle = 0.0; private Heading turretHeading = new Heading(); // 0-259 private double gunElevation = 0; // -5.0 - +20.0 private int ammunitionRemaining; private double fuelRemaining; private Nationality nationality; private boolean isLoaded; private double armorDamage; boolean gunOperational = true, radioOperational = true, crewHealthy = true, destroyed = false; String radioMessageString; private boolean isTreadGood; private AFVModel(AFVType afvType, Nationality nationality) { this.afvType = afvType; name = afvType.getName() + idCounter; this.nationality = nationality; if (!Parameters.isTesting()) idCounter++; ammunitionRemaining = afvType.getAmmunitionCapacity(); } public String getName() { return name; } public AFVType getAFVType() { return afvType; } public double getHeading() { return heading.getHeading(); } public Location getLocation() { return location; } public double getTurretHeading() { return turretHeading.getHeading(); } public double getGunElevation() { return gunElevation; } public int getAmmunitionRemaining() { return ammunitionRemaining; } public double getFuelRemaining() { return fuelRemaining; } public double getThrottle() { return throttle; } public void setThrottle(double throttle) { if ((throttle < -1.0) || (throttle > 1.0)) throw new RuntimeException("throttle out of bounds " + throttle); this.throttle = throttle; } public String toString() { return "<" + name + " " + location + ">"; } public double getMaxSpeedMPS() { return afvType.getMaxSpeedMPS(); } public double getSpeedMPS() { return velocity.getSpeedMPS(); } public double getSpeedKPH() { return velocity.getSpeedKPH(); } public boolean atLocation(double x, double y) { if ((Math.abs(x - location.getX())) > 0.1) return false; if ((Math.abs(y - location.getY())) > 0.1) return false; return true; } public void setLocation(double x, double y) { // System.out.println(" x y = " + x +" " +y); location.set(x, y); } public void setSpeedMPS(double speed) { velocity.setSpeedMPS(speed); } public void setSpeedKPH(double speed) { velocity.setSpeedKPH(speed); } public void setHeading(double heading) { this.heading.setHeading(heading); } public double getY() { return location.getY(); } public double getX() { return location.getX(); } public void setTurretHeading(double d) { turretHeading.setHeading(d); } public void receivedHit(Projectile projectile) { setDestroyed(); setSpeedMPS(0.0); } public static AFVModel create(AFVType afvType, Nationality nationality) { AFVModel t = new AFVModel(afvType, nationality); return t; } public void setGunElevation(double gunElevation) { this.gunElevation = gunElevation; } public void setAmmunitionRemaining(int ammunitionRemaining) { this.ammunitionRemaining = ammunitionRemaining; } public void setRadioMessage(String radioMessage) { // System.out.println("Model " + name + " received: " + radioMessage); } public Nationality getNationality() { return nationality; } public boolean isLoaded() { return isLoaded; } public void setLoaded(boolean isLoaded) { this.isLoaded = isLoaded; } public void setArmorDamage(double d) { armorDamage = d; } public double getFuel() { return fuelRemaining; } public void setFuelRemaining(double fuelRemaining) { this.fuelRemaining = fuelRemaining; } public boolean isDestroyed() { return destroyed; } public boolean isFullyOperational() { if (gunOperational && radioOperational && crewHealthy && !destroyed) return true; return false; } public void setDestroyed() { destroyed = true; } public boolean getOperational() { return !isDestroyed(); } public boolean isCrewHealthy() { return crewHealthy; } public boolean isRadioOperational() { return radioOperational; } public boolean isDamaged() { if (destroyed) return true; if (gunOperational && radioOperational && crewHealthy) return false; return true; } public double getArmorDamage() { return armorDamage; } public void incArmorDamage(double d) { armorDamage += d; } public void setRadioDestroyed() { radioOperational = false; } public String getRadioMessageString() { return radioMessageString; } public void setCrewSpacy() { crewHealthy = false; } public boolean isRadioDestroyed() { return !radioOperational; } public boolean isTreadGood() { return isTreadGood; } public void setTreadGood(boolean b) { isTreadGood = b; } } *************************************************************************************** BattalionGeneralCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Utility; import acsl.dTank.informationMessage.DetectedAFV; public class BattalionGeneralCommander extends Commander { // {"Allied", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} public static void main(String[] args) throws UnknownHostException, IOException { String nat = "Allied", afvType = "Sherman", withDisplay = "Display", number = "1"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = args[3]; String[] args2 = new String[] { nat, afvType, withDisplay, number }; Initializer.initializeAll(); List cs = new ArrayList(); int n = Integer.parseInt(number); for (int i = 0; i < n; i++) { cs.add(create(args2)); } } // { "Allied", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} public static Commander create(String[] args) { BattalionGeneralCommander c = new BattalionGeneralCommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { boolean retreating = false; commanderCommunicator.setDesiredHeading(90); commanderCommunicator.setThrottle(1.0); Thread.sleep(2000); commanderCommunicator.setThrottle(0.0); DetectedAFV currentTarget = null; long timeSpotted = -1; for (int i = 0; true; i++) { if (exit) return; Thread.sleep(1000); int elapsedTime = gameTime - previousGameTime; if (elapsedTime < 1000) continue; previousGameTime = gameTime; if (retreating && afvModel.getThrottle() != 0.0) continue; retreating = false; commanderCommunicator.setDesiredTurretHeading(afvModel.getTurretHeading() + 15.0); if (afvModel.getThrottle() == 0.0) commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 10.0 + 10 * Math.random()); commanderCommunicator.setThrottle(0.4); synchronized (cmap) { DetectedAFV dafv = cmap.probablySame(currentTarget, elapsedTime); currentTarget = dafv; if (dafv == null) { currentTarget = null; timeSpotted = -1; for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { DetectedAFV afv = cmap.getAFV(j); if (afv.getNationality() == nationality) continue; if (afv.isDestroyed()) continue; currentTarget = afv; timeSpotted = gameTime; // writeDisplayMessage("Acquired new target: " + // Utility.shorten(currentTarget.getX()) + "|" + "0.0"); break; } } if (currentTarget == null) continue; double targetHeading = calculateTargetHeading(currentTarget); double distance = calculateTargetDistance(currentTarget); commanderCommunicator.setDesiredTurretHeading(targetHeading); commanderCommunicator.setDesiredHeading(targetHeading); if ((gameTime - timeSpotted) > 16000) { commanderCommunicator.sendRadioMessage("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) + "|" + Utility.shorten(currentTarget.getY())); writeDisplayMessage("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) + "|" + Utility.shorten(currentTarget.getY())); // System.out.println("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) // + "|" + Utility.shorten(currentTarget.getY())); // writeDisplayMessage("Spotted enemy tank at " + // Utility.shorten(targetHeading) + " degrees " + // Utility.shorten(distance) + " meters."); } else { commanderCommunicator.sendRadioMessage("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) + "|" + "0.0"); writeDisplayMessage("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) + "|" + "0.0"); // System.out.println("FollowEnemyAt|" + Utility.shorten(currentTarget.getX()) // + "|" + "0.0"); } if (distance < 200.0) { writeDisplayMessage("Too close. Retreat!"); retreating = true; commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 10.0 + 10 * Math.random()); commanderCommunicator.setThrottle(-.50); if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); fire(); } continue; } else commanderCommunicator.setThrottle(1.0); if (distance > 1600.0) { writeDisplayMessage("Too far to fire: " + Utility.shorten(distance)); continue; } // setThrottle(0.0); if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); fire(); } } } } } *************************************************************************************** BattalionLieutenantCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Utility; import acsl.dTank.afv.Nationality; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.radioMessage.RadioMessage; public class BattalionLieutenantCommander extends Commander { DetectedAFV currentTarget = null; long timeSpotted = -1; // {"Allied", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} public static void main(String[] args) throws UnknownHostException, IOException { String nat = "Allied", afvType = "Sherman", withDisplay = "Display", number = "1"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = args[3]; String[] args2 = new String[] { nat, afvType, withDisplay, number }; Initializer.initializeAll(); List cs = new ArrayList(); int n = Integer.parseInt(number); for (int i = 0; i < n; i++) { cs.add(create(args2)); } } // { "Allied", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} public static Commander create(String[] args) { BattalionLieutenantCommander c = new BattalionLieutenantCommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { boolean retreating = false; commanderCommunicator.setDesiredHeading(90); commanderCommunicator.setThrottle(1.0); Thread.sleep(2000); commanderCommunicator.setThrottle(0.0); for (int i = 0; true; i++) { if (exit) return; Thread.sleep(1000); if (gameTime - previousGameTime < 1000) continue; previousGameTime = gameTime; if (retreating && afvModel.getThrottle() != 0.0) continue; retreating = false; commanderCommunicator.setDesiredTurretHeading(afvModel.getTurretHeading() + 15.0); if (afvModel.getThrottle() == 0.0) commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 50.0 + 10 * Math.random()); commanderCommunicator.setThrottle(0.4); synchronized (cmap) { processRadioMessage(); if (currentTarget == null) continue; double targetHeading = calculateTargetHeading(currentTarget); double distance = calculateTargetDistance(currentTarget); commanderCommunicator.setDesiredTurretHeading(targetHeading); if (!cmap.probablyContains(currentTarget, 2)) continue; commanderCommunicator.setDesiredHeading(targetHeading); commanderCommunicator.setThrottle(1.0); if (distance > 600.0) { writeDisplayMessage("Too far to fire: " + Utility.shorten(distance)); continue; } // setThrottle(0.0); if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); fire(); } } } } private void processRadioMessage() { String ms = afvModel.getRadioMessageString(); if (ms == null) return; RadioMessage m = RadioMessage.create(ms); m.processMessage(this); } public void setCurrentTarget(DetectedAFV detectedAFV) { this.currentTarget = detectedAFV; } } *************************************************************************************** BilsCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.communicator.CommanderDebuggerSocketCommunicator; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.map.TerrainType; public class BilsCommander extends Commander { // private int startTime; private double scanInc = 10.0; // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static void main(String[] args) throws UnknownHostException, IOException { int number = 1; String nat = "Blue", afvType = "Sherman", withDisplay = "false"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = Integer.parseInt(args[3]); String[] args2 = new String[] { BilsCommander.class.toString(), nat, afvType, withDisplay }; Initializer.initializeAll(); for (int i = 0; i < number; i++) { BilsCommander.create(args2); } } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static Commander create(String[] args) { BilsCommander c = new BilsCommander(); c.initialize(args); return c; } @Override public void initialize(String[] args) { super.initialize(args); debuggerCommunicator = new CommanderDebuggerSocketCommunicator(); debuggerCommunicator.initialize(cmdrName); } public void runCommander() throws InterruptedException { // startTime = getTime(); setDesiredHeading(210 + Math.random() * 120); setDesiredTurretHeading(270); setThrottle(1.0); for (int i = 0; true; i++) { if (exit) return; Thread.sleep(1000); if (gameTime > 2000000) { System.out.println("RESET"); setResetBattle(); return; } DetectedAFV afv = closestEnemy(); double dir = (afv != null) ? calculateTargetHeading(afv) : 0.0; if (inRange(afv) && afvModel.isLoaded()) { writeDisplayMessage("Fire!"); setDesiredTurretHeading(dir); fire(); continue; } if (onEdgesOfHills()) { setThrottle(0.0); if (afv == null) { continueScaning(); continue; } continue; } if (inRange(afv)) { setDesiredHeading(dir + 45); setDesiredTurretHeading(dir); setThrottle(-0.5); continue; } } } private void continueScaning() { double h = afvModel.getTurretHeading(); if (h > 345.0) scanInc = -10; else if (h < 165.0) scanInc = 10; setDesiredTurretHeading(h + scanInc); } private boolean inRange(DetectedAFV afv) { if (afv == null) return false; double dist = calculateTargetDistance(afv); if (dist < 600.0) return true; return false; } private DetectedAFV closestEnemy() { double closest = 100000.0; DetectedAFV closestAFV = null; for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { DetectedAFV afv = cmap.getAFV(j); if (afv.getNationality() == nationality) continue; if (afv.isDestroyed()) continue; double distance = calculateTargetDistance(afv); if (distance < closest) { closest = distance; closestAFV = afv; } } return closestAFV; } public boolean onEdgesOfHills() { if (!cmap.get(afvModel.getX(), afvModel.getY()).equals( TerrainType.LOW_HILL)) return false; TerrainType type = cmap.get(afvModel.getX() - 50.0, afvModel.getY()); if (type.equals(TerrainType.GRASS)) return true; if (type.equals(TerrainType.ROAD)) return true; return false; } } *************************************************************************************** Commander.java *************************************************************************************** /* * This is the base class for commanders, which is convienient to use when writing in Java. * It can be run as a separate thread or in its own process. (The create() method always creates * one thread to accept messages and update the map and afvModels, and another for runCommander().) * It is sufficent to write a subclass that only implements runCommander(). */ package acsl.dTank.commander; import java.io.IOException; import java.lang.reflect.Method; import java.net.Socket; import java.util.ArrayList; import java.util.List; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.Utility; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.communicator.CommanderCommunicator; import acsl.dTank.communicator.CommanderDebuggerSocketCommunicator; import acsl.dTank.communicator.CommanderDirectCommunicator; import acsl.dTank.communicator.CommanderSocketCommunicator; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.map.CommanderMap; import acsl.dTank.ui.CommanderControlPanel; public abstract class Commander { private static int count = 0; AFVModel afvModel; String cmdrName; Nationality nationality; AFVType afvType; Socket socket; String afvName = "Server"; CommanderMap cmap; double width, height, featureSize; private CommanderControlPanel commanderControlPanel; private List displayMessages = new ArrayList(); protected CommanderCommunicator commanderCommunicator; protected CommanderDebuggerSocketCommunicator debuggerCommunicator; protected int gameTime = 0, previousGameTime = 0; protected boolean exit; // private String commanderFullClassName; private Thread ccThread; private Thread clThread; private boolean isLoaded = true; private static List commanderList = new ArrayList(); // {"acsl.dTank.commander.SmartCommander", "Blue", "Sherman", "Display", // "3", "arg0", "arg1", "arg2", ..} public static void createCommanders(String[] args) { int n = Integer.parseInt(args[4]); for (int i = 0; i < n; i++) { commanderList.add(create(args)); } } // {"acsl.dTank.commander.SmartCommander", "Blue", "Sherman", "Display", // "3", "arg0", "arg1", "arg2", ..} public static Commander create(String[] args) { String cName = args[0]; String[] args2 = new String[args.length - 1]; for (int i = 0; i < args2.length; i++) { args2[i] = args[i + 1]; } ClassLoader classLoader = Thread.currentThread() .getContextClassLoader(); Class clazz; try { clazz = classLoader.loadClass(cName); } catch (Exception e) { System.out.println("Could not find class " + cName); throw new RuntimeException(e); } Method method; try { method = clazz.getDeclaredMethod("create", new Class[] { String[].class }); } catch (Exception e) { System.out.println("Could not find method " + cName + ".create(String[] args)"); throw new RuntimeException(e); } try { return (Commander) method.invoke(null, new Object[] { args2 }); } catch (Exception e) { System.out.println("Could not run method " + cName + ".create(String[] args)"); throw new RuntimeException(e); } } // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", ... } public void initialize(String[] args) { Nationality nationality = Nationality.BLUE; AFVType afvType = AFVType.SHERMAN; boolean showDisplay = true; nationality = Nationality.lookup(args[0]); afvType = AFVType.lookup(args[1]); showDisplay = args[2].equals("Display"); if (Parameters.useDirectCommunicator()) commanderCommunicator = new CommanderDirectCommunicator(); else commanderCommunicator = new CommanderSocketCommunicator(); String[] cn = this.getClass().getName().split("[.]"); this.cmdrName = cn[cn.length - 1] + count++; InformationMessage m = commanderCommunicator.initialize(nationality, afvType, cmdrName); this.nationality = nationality; this.afvType = afvType; this.afvModel = AFVModel.create(afvType, nationality); try { afvName = m.getFrom(); width = m.getWidth(); height = m.getHeight(); featureSize = m.getFeatureSize(); cmap = CommanderMap.create(width, height, featureSize); ccThread = new Thread(new CommanderThread(this), "Commander"); ccThread.start(); clThread = new Thread(new CommanderListener(this), "CommanderListener"); clThread.start(); } catch (Exception e) { throw new RuntimeException(e); } if (showDisplay) createControlPanel(); } public abstract void runCommander() throws InterruptedException; public void runListener() throws InterruptedException, IOException { while (true) { InformationMessage m = commanderCommunicator.readMessage(); if (m == null) { Logger.log("Exiting: " + afvName); return; } processMessage(m); if (commanderControlPanel != null) commanderControlPanel.redisplay(); } } void processMessage(InformationMessage m) { if (m.isSettingThrottle()) afvModel.setThrottle(m.getThrottle()); if (m.isSettingHeading()) afvModel.setHeading(m.getHeading()); if (m.isSettingTurretHeading()) afvModel.setTurretHeading(m.getTurretHeading()); if (m.isSettingLocation()) afvModel.setLocation(m.getX(), m.getY()); if (m.isSettingSpeed()) afvModel.setSpeedKPH(m.getSpeedKPH()); if (m.isSettingGunElevation()) afvModel.setGunElevation(m.getGunElevation()); if (m.isSettingAmmunitionRemaining()) afvModel.setAmmunitionRemaining(m.getAmmunitionRemaining()); if (m.isSettingRadioMessage()) afvModel.setRadioMessage(m.getRadioMessage()); if (m.isSettingLoaded()) { boolean isNowLoaded = m.isLoaded(); afvModel.setLoaded(isLoaded); if (isNowLoaded != isLoaded) { if (isNowLoaded) writeDisplayMessage("Loaded"); else writeDisplayMessage("Loading..."); isLoaded = isNowLoaded; } } if (m.isSettingFuelRemaining()) afvModel.setFuelRemaining(m.getFuelRemaining()); if (m.isExit()) { exit = true; if (commanderControlPanel != null) commanderControlPanel.dispose(); throw new RuntimeException("Exit"); } gameTime = m.getTime(); if (m.isSettingOperationalStatus()) { double ad = m.getArmorDamage(), mad = afvModel.getArmorDamage(); if (ad > mad) writeDisplayMessage("Damaged: " + ad); afvModel.setArmorDamage(ad); if (!m.isTreadGood()) { if (afvModel.isTreadGood()) { afvModel.setTreadGood(false); writeDisplayMessage("Tread damaged. AFV cannot move."); } } boolean mdes = afvModel.isDestroyed(), des = m.isDestroyed(); if (des && !mdes) writeDisplayMessage("Destroyed!"); if (des) afvModel.setDestroyed(); } if (m.isSettingCollision()) { writeDisplayMessage("Collided with " + m.getCollisionWithTerrainType().getName()); } if (m.isProjectileScan()) { cmap.setProjectiles(m.getProjectiles()); return; } cmap.reset(m); cmap.addAFVModel(new DetectedAFV(afvModel.getNationality(), false, afvModel.getX(), afvModel.getY(), afvModel.getHeading(), afvModel.getTurretHeading(), afvModel.getAFVType())); } public void writeDisplayMessage(String msg) { try { int size = displayMessages.size(); if (size > 0 && msg.equals(displayMessages.get(size - 1))) return; while (displayMessages.size() > 10) { displayMessages.remove(0); } displayMessages.add(msg + "\n"); } finally { if (commanderControlPanel != null) commanderControlPanel.redisplay(); } } public String getMessageString() { StringBuffer sb = new StringBuffer(); if (displayMessages.size() > 8) displayMessages.remove(0); for (int i = 0, size = displayMessages.size(); i < size; i++) { sb.append((String) displayMessages.get(i)); } return sb.toString(); } public void createControlPanel() { commanderControlPanel = CommanderControlPanel.create(cmap, this, afvModel); } public AFVModel getAFVModel() { return afvModel; } protected double calculateTargetHeading(DetectedAFV afv) { double x0 = afvModel.getX(); double y0 = afvModel.getY(); double x1 = afv.getX(); double y1 = afv.getY(); return Utility.calculateTargetHeading(x0, y0, x1, y1); } protected double calculateTargetDistance(DetectedAFV afv) { double x0 = afvModel.getX(); double y0 = afvModel.getY(); double x1 = afv.getX(); double y1 = afv.getY(); return Utility.calculateDistance(x0, y0, x1, y1); } public CommanderCommunicator getCommanderCommunicator() { return commanderCommunicator; } public void fire() { commanderCommunicator.setFire(); afvModel.setLoaded(false); } public void setDesiredTurretHeading(double d) { commanderCommunicator.setDesiredTurretHeading(d); } public void setThrottle(double d) { commanderCommunicator.setThrottle(d); } public void setDesiredHeading(double d) { commanderCommunicator.setDesiredHeading(d); } public void setDesiredTurretHeadingEvent(double angle) { System.out.println("Ignoring mouse clicks"); } public double getFeatureSize() { return featureSize; } public void incDesiredHeading() { System.out.println("Ignoring key strokes"); } public void decDesiredHeading() { System.out.println("Ignoring key strokes"); } public void decThrottle() { System.out.println("Ignoring key strokes"); } public void incThrottle() { System.out.println("Ignoring key strokes"); } public void shutDown() { ccThread.interrupt(); clThread.interrupt(); } public void fireKeyStroke() { System.out.println("Ignoring key strokes"); } public int getGameTime() { return gameTime; } public void setResetBattle() { if (debuggerCommunicator == null) { writeDisplayMessage("No debugger connection."); return; } debuggerCommunicator.setResetBattle(); writeDisplayMessage("Sent reset request."); } public void setPause(boolean b) { if (debuggerCommunicator == null) { writeDisplayMessage("No debugger connection."); return; } debuggerCommunicator.setPause(b); writeDisplayMessage("Sent " + (b ? "pause" : "resume") + " request."); } public void setStep(int i) { if (debuggerCommunicator == null) { writeDisplayMessage("No debugger connection."); return; } debuggerCommunicator.setStep(i); writeDisplayMessage("Sent step request for " + i + " steps."); } public void setRealTimeMode(boolean selected) { if (debuggerCommunicator == null) { writeDisplayMessage("No debugger connection."); return; } debuggerCommunicator.setRealTimeMode(selected); writeDisplayMessage("Sent real time request."); } } class CommanderListener implements Runnable { Commander commander; public CommanderListener(Commander commander) { this.commander = commander; } public void run() { try { commander.runListener(); } catch (Exception e) { if ("Exit".equals(e.getMessage())) return; e.printStackTrace(); System.exit(1); } } } class CommanderThread implements Runnable { Commander commander; public CommanderThread(Commander commander) { this.commander = commander; } public void run() { try { commander.runCommander(); } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } } } *************************************************************************************** CommanderHeadingTest.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.battle.Battlefield; public class CommanderHeadingTest extends TestCase { public void test1() throws UnknownHostException, IOException { Battlefield.create("empty20x20.map", 1000.0, 1000.0); AFV afv0 = AFV.create(AFVType.SHERMAN, null); AFV afv1 = AFV.create(AFVType.TIGER, null); afv0.setLocation(500, 500); afv1.setLocation(500, 600); { //for (double t = -Math.PI / 2; t < Math.PI / 2; t += 0.1) { //double dy = Math.sin(t); //double dx = Math.cos(t); //double a = Math.atan(dy / dx); // System.out.println(t + " == " +a); // assertEquals(t, a, 0.1); //} } // This is for the "standard" x,y. { double a0 = calculateTargetHeading(500, 500, 600, 500); assertEquals(0.0, a0, 1.0); } { double a0 = calculateTargetHeading(500, 500, 600, 550); assertEquals(26.0, a0, 1.0); } { double a0 = calculateTargetHeading(500, 500, 600, 600); assertEquals(45.0, a0, 1.0); } { double a0 = calculateTargetHeading(500, 500, 500, 600); assertEquals(90.0, a0, 1.0); } { double a0 = calculateTargetHeading(500, 500, 400, 600); assertEquals(135.0, a0, 1.0);// 135 } { double a0 = calculateTargetHeading(500, 500, 400, 500); assertEquals(180.0, a0, 1.0);// 180 } { double a0 = calculateTargetHeading(500, 500, 400, 400); assertEquals(225.0, a0, 1.01); // 225 } { double a0 = calculateTargetHeading(500, 500, 500, 400); assertEquals(270.0, a0, 1.01); // 270 } { double a0 = calculateTargetHeading(500, 500, 600, 400); assertEquals(315.0, a0, 1.01); // 315 } } // x0,y0 is ME, x1,y1 is the target private double calculateTargetHeading(double x0, double y0, double x1, double y1) { double deltaX = (x1 - x0); double deltaY = (y1 - y0); double theta; // if (deltaY == 0.0) theta = (deltaX > 0.0) ? Math.PI / 2 : 3 * Math.PI // / 2; else theta = Math.atan(deltaY / deltaX); if (deltaX < 0) theta += Math.PI; if (theta < 0) theta += Math.PI * 2; if (theta > Math.PI * 2) theta -= Math.PI * 2; return Math.toDegrees(theta); } } *************************************************************************************** CommanderMapTest.java *************************************************************************************** package acsl.dTank.commander; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.map.CommanderMap; import acsl.dTank.map.TerrainType; public class CommanderMapTest extends TestCase { public static String input2 = ""; private CommanderMap map; public void setUp() { Initializer.initializeAll( ); map = CommanderMap.create(1000.0, 1000.0, 50.0); assertEquals(50.0, map.getFeatureSize(), 0.1); } public void test1() { assertEquals(TerrainType.GRASS, map.get(100.0, 100.0)); assertEquals(TerrainType.GRASS, map.get(40.0, 400.0)); assertEquals(TerrainType.GRASS, map.get(999.0, 45.4)); assertEquals(TerrainType.GRASS, map.get(0.1, 0.0)); assertEquals(TerrainType.OFF_MAP, map.get(-0.01, 1000.1)); assertEquals(TerrainType.OFF_MAP, map.get(1001.0, 99)); } public void test2() { InformationMessage m = InformationMessage.create(input2); map.reset(m); assertEquals(TerrainType.GRASS, map.get(100.0, 100.0)); assertEquals(TerrainType.GRASS, map.get(40.0, 400.0)); assertEquals(TerrainType.STONE, map.get(125.6, 998.0)); assertEquals(TerrainType.HIGH_HILL, map.get(235.6, 998.0)); assertEquals(TerrainType.OFF_MAP, map.get(-0.01, 1000.1)); assertEquals(TerrainType.OFF_MAP, map.get(1001.0, 99)); } public static void main(String[] args) { System.out.println("==========CommanderMapTest=========="); CommanderMapTest test = new CommanderMapTest(); test.setUp(); test.test1(); test.test2(); } } *************************************************************************************** CommanderMessageTest.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.battle.Battlefield; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.server.Server; public class CommanderMessageTest extends TestCase { Commander commander; InformationMessage message0; String input0 = ""; public void setUp() throws UnknownHostException, IOException { Initializer.initializeAll(); String[] args = new String[]{"Blue", "Sherman", "Display", "1", "arg0"}; Parameters.setTesting(true); Battlefield.create("testMaps/test20x20.map", 1000.0, 1000.0); Server.startPortListener(); commander = DullCommander.create(args); message0 = InformationMessage.create(input0); } public void test1() throws UnknownHostException, IOException { commander.processMessage(message0); AFVModel afv = commander.getAFVModel(); assertEquals(949.0, afv.getX(), 0.01); assertEquals(500.0, afv.getY(), 0.01); assertEquals(10.0, afv.getHeading(), 0.01); assertEquals(-25.0, afv.getSpeedKPH(), 0.01); assertEquals(12.0, afv.getGunElevation(), 0.01); assertEquals(9, afv.getAmmunitionRemaining()); } public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("==========CommanderMessageTest=========="); CommanderMessageTest test = new CommanderMessageTest(); test.setUp(); test.test1(); // test.test2(); } } *************************************************************************************** CommanderTest.java *************************************************************************************** package acsl.dTank.commander; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import junit.framework.TestCase; public class CommanderTest extends TestCase { SCTListener sct; private Thread thread; Commander c; public void setUp() { Initializer.initializeAll(); startListener(); } protected void tearDown() { c.shutDown(); } private void startListener() { sct = new SCTListener(); thread = new Thread(sct, "Test"); thread.start(); sct.waitForReady(); } public void test1() throws UnknownHostException, IOException { String[] args = new String[] { "Blue", "Sherman", "1", "Display", "arg0", "arg1" }; c = DullCommander.create(args); } public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("==========CommanderTest=========="); CommanderTest test = new CommanderTest(); test.setUp(); test.test1(); test.tearDown(); System.out.println("==========End CommanderTest=========="); } } class SCTListener implements Runnable { private String expectedInitialization = ""; private String initReply = ""; private boolean ready = false; private boolean shuttingDown = false; public void run() { try { ServerSocket listenSocket = new ServerSocket(Parameters.getPort()); synchronized (this) { ready = true; this.notifyAll(); } Socket socket = listenSocket.accept(); BufferedReader inStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); String input = inStream.readLine(); TestCase.assertEquals(expectedInitialization, input); outStream.println(initReply); listenSocket.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public synchronized void shutDown() { shuttingDown = true; notifyAll(); while (shuttingDown) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void waitForReady() { try { while (!ready) { wait(); } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** CommanderTestTwo.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.battle.Battlefield; import acsl.dTank.battle.Simulation; import acsl.dTank.server.Server; import junit.framework.TestCase; public class CommanderTestTwo extends TestCase { public void setUp() throws UnknownHostException, IOException { Initializer.initializeAll(); startListener(); } private void startListener() throws UnknownHostException, IOException { Parameters.setLoggingToTTY(true); Battlefield.create("testMaps/empty20x20.map", 1000.0, 1000.0); Simulation.startSimulation(); Server.startPortListener(); } public void test1() throws UnknownHostException, IOException { String[] args = new String[]{"Blue", "Sherman", "NoDisplay", "1", "arg0"}; Commander c = DullCommander.create(args); } public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("==========CommanderTestTwo=========="); CommanderTestTwo test = new CommanderTestTwo(); test.setUp(); test.test1(); System.out.println("==========End CommanderTestTwo=========="); } } *************************************************************************************** DebugCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.communicator.CommanderDebuggerSocketCommunicator; import acsl.dTank.ui.DebuggerControlPanel; public class DebugCommander extends Commander { public static void main(String[] args) throws UnknownHostException, IOException { DebugCommander.create(args); } public static Commander create(String[] args) { // Doesn't work, :-( // DebugCommander c = new DebugCommander(); // c.initialize(args); // return c; return null; } @Override public void initialize(String[] args) { createControlPanel(); debuggerCommunicator = new CommanderDebuggerSocketCommunicator(); debuggerCommunicator.initialize(cmdrName); } public void createControlPanel() { DebuggerControlPanel.create(cmap, this, afvModel); } public void runCommander() throws InterruptedException { for (int i = 0; true; i++) { Thread.sleep(100000); } } } *************************************************************************************** DullCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Utility; import acsl.dTank.informationMessage.InformationMessage; public class DullCommander extends Commander { private DullCommander() { super(); } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1" } public static Commander create(String[] args) { DullCommander c = new DullCommander(); try { c.initialize(args); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return c; } public static void main(String[] args) throws UnknownHostException, IOException { DullCommander.create(args); } public void runCommander() throws InterruptedException { double direction = 0.0; //System.out.println(" afv name " + afvModel.getSpeedMPS() + " " + afvModel.getThrottle()); commanderCommunicator.setDesiredHeading(direction); commanderCommunicator.setDesiredTurretHeading(direction); commanderCommunicator.setThrottle(0.0); while (true) { if (exit) return; sleep(2000); if (afvModel.getThrottle() == 0.0) { direction = Utility.normalizeAngle(120 - (30 * Math.random()) + direction); commanderCommunicator.setDesiredHeading(direction); commanderCommunicator.setDesiredTurretHeading(direction); commanderCommunicator.setThrottle(.250); //commanderCommunicator.setThrottle(1); } } } /** * This a the REAL simulation sleep time
* It waits for the gameTime to increase by time amount of * milliseconds
* The check is performed for each update from the simulation. * * @param time * the time to wait for in milliseconds */ private void sleep(long time) throws InterruptedException { long startTime = gameTime; while ((gameTime - startTime) < time) { synchronized (this) { this.wait(); } } } /** * This method overrides the Commander processMessage adding the notify to * all the listeners waiting for the object this
* This is in hand to synch with the simulation updates.
* Currently used by the sleep(long) method. * * @param InformationMessage * the information update from the Simulation */ public void processMessage(InformationMessage im) { super.processMessage(im); synchronized (this) { this.notify(); } } } *************************************************************************************** DumbCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Utility; import acsl.dTank.informationMessage.InformationMessage; public class DumbCommander extends Commander { private DumbCommander() { super(); } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1" } public static Commander create(String[] args) { DumbCommander c = new DumbCommander(); try { c.initialize(args); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return c; } public static void main(String[] args) throws UnknownHostException, IOException { DumbCommander.create(args); } public void runCommander() throws InterruptedException { double direction = 0.0; //System.out.println(" afv name " + afvModel.getSpeedMPS() + " " + afvModel.getThrottle()); commanderCommunicator.setDesiredHeading(direction); commanderCommunicator.setDesiredTurretHeading(direction); commanderCommunicator.setThrottle(0.0); while (true) { if (exit) return; Thread.sleep(1000); if (afvModel.getThrottle() == 0.0) { direction = Utility.normalizeAngle(120 - (30 * Math.random()) + direction); commanderCommunicator.setDesiredHeading(direction); commanderCommunicator.setDesiredTurretHeading(direction); commanderCommunicator.setThrottle(.250); //commanderCommunicator.setThrottle(1); } } } void processMessage(InformationMessage m) { super.processMessage(m); } } *************************************************************************************** HillCommander.java *************************************************************************************** /** * Specialized example for the El Alamein battle. */ package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.map.TerrainType; public class HillCommander extends Commander { // private int startTime; private double scanInc = 10.0; // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static void main(String[] args) throws UnknownHostException, IOException { int number = 1; String nat = "Blue", afvType = "Sherman", withDisplay = "false"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = Integer.parseInt(args[3]); String[] args2 = new String[] { HillCommander.class.toString(), nat, afvType, withDisplay }; Initializer.initializeAll(); for (int i = 0; i < number; i++) { HillCommander.create(args2); } } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static Commander create(String[] args) { HillCommander c = new HillCommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { // startTime = getTime(); setDesiredHeading(210 + Math.random() * 120); setDesiredTurretHeading(270); setThrottle(1.0); for (int i = 0; true; i++) { if (exit) return; Thread.sleep(1000); DetectedAFV afv = closestEnemy(); double dir = (afv != null) ? calculateTargetHeading(afv) : 0.0; if (inRange(afv) && afvModel.isLoaded()) { writeDisplayMessage("Fire!"); setDesiredTurretHeading(dir); fire(); continue; } if (onEdgesOfHills()) { setThrottle(0.0); if (afv == null) { continueScaning(); continue; } continue; } if (inRange(afv)) { setDesiredHeading(dir + 45); setDesiredTurretHeading(dir); setThrottle(-0.5); continue; } } } private void continueScaning() { double h = afvModel.getTurretHeading(); if (h > 345.0) scanInc = -10; else if (h < 165.0) scanInc = 10; setDesiredTurretHeading(h + scanInc); } private boolean inRange(DetectedAFV afv) { if (afv == null) return false; double dist = calculateTargetDistance(afv); if (dist < 600.0) return true; return false; } private DetectedAFV closestEnemy() { double closest = 100000.0; DetectedAFV closestAFV = null; for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { DetectedAFV afv = cmap.getAFV(j); if (afv.getNationality() == nationality) continue; if (afv.isDestroyed()) continue; double distance = calculateTargetDistance(afv); if (distance < closest) { closest = distance; closestAFV = afv; } } return closestAFV; } public boolean onEdgesOfHills() { if (!cmap.get(afvModel.getX(), afvModel.getY()).equals(TerrainType.LOW_HILL)) return false; TerrainType type = cmap.get(afvModel.getX() - 50.0, afvModel.getY()); if (type.equals(TerrainType.GRASS)) return true; if (type.equals(TerrainType.ROAD)) return true; return false; } } *************************************************************************************** HumanCommander.java *************************************************************************************** /** * Sample commander that just takes input from the display (mouse & keys). */ package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.communicator.CommanderSocketCommunicator; public class HumanCommander extends Commander { // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", ... } public static void main(String[] args) throws UnknownHostException, IOException { int number = 1; String nat = "Blue", afvType = "Sherman", withDisplay = "false"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = Integer.parseInt(args[3]); String[] args2 = new String[] { nat, afvType, withDisplay }; Initializer.initializeAll(); for (int i = 0; i < number; i++) { HumanCommander.create(args2); } } // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", ... } public static Commander create(String[] args) { Commander c = new HumanCommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { } public void setDesiredTurretHeadingEvent(double angle) { setDesiredTurretHeading(angle); } public void incDesiredHeading() { double h = afvModel.getHeading(); h += 20; setDesiredHeading(h); } public void decDesiredHeading() { double h = afvModel.getHeading(); h -= 10; setDesiredHeading(h); } public void decThrottle() { double t = afvModel.getThrottle(); if (t < -0.8) return; setThrottle(t - 0.2); } public void incThrottle() { double t = afvModel.getThrottle(); if (t > 0.8) return; setThrottle(t + 0.2); } public void fireKeyStroke() { fire(); } } *************************************************************************************** JackCommander.java *************************************************************************************** /** * Created by: Paolo Busetta, AOS, 16 October 2007 * * Simple module to send information and command messages via a * socket to an external server. This will be used to integrate JACK * by AOS, but could be used for just anything else. * * The following system properties can be used to control behaviour: * aos.jack.host (default localhost) where the server runs * aos.jack.port (default 4444) port of the server * aos.jack.debug (default null) if !null, print info */ package acsl.dTank.commander; import java.io.*; import java.net.*; import acsl.dTank.communicator.*; import acsl.dTank.afv.*; import acsl.dTank.Utility; import acsl.dTank.informationMessage.InformationMessage; public class JackCommander extends Commander { // sample arg list: { "Blue", "Sherman", "1", "Display", "arg0", "arg1" } static String defaultJackHost = "localhost"; static String defaultJackPort = "4444"; public static Commander create(String[] args) { JackCommander c = new JackCommander(); try { Socket s = new Socket ( System.getProperty ("aos.jack.host", defaultJackHost), Integer.parseInt ( System.getProperty ("aos.jack.port", defaultJackPort)) ); c.inStream = new BufferedReader ( new InputStreamReader(s.getInputStream())); c.outStream = new PrintStream(s.getOutputStream()); c.socket = s; c.initialize(args); c.storeNonStandardOptions ( args, 4 ); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return c; } /// /// /// protected Socket socket; protected BufferedReader inStream; protected PrintStream outStream; protected int commanderNr; protected boolean debugOn = false; protected String[] options = null; static int commanderCounter = 0; private JackCommander() { super(); commanderNr = ++commanderCounter; debugOn = System.getProperty ( "aos.jack.debug" ) != null; } void storeNonStandardOptions ( String[] args, int from ) { options = new String [args.length - from]; for (int i = 0; i < options.length; i++) options [i] = args [i + from]; } void printout ( Object ... args ) { if (!debugOn) return; System.err.print ( "(" + commanderNr + ") " ); for (Object o: args) System.err.print ( o ); System.err.print ( " " ); System.err.flush(); } void printoutln ( Object ... args ) { if (!debugOn) return; System.err.print ( "(" + commanderNr + ") " ); for (Object o: args) System.err.print ( o ); System.err.println ( "" ); System.err.flush(); } boolean remoteCommanderStarted = false; public void runCommander() throws InterruptedException { printoutln ("created. ", " afv - name: " + afvName + " model: " + afvModel.toString() + " speed: " + afvModel.getSpeedMPS() + " throttle: " + afvModel.getThrottle()); Thread.sleep (1000); /// give time to finish initialization /// /// Inform the JACK side of our basic parameters. /// outStream.println ( "# selfName " + cmdrName ); outStream.println ( "# afvName " + afvName ); outStream.println ( "# nation " + nationality.getName() ); outStream.println ( "# afvModel " + afvModel.getAFVType().getName() ); outStream.println ( "# afvSpeed " + afvModel.getSpeedMPS() ); outStream.println ( "# afvThrottle " + afvModel.getThrottle() ); outStream.println ( "# optionsNr " + options.length ); for (int i = 0; i < options.length; i++ ) outStream.println ( "# option_" + i + " " + options [i] ); outStream.println ( "# EndOfParameters" ); synchronized (this) { remoteCommanderStarted = true; notifyAll(); /// wake up the sender } int msgCount = 0; while (!exit) { if (exit) return; try { String cmd = inStream.readLine(); if (cmd == null) { printoutln ( "remote leaved!" ); inStream.close(); exit = true; } else { msgCount++; printout ( "r", msgCount ); if (msgCount % 10 == 0) printoutln ( "\nSample: ", cmd ); commanderCommunicator.sendEncodedMsg (cmd); } } catch (Exception e) { System.err.println ( "error reading from input stream" ); e.printStackTrace(); exit = true; } } } public void runListener() throws InterruptedException, IOException { int msgCount = 0; while (!remoteCommanderStarted) { synchronized (this) { wait(); } } while (!exit) { String msg = commanderCommunicator.dequeueEncodedMsg(); if ( msg == null) return; msgCount++; printout ( "J#" + commanderNr + "s" + msgCount ); outStream.println ( msg ); outStream.flush(); } outStream.close(); socket.close(); } void processMessage(InformationMessage m) { System.err.println ( "processMessage should not be required for JackCommander" ); } } *************************************************************************************** JessCommander.java *************************************************************************************** ///** // * Sample commander. (Smarter than the Dull one!) // */ // //// // package acsl.dTank.commander; // //import java.io.IOException; //import java.net.UnknownHostException; //import java.util.*; // //import acsl.dTank.Initializer; // //import acsl.dTank.informationMessage.DetectedAFV; //import acsl.dTank.map.TerrainType; // //import jess.*; // public class JessCommander extends Commander { // // private static int m_agentCount = 0; // private int m_enemyCount = 0; // private boolean m_inTrouble = false; // // private static Random m_rand = new Random(); // // private long m_counter = 0; // private final int PERCEPTION_FACTOR = 100; // private final int ACTION_FACTOR = 10; // // private static final String ENEMYSPOTTED_FACT_NAME = "dtank.types.enemySpotted"; // private static final String INTROUBLE_FACT_NAME = "dtank.types.inTrouble"; // private static final String ENEMY_FACT_NAME = "dtank.types.enemy"; // private static final String FRIEND_FACT_NAME = "dtank.types.friend"; // private static final String ME_FACT_NAME = "dtank.types.me"; // private static final String TERRAIN_FACT_NAME = "dtank.types.terrain"; // private static final String TURRETHEAD_FACT_NAME = "dtank.types.turretHeading"; // private static final String TANKHEAD_FACT_NAME = "dtank.types.tankHeading"; // private static final String THROTTLE_FACT_NAME = "dtank.types.throttle"; // private static final String ACTION_FACT_NAME = "dtank.types.action"; // private static final String ACTION_FIRE_COUNT = "dtank.types.fireCount"; // // private String m_modelFileName; // // private Fact m_enemyFact; // private Fact m_enemySpottedFact; // private Fact m_inTroubleFact; // private Fact m_friendFact; // private Fact m_meFact; // private Fact m_terrainFact; // // Rete rete = new Rete(); // private int noTank = 0; // private Hashtable factList; // private int factID; // private String initSpace = null; // // // {"Blue", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} // public static void main(String[] args) throws UnknownHostException, IOException { // String nat = "Blue", afvType = "Sherman", withDisplay = "Display", number = "1"; // if (args.length > 0) // nat = args[0]; // if (args.length > 1) // afvType = args[1]; // if (args.length > 2) // withDisplay = args[2]; // if (args.length > 3) // number = args[3]; // String[] args2 = new String[] { nat, afvType, withDisplay, number }; // Initializer.initializeAll(); // List cs = new ArrayList(); // int n = Integer.parseInt(number); // for (int i = 0; i < n; i++) { // cs.add(create(args2)); // } // } // // // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} // public static Commander create(String[] args) { // JessCommander c = new JessCommander(); // c.initialize(args); // c.initializeJess(); // return c; // } // // public void initialize(String[] args){ // factList = new Hashtable(); // // super.initialize(args); // if (args.length > 4) // m_modelFileName = args[4]; // else // m_modelFileName = "jessTank.clp"; // // //Now replace any backslash operator with an front slash. // m_modelFileName = m_modelFileName.replace('\\', '/'); // } // // public void initializeJess() { // String ruleFile = m_modelFileName; // // try{ // if(ruleFile != null) // System.out.println("rule file " + ruleFile); // rete.executeCommand("(batch " + ruleFile +")" ); // initSpace = rete.getCurrentModule(); // }catch(JessException j){System.out.println(j.toString());} // } // // //default tank template // public void setTankTemplate(){ // try{ // Deftemplate d = new Deftemplate("tank", " Data base of tanks", rete); // d.addSlot("name", Funcall.NIL, "STRING"); // d.addSlot("nationality", Funcall.NIL, "STRING"); // d.addSlot("distance", Funcall.NIL, "FLOAT"); // d.addSlot("speed", Funcall.NIL, "FLOAT"); // rete.addDeftemplate(d); // // //Another way to create an template - // //rete.executeCommand("(deftemplate tank (slot name)(slot nationality)(slot distance)(slot speed))"); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void removeTankFacts(int i){ // try{ // Fact f = rete.findFactByID(i); // rete.retract(f); // // }catch(JessException j){j.toString();} // } // // public void makeFriendTankFact(double d, double h, DetectedAFV afv){ // try{ // Fact f = new Fact("dtank.types.friend", rete); // f.setSlotValue("x", new Value(afv.getX() , RU.FLOAT)); // f.setSlotValue("y", new Value(afv.getY(), RU.FLOAT)); // f.setSlotValue("nationality", new Value(afv.getNationality().getName(), RU.STRING)); // f.setSlotValue("distance", new Value(d, RU.FLOAT)); // f.setSlotValue("heading", new Value(h, RU.FLOAT)); // assertFacts(FRIEND_FACT_NAME , f); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void makeEnemyTankFact(double d, double h, DetectedAFV afv){ // try{ // Fact f = new Fact("dtank.types.enemy", rete); // f.setSlotValue("x", new Value(afv.getX() , RU.FLOAT)); // f.setSlotValue("y", new Value(afv.getY(), RU.FLOAT)); // f.setSlotValue("nationality", new Value(afv.getNationality().getName(), RU.STRING)); // f.setSlotValue("distance", new Value(d, RU.FLOAT)); // f.setSlotValue("heading", new Value(h, RU.FLOAT)); // assertFacts(ENEMY_FACT_NAME , f); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void makeEnemySpottedFact(String flag){ // try{ // Fact f = new Fact("dtank.types.enemySpotted", rete); // f.setSlotValue("flag", new Value(flag , RU.ATOM)); // assertFacts(ENEMYSPOTTED_FACT_NAME , f); // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void makeEnemyInTroubleFact(String flag){ // try{ // Fact f = new Fact("dtank.types.inTrouble", rete); // f.setSlotValue("flag", new Value(flag , RU.ATOM)); // assertFacts(INTROUBLE_FACT_NAME, f); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void makeMeFact(){ // try{ // Fact f = new Fact("dtank.types.me", rete); // f.setSlotValue("x", new Value(getAFVModel().getX() , RU.FLOAT)); // f.setSlotValue("y", new Value(getAFVModel().getY(), RU.FLOAT)); // f.setSlotValue("nationality", new Value(getAFVModel().getNationality().getName(), RU.STRING)); // f.setSlotValue("ammunition", new Value(getAFVModel().getAmmunitionRemaining(), RU.INTEGER)); // f.setSlotValue("fuel", new Value(getAFVModel().getFuelRemaining(), RU.INTEGER)); // f.setSlotValue("tankHeading", new Value(getAFVModel().getHeading(), RU.FLOAT)); // f.setSlotValue("turretHeading", new Value(getAFVModel().getTurretHeading(), RU.FLOAT)); // f.setSlotValue("speedMPS", new Value(getAFVModel().getSpeedMPS(), RU.FLOAT)); // f.setSlotValue("speedKPH", new Value(getAFVModel().getSpeedKPH(), RU.FLOAT)); // f.setSlotValue("throttle", new Value(getAFVModel().getThrottle(), RU.FLOAT)); // f.setSlotValue("armor", new Value(getAFVModel().getArmorDamage(), RU.FLOAT)); // // assertFacts(ME_FACT_NAME, f); // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void makeTerrainFact(){ // try{ // Fact f = new Fact("dtank.types.terrain", rete); // String l = terrainType(cmap.get(getAFVModel().getX()-40, getAFVModel().getY())); // String r = terrainType(cmap.get(getAFVModel().getX()+40, getAFVModel().getY())); // String u = terrainType(cmap.get(getAFVModel().getX(), getAFVModel().getY()-40)); // String d = terrainType(cmap.get(getAFVModel().getX(), getAFVModel().getY()+40)); // // f.setSlotValue("left", new Value(l , RU.STRING)); // f.setSlotValue("right", new Value(r , RU.STRING)); // f.setSlotValue("up", new Value(u , RU.STRING)); // f.setSlotValue("down", new Value(d , RU.STRING)); // assertFacts(TERRAIN_FACT_NAME, f); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void resetFacts(){ // try{ // rete.reset(); // }catch(JessException j){j.toString();} // } // // public void removeFacts(){ // // //retracting facts by type - Usage // /* // retractAllFactsOfType(ENEMYSPOTTED_FACT_NAME); // */ // retractAllFacts(); // } // // public void assertInitFacts(){ // makeEnemySpottedFact("false"); // makeEnemyInTroubleFact("false"); // } // // public void assertFacts(String type, Fact f){ // try{ // Fact tempHandle = (Fact)factList.get(type); // //rete. // // if(tempHandle!=null){ // rete.retract(tempHandle); // } // // String tempSpace = rete.getCurrentModule(); // //change to topspace so that all facts are entered into the topmost module // if(initSpace != null) // rete.setCurrentModule(initSpace); // Fact handle = rete.assertFact(f); // // //now change back to current module // //rete.setCurrentModule(tempSpace); // // factList.put(type, (Fact)handle); // // }catch(JessException j){System.out.println("Error Defining Template: " + j.toString());} // } // // public void retractAllFactsOfType(String qualifiedDeftemplateName) { // try { // Iterator itt = rete.listFacts(); // while (itt.hasNext()) { // Fact fact = (Fact) itt.next(); // if (fact.getDeftemplate().getName().equals( // qualifiedDeftemplateName)) { // rete.retract(fact); // } // } // } catch (JessException jex) { // jex.printStackTrace(System.err); // } // } // // public void retractAllFacts() { // try { // Iterator itt = rete.listFacts(); // while (itt.hasNext()) { // Fact fact = (Fact) itt.next(); // rete.retract(fact); // } // } catch (JessException jex) { // jex.printStackTrace(System.err); // } // } // // public void runRete(){ // try{ // rete.run(1); // rete.executeCommand("(facts)"); // }catch(JessException j){j.toString();} // } // // private void chill(int time) // { // try // { Thread.sleep(time); // } // catch (Exception e) // {} // } // // private void chill() // { // chill(m_rand.nextInt(100)); // } // // private String terrainType(TerrainType t) // { // String ret = "UNKNOWN"; // if (t.equals(TerrainType.GRASS)) // ret = "grass"; // else if (t.equals(TerrainType.HIGH_HILL)) // ret = "highHill"; // else if (t.equals(TerrainType.LOW_HILL)) // ret = "lowHill"; // else if (t.equals(TerrainType.OFF_MAP)) // ret = "offMap"; // else if (t.equals(TerrainType.ROAD)) // ret = "road"; // else if (t.equals(TerrainType.STONE)) // ret = "stone"; // else if (t.equals(TerrainType.WOODS)) // ret = "woods"; // // return ret; // } // // public void handleAction(){ // // Value retValue ; // Double turretHeading, tankHeading, throttle; // String action; // boolean tankCommand = false, turretCommand = false, actionCommand = false, throttleCommand = false; // // try{ // Iterator it = rete.listFacts(); // // if(it!=null){ // // while(it.hasNext()){ // Fact f = ((Fact)it.next()); // // if ((f.getName().equals(rete.getCurrentModule()+"::"+TANKHEAD_FACT_NAME) && (tankCommand == false ))){ // Value v = f.getSlotValue("value"); // tankHeading = v.floatValue(rete.getGlobalContext()); // // if (tankHeading != null) // { // commanderCommunicator.setDesiredHeading(tankHeading); // System.out.println("heading: " + tankHeading); // tankCommand = true; // chill(1000); // } // } // else if ((f.getName().equals(rete.getCurrentModule()+"::"+TURRETHEAD_FACT_NAME) && (turretCommand == false))){ // Value v = f.getSlotValue("value"); // turretHeading = v.floatValue(rete.getGlobalContext()); // // if (turretHeading != null) // { // commanderCommunicator.setDesiredTurretHeading(turretHeading); // System.out.println("turret heading: " + turretHeading); // turretCommand = true; // chill(250); // } // } // else if (f.getName().equals(rete.getCurrentModule()+"::"+THROTTLE_FACT_NAME)){ // Value v = f.getSlotValue("value"); // throttle = v.floatValue(rete.getGlobalContext()); // if (throttle != null) // { // commanderCommunicator.setThrottle(throttle); // System.out.println("throttle: " + throttle); // chill(1000); // } // // } // else if (f.getName().equals(rete.getCurrentModule()+"::"+ACTION_FACT_NAME)){ // Value v = f.getSlotValue("value"); // action = v.stringValue(rete.getGlobalContext()); // // if (action.equals("fire")){ // fire(); // System.out.println("fire "); // }else if (action.equals("faster")){ // if (getAFVModel().getThrottle() < 0.9) // { // commanderCommunicator.setThrottle(getAFVModel().getThrottle()+0.1); // System.out.println("faster "); // chill(1000); // } // } // else if (action.equals("slower")) // { // if (getAFVModel().getThrottle() > 0.1) // { // commanderCommunicator.setThrottle(getAFVModel().getThrottle()-0.1); // System.out.println("slower "); // chill(1000); // } // } // else if (action.equals("rotateTurret")) // { // commanderCommunicator.setDesiredTurretHeading(getAFVModel().getTurretHeading()+30.0); // System.out.println("rotateTurret "); // chill(250); // } // else if (action.equals("rotateTank")) // { // commanderCommunicator.setDesiredHeading(getAFVModel().getHeading()+30.0); // System.out.println("rotateTank "); // chill(500); // } // // // } // } // } // // }catch(JessException j){j.toString();} // } // // public void runCommander() throws InterruptedException { // boolean retreating = false; // commanderCommunicator.setDesiredHeading(90); // commanderCommunicator.setThrottle(0.4); // // for (int i = 0; true; i++) { // // if (exit) // return; // Thread.sleep(1000); // if (gameTime - previousGameTime < 1000) // continue; // previousGameTime = gameTime; // if (retreating && afvModel.getThrottle() != 0.0) // continue; // retreating = false; // commanderCommunicator.setDesiredTurretHeading(afvModel.getTurretHeading() + 15.0); // // if (afvModel.getThrottle() == 0.0) // commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 10.0 + 10 * Math.random()); // commanderCommunicator.setThrottle(0.4); // // synchronized (cmap) { // int count = 0; // // assertInitFacts(); // // for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { // // DetectedAFV afv = cmap.getAFV(j); // // if (getAFVModel().getX() == afv.getX() && // getAFVModel().getY() == afv.getY()) // continue; // // if (afv.isDestroyed()) // continue; // // double targetHeading = calculateTargetHeading(afv); // double distance = calculateTargetDistance(afv); // // if (afv.getNationality() == nationality) // { // if (getAFVModel().getX() != afv.getX() && // getAFVModel().getY() != afv.getY()) // { // makeFriendTankFact( distance, targetHeading, afv); // } // } // else // { // count++; // makeEnemyTankFact(distance, targetHeading, afv); // makeEnemySpottedFact("true"); // } // // if(getAFVModel().getArmorDamage() >= 0.4){ // makeEnemyInTroubleFact("true"); // } // if ( (count == 0 && m_enemyCount != 0) || // (count > 0 && m_enemyCount == 0) // ) // { // m_enemyCount = count; // makeEnemySpottedFact("true"); // } // // // makeMeFact(); // makeTerrainFact(); // runRete(); // handleAction(); // // /* // // //commanderCommunicator.setDesiredTurretHeading(targetHeading); // //commanderCommunicator.setDesiredHeading(targetHeading); // if (distance < 200.0 && afv.getNationality() != nationality) { // writeDisplayMessage("Too close. Retreat!"); // retreating = true; // commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 10.0 + 10 * Math.random()); // commanderCommunicator.setThrottle(-.50); // if (afvModel.isLoaded() ) { // writeDisplayMessage("Fire!"); // fire(); // } // continue; // } else // commanderCommunicator.setThrottle(1.0); // if (distance > 600.0 && afv.getNationality() != nationality) { // writeDisplayMessage("Too far to fire: " + Utility.shorten(distance)); // continue; // } // commanderCommunicator.setDesiredHeading(afvModel.getHeading() + 10.0 + 10 * Math.random()); // */ // // } // } // } } // } *************************************************************************************** RadioMessageTest.java *************************************************************************************** package acsl.dTank.commander; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.Parameters; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Battlefield; import acsl.dTank.communicator.CommanderCommunicator; public class RadioMessageTest extends TestCase { Commander commander; CommanderCommunicator commanderCommunicator; public void setUp() throws UnknownHostException, IOException { Battlefield.create("testMaps/empty20x20.map", 1000.0, 1000.0); startListener(); commander = SmartCommander.create(new String[] { "Blue", "Sherman", "Display", "1", "arg0" }); commanderCommunicator = commander.getCommanderCommunicator(); } public void test1() throws UnknownHostException, IOException { commanderCommunicator.sendRadioMessage("EnemyAt|123.4|45.3"); } public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("==========RadioMessageTest=========="); RadioMessageTest test = new RadioMessageTest(); test.setUp(); test.test1(); // test.test2(); } private void startListener() { SCTListener2 sct = new SCTListener2(); new Thread(sct).start(); sct.waitForReady(); } } class SCTListener2 implements Runnable { private String expectedInitialization = ""; private String initReply = ""; private String expectedRadioMessage = ""; private boolean ready = false; public void run() { try { ServerSocket listenSocket = new ServerSocket(Parameters.getPort()); synchronized (this) { ready = true; this.notifyAll(); } Socket socket = listenSocket.accept(); BufferedReader inStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); String input = inStream.readLine(); TestCase.assertEquals(expectedInitialization, input); outStream.println(initReply); while (true) { input = inStream.readLine(); if (input.indexOf("Radio") != -1) break; } TestCase.assertEquals(expectedRadioMessage, input); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public synchronized void waitForReady() { try { while (!ready) { wait(); } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** RemoteCommander.java *************************************************************************************** /** * Sample code for starting a remote process for a commander. No reason I can * think of not to use this for all remote processes in any language. (See RemoteSmartCommander) * * Running the Server under Eclipse requires the CLASSPATH and PATH to be set up just so. It * can be confusing and not recommened. I don't even test remote commanders under Eclipse. */ package acsl.dTank.commander; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public abstract class RemoteCommander extends Commander { public static void startRemoteProcess(String programName, String flagString, String cName, String[] args) { try { Runtime r = Runtime.getRuntime(); String[] flags = flagString.split(" "); int size = flags.length + args.length + 2; String[] cmd = new String[size]; cmd[0] = programName; for (int i = 1; i <= flags.length; i++) { cmd[i] = flags[i - 1]; } cmd[flags.length + 1] = cName; for (int i = 0; i < args.length; i++) cmd[i + flags.length + 2] = args[i]; // /usr/bin/java acsl.dTank.commander.SmartCommander Blue Sherman 1 // Display arg0 arg1 arg2 System.out.println("Started Remote Commander: " + makeString(cmd)); Process p = r.exec(cmd); } catch (IOException e) { throw new RuntimeException(e); } } private static String makeString(String[] cmd) { StringBuilder sb = new StringBuilder(); for (String s : cmd) sb.append(s + " "); return sb.toString(); } public static void debugRemoteProcess(String programName, String flags, String cName, String[] args) { try { // programName = "/bin/echo"; // programName = "/Users/bil/junk/debugRemote.csh"; // cName = "/bin/echo"; Runtime r = Runtime.getRuntime(); String[] cmd = new String[args.length + 4]; cmd[0] = programName; cmd[1] = flags; cmd[2] = "com.lambda.Debugger.Debugger"; cmd[3] = cName; for (int i = 0; i < args.length; i++) cmd[i + 4] = args[i]; // /usr/bin/java com.lambda.Debugger.Debugger // acsl.dTank.commander.SmartCommander Blue Sherman 1 Display arg0 // arg1 arg2 Process p = r.exec(cmd); BufferedReader inStream = new BufferedReader(new InputStreamReader( p.getInputStream())); String line = inStream.readLine(); try { p.waitFor(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(line); System.out.println("Process exit: " + p.exitValue()); } catch (IOException e) { throw new RuntimeException(e); } } public void runCommander() throws InterruptedException { throw new RuntimeException("Cannot run a RemoteCommander locally."); } } *************************************************************************************** RemoteCommanderTest.java *************************************************************************************** package acsl.dTank.commander; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; public class RemoteCommanderTest extends TestCase { SCTListener3 sct; private Thread thread; Commander c; public void setUp() { Initializer.initializeAll(); startListener(); } protected void tearDown() { //c.shutDown(); } private void startListener() { sct = new SCTListener3(); thread = new Thread(sct); thread.start(); sct.waitForReady(); } public void test1() throws UnknownHostException, IOException { String[] args = new String[] { "Blue", "Sherman", "1", "Display", "arg0", "arg1" }; c = RemoteSmartCommander.create(args); } public static void main(String[] args) throws UnknownHostException, IOException { System.out.println("==========RemoteCommanderTest=========="); RemoteCommanderTest test = new RemoteCommanderTest(); test.setUp(); test.test1(); test.tearDown(); System.out.println("==========End CommanderTest=========="); } } class SCTListener3 implements Runnable { private String expectedInitialization = ""; private String initReply = ""; private boolean ready = false; private boolean shuttingDown = false; public void run() { try { ServerSocket listenSocket = new ServerSocket(Parameters.getPort()); synchronized (this) { ready = true; this.notifyAll(); } Socket socket = listenSocket.accept(); BufferedReader inStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); String input = inStream.readLine(); TestCase.assertEquals(expectedInitialization, input); outStream.println(initReply); listenSocket.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public synchronized void shutDown() { shuttingDown = true; notifyAll(); while (shuttingDown) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void waitForReady() { try { while (!ready) { wait(); } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** RemoteSmartCommander.java *************************************************************************************** /** * This starts a remote Java process that runs a SmartCommander. Create a similar class * to start your favorite commander in whatever language you desire. */ package acsl.dTank.commander; public class RemoteSmartCommander extends RemoteCommander { // Never call main() from command line. public static Commander create(String[] args) { String programName = "/usr/bin/java"; String flags = "-cp /Users/bil/Workspaces/dTankWorkspace2/dTank4.3/bin"; String cName = "acsl.dTank.commander.SmartCommander"; startRemoteProcess(programName, flags, cName, args); return null; } } *************************************************************************************** SmartCommander.java *************************************************************************************** /** * Sample commander. (Smarter than the Dull one!) */ package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Utility; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.InformationMessage; public class SmartCommander extends Commander { // {"Blue", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} public static void main(String[] args) throws UnknownHostException, IOException { String nat = "Blue", afvType = "Sherman", withDisplay = "Display", number = "1"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = args[3]; String[] args2 = new String[] { nat, afvType, withDisplay, number }; Initializer.initializeAll(); List cs = new ArrayList(); int n = Integer.parseInt(number); for (int i = 0; i < n; i++) { cs.add(create(args2)); } } // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} public static Commander create(String[] args) { System.out.println("Starting up: " +args[0]+" "+args[1]+" "+args[2]+" "+args[3]+" "); SmartCommander c = new SmartCommander(); c.initialize(args); return c; } /** * This a the REAL simulation sleep time
* It waits for the gameTime to increase by time amount of * milliseconds
* The check is performed for each update from the simulation. * * @param time * the time to wait for in milliseconds */ private void sleep(long time) throws InterruptedException { long startTime = gameTime; while ((gameTime - startTime) < time) { synchronized (this) { this.wait(); } } } /** * This method overrides the Commander processMessage adding the notify to * all the listeners waiting for the object this
* This is in hand to synch with the simulation updates.
* Currently used by the sleep(long) method. * * @param InformationMessage * the information update from the Simulation */ public void processMessage(InformationMessage im) { super.processMessage(im); synchronized (this) { this.notify(); } } public void runCommander() throws InterruptedException { boolean retreating = false; commanderCommunicator.setDesiredHeading(360 * Math.random()); commanderCommunicator.setThrottle(1.0); // Thread.sleep(2000); this.sleep(2000); commanderCommunicator.setThrottle(0.0); boolean enemySpotted = false; for (int i = 0; true; i++) { if (exit) return; /* * Thread.sleep(1000); if (gameTime - previousGameTime < 1000) * continue; */ this.sleep(1000); previousGameTime = gameTime; if (retreating && afvModel.getThrottle() != 0.0) retreating = false; if (!enemySpotted) { commanderCommunicator.setDesiredTurretHeading(afvModel .getTurretHeading() + 15.0); if (afvModel.getThrottle() == 0.0) commanderCommunicator.setDesiredHeading(afvModel .getHeading() + 10.0 + 20 * Math.random()); if (!retreating) commanderCommunicator.setThrottle(0.4); } boolean farEnough = true; synchronized (cmap) { enemySpotted = false; for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { DetectedAFV afv = cmap.getAFV(j); if (afv.getNationality() == nationality) continue; if (afv.isDestroyed()) continue; enemySpotted = true; double targetHeading = calculateTargetHeading(afv); double distance = calculateTargetDistance(afv); commanderCommunicator .setDesiredTurretHeading(targetHeading); commanderCommunicator.setDesiredHeading(targetHeading); // writeDisplayMessage("Spotted enemy tank at " + // Utility.shorten(targetHeading) + " degrees " + // Utility.shorten(distance) + " meters."); if (distance < 500.0) { writeDisplayMessage("Too close. Retreat!"); retreating = true; commanderCommunicator.setDesiredHeading(afvModel .getHeading() + 60 * Math.random()); commanderCommunicator.setThrottle(-.50); } else { if (!retreating) commanderCommunicator.setThrottle(1.0); } if (distance < 1500.0) farEnough = false; if (distance > 1600.0) { writeDisplayMessage("Too far to fire: " + Utility.shorten(distance)); continue; } // setThrottle(0.0); if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); commanderCommunicator.setIntendedRange(distance * 1.05); fire(); } } } if (farEnough) retreating = false; } } } *************************************************************************************** SoarCommander.java *************************************************************************************** package acsl.dTank.commander; // //import java.io.IOException; // //import java.net.UnknownHostException; //import java.util.ArrayList; //import java.util.List; //import java.util.Random; //import java.util.StringTokenizer; // //import acsl.dTank.Initializer; //import acsl.dTank.Logger; //import acsl.dTank.Parameters; //import acsl.dTank.battle.Simulation; //import acsl.dTank.informationMessage.DetectedAFV; //import acsl.dTank.map.TerrainType; // //import sml.*; // // public class SoarCommander extends Commander { // private static int m_agentCount = 0; // private int m_enemyCount = 0; // private boolean m_inTrouble = false; // private Kernel m_kernel; // private Agent m_agent; // private static Random m_rand = new Random(); // // private long m_counter = 0; // private final int PERCEPTION_FACTOR = 100; // private final int ACTION_FACTOR = 10; // // private static final String ENEMYSPOTTED_FACT_NAME = "dtank.types.enemySpotted"; // private static final String INTROUBLE_FACT_NAME = "dtank.types.inTrouble"; // private static final String ENEMY_FACT_NAME = "dtank.types.enemy"; // private static final String FRIEND_FACT_NAME = "dtank.types.friend"; // private static final String ME_FACT_NAME = "dtank.types.me"; // private static final String TERRAIN_FACT_NAME = "dtank.types.terrain"; // private static final String TURRETHEAD_FACT_NAME = "dtank.types.turretHeading"; // private static final String TANKHEAD_FACT_NAME = "dtank.types.tankHeading"; // private static final String THROTTLE_FACT_NAME = "dtank.types.throttle"; // private static final String ACTION_FACT_NAME = "dtank.types.action"; // private static final String ACTION_FIRE_COUNT = "dtank.types.fireCount"; // // private String m_modelFileName; // // private Identifier m_enemyFact; // private Identifier m_enemySpottedFact; // private Identifier m_inTroubleFact; // private Identifier m_friendFact; // private Identifier m_meFact; // private Identifier m_terrainFact; // // // {"Blue", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} // public static void main(String[] args) throws UnknownHostException, IOException // { // String nat = "Blue", afvType = "Sherman", withDisplay = "Display", number = "1"; // if (args.length > 0) // nat = args[0]; // if (args.length > 1) // afvType = args[1]; // if (args.length > 2) // withDisplay = args[2]; // if (args.length > 3) // number = args[3]; // String[] args2 = new String[] { nat, afvType, withDisplay, number }; // Initializer.initializeAll(); // List cs = new ArrayList(); // int n = Integer.parseInt(number); // for (int i = 0; i < n; i++) // { // cs.add(create(args2)); // } // } // // // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} // public static Commander create(String[] args) // { // SoarCommander c = new SoarCommander(); // c.initialize(args); // return c; // } // // public void initialize(String[] args) // { // super.initialize(args); // if (args.length > 4) // m_modelFileName = args[4]; // else // m_modelFileName = "tank.soar"; // } // // // public void runCommander() //throws InterruptedException { // try // { // try // { // m_kernel = Kernel.CreateKernelInCurrentThread("SoarKernelSML"); // } // catch (Exception e) // { // throw new IllegalStateException("Error creating Soar kernel: " // + e.getMessage()); // } // // if (m_kernel.HadError()) // { // throw new IllegalStateException("Error creating Soar kernel: " // + m_kernel.GetLastErrorDescription()); // } // // m_kernel.AddRhsFunction("rand", this, "rand", this); // // m_agent = m_kernel.CreateAgent("SoarAgent" + m_agentCount++); // boolean load = m_agent.LoadProductions(m_modelFileName); // if (!load || m_agent.HadError()) // { // throw new IllegalStateException("Error loading productions: " // + m_agent.GetLastErrorDescription()); // } // // Logger.logAll("Soar agent file: " + m_modelFileName); // // // Register for the event we'll use to update the world // registerForUpdateWorldEvent() ; // // createFacts(); // // while (!getAFVModel().isDestroyed() && // ((Parameters.getBattleDuration() - gameTime) >= 3000) && // (!Simulation.isStopped()) // ) // { // if (!Simulation.isPaused()) // m_agent.RunSelf(1); // } // } // catch (Exception e) // { // throw new IllegalStateException(e); // } // finally // { // shutDown(); // } // } // // protected void createFacts() // { // synchronized (cmap) // { // int count = 0; // for (int j = 0, size = cmap.getNAFVs(); j < size; j++) // { // DetectedAFV afv = cmap.getAFV(j); // // if (!afv.isDestroyed()) // { // double heading = calculateTargetHeading(afv); // double distance = calculateTargetDistance(afv); // // if (afv.getNationality() == nationality) // { // if (getAFVModel().getX() != afv.getX() && // getAFVModel().getY() != afv.getY()) // // { // if (m_friendFact != null) // m_agent.DestroyWME(m_friendFact); // m_friendFact = m_agent.CreateIdWME(m_agent.GetInputLink(), FRIEND_FACT_NAME); // makeTankFact(m_friendFact, distance, heading, afv); // } // } // else // { // count++; // if (m_enemyFact != null) // m_agent.DestroyWME(m_enemyFact); // m_enemyFact = m_agent.CreateIdWME(m_agent.GetInputLink(), ENEMY_FACT_NAME); // makeTankFact(m_enemyFact, distance, heading, afv); // } // } // // if (m_enemySpottedFact == null) // { // m_enemySpottedFact = m_agent.CreateIdWME(m_agent.GetInputLink(), ENEMYSPOTTED_FACT_NAME); // m_agent.CreateStringWME(m_enemySpottedFact, "flag", ""+(m_enemyCount > 0)); // } // // if (m_inTroubleFact == null) // { // m_inTroubleFact = m_agent.CreateIdWME(m_agent.GetInputLink(), INTROUBLE_FACT_NAME); // m_agent.CreateStringWME(m_inTroubleFact, "flag", ""+m_inTrouble); // } // // if ( (count == 0 && m_enemyCount != 0) || // (count > 0 && m_enemyCount == 0) // ) // { // m_enemyCount = count; // m_agent.DestroyWME(m_enemySpottedFact); // m_enemySpottedFact = m_agent.CreateIdWME(m_agent.GetInputLink(), ENEMYSPOTTED_FACT_NAME); // m_agent.CreateStringWME(m_enemySpottedFact, "flag", ""+(m_enemyCount > 0)); // } // // if (m_inTrouble != (getAFVModel().getArmorDamage() >= 0.4)) // { // m_inTrouble = (getAFVModel().getArmorDamage() >= 0.4); // m_agent.DestroyWME(m_inTroubleFact); // m_inTroubleFact = m_agent.CreateIdWME(m_agent.GetInputLink(), INTROUBLE_FACT_NAME); // m_agent.CreateStringWME(m_inTroubleFact, "flag", ""+m_inTrouble); // } // // if (m_meFact != null) // m_agent.DestroyWME(m_meFact); // m_meFact = m_agent.CreateIdWME(m_agent.GetInputLink(), ME_FACT_NAME); // makeMeFact(m_meFact); // // if (m_terrainFact != null) // m_agent.DestroyWME(m_terrainFact); // m_terrainFact = m_agent.CreateIdWME(m_agent.GetInputLink(), TERRAIN_FACT_NAME); // String l = terrainType(cmap.get(getAFVModel().getX()-40, getAFVModel().getY())); // String r = terrainType(cmap.get(getAFVModel().getX()+40, getAFVModel().getY())); // String u = terrainType(cmap.get(getAFVModel().getX(), getAFVModel().getY()-40)); // String d = terrainType(cmap.get(getAFVModel().getX(), getAFVModel().getY()+40)); // m_agent.CreateStringWME(m_terrainFact, "left", l); // m_agent.CreateStringWME(m_terrainFact, "right", r); // m_agent.CreateStringWME(m_terrainFact, "up", u); // m_agent.CreateStringWME(m_terrainFact, "down", d); // } // // m_agent.Commit(); // } // } // // protected void handleAction() // { // if (m_agent.Commands()) // { // Identifier command = m_agent.GetCommand(0); // String name = command.GetCommandName(); // String value = command.GetParameterValue("value"); // if (name.equals(TURRETHEAD_FACT_NAME)) // { // if (value != null) // { // commanderCommunicator.setDesiredTurretHeading(Double.parseDouble(value)); // chill(250); // } // } // else if (name.equals(TANKHEAD_FACT_NAME)) // { // if (value != null) // { // commanderCommunicator.setDesiredHeading(Double.parseDouble(value)); // chill(500); // } // } // else if (name.equals(THROTTLE_FACT_NAME)) // { // if (value != null) // { // commanderCommunicator.setThrottle(Double.parseDouble(value)); // chill(1000); // } // } // else if (name.equals(ACTION_FACT_NAME)) // { // if (value.equals("fire")) // fire(); // else if (value.equals("faster")) // { // if (getAFVModel().getThrottle() < 0.9) // { // commanderCommunicator.setThrottle(getAFVModel().getThrottle()+0.1); // chill(1000); // } // } // else if (value.equals("slower")) // { // if (getAFVModel().getThrottle() > 0.1) // { // commanderCommunicator.setThrottle(getAFVModel().getThrottle()-0.1); // chill(1000); // } // } // else if (value.equals("rotateTurret")) // { // commanderCommunicator.setDesiredTurretHeading(getAFVModel().getTurretHeading()+30.0); // chill(250); // } // else if (value.equals("rotateTank")) // { // commanderCommunicator.setDesiredHeading(getAFVModel().getHeading()+30.0); // chill(500); // } // } // else if (name.equals(ACTION_FIRE_COUNT)){ // // } // // command.AddStatusComplete(); // m_agent.ClearOutputLinkChanges(); // } // } // //// handlers... // // public void registerForUpdateWorldEvent() // { // m_agent.RegisterForRunEvent(smlRunEventId.smlEVENT_AFTER_DECISION_CYCLE, this, "afterDecisionHandler", null) ; // m_agent.RegisterForPrintEvent(smlPrintEventId.smlEVENT_PRINT, this, "printEventHandler", this) ; // } // // public void printEventHandler(int eventID, Object data, Agent agent, String message) // { // print(message); // } // // public String rand(int id, Object data, String agentName, String functionName, String arguments) // { // List choices = new ArrayList(); // StringTokenizer tokenizer = new StringTokenizer(arguments, ","); // while (tokenizer.hasMoreTokens()) // { // String tk = tokenizer.nextToken(); // if (tk.trim().length() > 0) // choices.add(tk.trim()); // } // // int i = 0; // if (choices.size() > 0) // i = m_rand.nextInt(choices.size()); // // return choices.get(i); // } // // public void afterDecisionHandler(int eventID, Object data, Agent agent, int phase) // { // // only handle actions every Nth decision cycle // if ( (m_counter % ACTION_FACTOR) == 0) // { // debug("Handling Actions..."); // handleAction(); // } // // // only update the sensors every Mth decision cycle // if ( (m_counter % PERCEPTION_FACTOR) == 0) // { // debug("Getting facts..."); // createFacts(); // } // // m_counter++; // } // // private void makeTankFact(Identifier f, double d, double h, DetectedAFV afv) // { // m_agent.CreateFloatWME(f, "x", afv.getX()); // m_agent.CreateFloatWME(f, "y", afv.getY()); // m_agent.CreateStringWME(f, "nationality", afv.getNationality().getName()); // m_agent.CreateFloatWME(f, "distance", d); // m_agent.CreateFloatWME(f, "heading", h); // } // // private void makeMeFact(Identifier f) // { // m_agent.CreateFloatWME(f, "x", getAFVModel().getX()); // m_agent.CreateFloatWME(f, "y", getAFVModel().getY()); // m_agent.CreateStringWME(f, "nationality", getAFVModel().getNationality().getName()); // m_agent.CreateIntWME(f, "ammunition", getAFVModel().getAmmunitionRemaining()); // m_agent.CreateFloatWME(f, "fuel", getAFVModel().getFuelRemaining()); // m_agent.CreateFloatWME(f, "tankHeading", getAFVModel().getHeading()); // m_agent.CreateFloatWME(f, "turretHeading", getAFVModel().getTurretHeading()); // m_agent.CreateFloatWME(f, "speedMPS", getAFVModel().getSpeedMPS()); // m_agent.CreateFloatWME(f, "speedKPH", getAFVModel().getSpeedKPH()); // m_agent.CreateFloatWME(f, "throttle", getAFVModel().getThrottle()); // m_agent.CreateFloatWME(f, "armor", getAFVModel().getArmorDamage()); // } // // private void clearFacts(){ // m_enemyFact = null; // m_friendFact = null; // m_enemySpottedFact = null; // m_meFact = null; // m_terrainFact = null; // } // // private String terrainType(TerrainType t) // { // String ret = "UNKNOWN"; // if (t.equals(TerrainType.GRASS)) // ret = "grass"; // else if (t.equals(TerrainType.HIGH_HILL)) // ret = "highHill"; // else if (t.equals(TerrainType.LOW_HILL)) // ret = "lowHill"; // else if (t.equals(TerrainType.OFF_MAP)) // ret = "offMap"; // else if (t.equals(TerrainType.ROAD)) // ret = "road"; // else if (t.equals(TerrainType.STONE)) // ret = "stone"; // else if (t.equals(TerrainType.WOODS)) // ret = "woods"; // // return ret; // // } // // private void debug(String s) // { // //s = s.replace("\n", ""); // if (s.trim().length() > 0); // { // Logger.log(m_agent.GetAgentName() + ": " + s); // Logger.flushAll(); // } // } // // private void print(String s) // { // //s = s.replace("|", " "); // s = s.trim(); // if (s.length() > 0) // { // Logger.logAll(m_agent.GetAgentName() + ": " + s); // Logger.flushAll(); // } // } // // private void chill(int time) // { // try // { Thread.sleep(time); // } // catch (Exception e) // {} // } // // private void chill() // { // chill(m_rand.nextInt(100)); // } // // private void yield() // { // try // {Thread.yield(); } // catch (Exception e) // {} // } // // public void shutDown() // { // if (m_kernel != null) // { // m_agent.StopSelf(); // m_kernel.DestroyAgent(m_agent); // //m_kernel.Shutdown(); // //m_kernel.delete(); // } // m_agent = null; // m_kernel = null; // // clearFacts(); // super.shutDown(); } } *************************************************************************************** StationaryCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.informationMessage.InformationMessage; public class StationaryCommander extends Commander { // { "Blue", "Sherman", "1", "Display", "arg0", "arg1" } public static Commander create(String[] args) { StationaryCommander c = new StationaryCommander(); try { c.initialize(args); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return c; } public static void main(String[] args) throws UnknownHostException, IOException { StationaryCommander.create(args); } public void runCommander() throws InterruptedException { } void processMessage(InformationMessage m) { super.processMessage(m); } } *************************************************************************************** StationaryFiringCommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Utility; import acsl.dTank.informationMessage.DetectedAFV; public class StationaryFiringCommander extends Commander { // {"Blue", "Sherman", "Display", "3", "arg0", "arg1", "arg2", ..} public static void main(String[] args) throws UnknownHostException, IOException { String nat = "Blue", afvType = "Sherman", withDisplay = "Display", number = "1"; if (args.length > 0) nat = args[0]; if (args.length > 1) afvType = args[1]; if (args.length > 2) withDisplay = args[2]; if (args.length > 3) number = args[3]; String[] args2 = new String[] { nat, afvType, withDisplay, number }; Initializer.initializeAll(); List cs = new ArrayList(); int n = Integer.parseInt(number); for (int i = 0; i < n; i++) { cs.add(create(args2)); } } // { "Blue", "Sherman", "Display", "1", "arg0", "arg1", "arg2", ..} public static Commander create(String[] args) { StationaryFiringCommander c = new StationaryFiringCommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { for (int i = 0; true; i++) { if (exit) return; Thread.sleep(1000); if (gameTime - previousGameTime < 1000) continue; previousGameTime = gameTime; commanderCommunicator.setDesiredTurretHeading(afvModel.getTurretHeading() + 15.0); synchronized (cmap) { for (int j = 0, size = cmap.getNAFVs(); j < size; j++) { DetectedAFV afv = cmap.getAFV(j); if (afv.getNationality() == nationality) continue; if (afv.isDestroyed()) continue; double targetHeading = calculateTargetHeading(afv); double distance = calculateTargetDistance(afv); commanderCommunicator.setDesiredTurretHeading(targetHeading); if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); commanderCommunicator.setIntendedRange(distance); fire(); } } } } } } *************************************************************************************** TestACommander.java *************************************************************************************** package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.afv.Nationality; public class TestACommander extends Commander { private static int number = 1; // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static void main(String[] args) throws UnknownHostException, IOException { if (args.length > 2) number = Integer.parseInt(args[2]); Initializer.initializeAll(); for (int i = 0; i < number; i++) { Commander c = TestACommander.create(args); } } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static Commander create(String[] args) { TestACommander c = new TestACommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { if (nationality == Nationality.BLUE) { commanderCommunicator.setDesiredTurretHeading(300); commanderCommunicator.setDesiredHeading(270); } else { commanderCommunicator.setDesiredTurretHeading(110); commanderCommunicator.setDesiredHeading(90); } commanderCommunicator.setThrottle(1.0); Thread.sleep(2000); commanderCommunicator.setThrottle(0.0); for (int i = 0; true; i++) { Thread.sleep(1000); if (gameTime - previousGameTime < 1000) continue; previousGameTime = gameTime; if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); fire(); } } } } package acsl.dTank.commander; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.Initializer; import acsl.dTank.afv.Nationality; public class TestACommander extends Commander { private static int number = 1; // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static void main(String[] args) throws UnknownHostException, IOException { if (args.length > 2) number = Integer.parseInt(args[2]); Initializer.initializeAll(); for (int i = 0; i < number; i++) { Commander c = TestACommander.create(args); } } // { "Blue", "Sherman", "1", "Display", "arg0", "arg1", ... } public static Commander create(String[] args) { TestACommander c = new TestACommander(); c.initialize(args); return c; } public void runCommander() throws InterruptedException { if (nationality == Nationality.BLUE) { commanderCommunicator.setDesiredTurretHeading(300); commanderCommunicator.setDesiredHeading(270); } else { commanderCommunicator.setDesiredTurretHeading(110); commanderCommunicator.setDesiredHeading(90); } commanderCommunicator.setThrottle(1.0); Thread.sleep(2000); commanderCommunicator.setThrottle(0.0); for (int i = 0; true; i++) { Thread.sleep(1000); if (gameTime - previousGameTime < 1000) continue; previousGameTime = gameTime; if (afvModel.isLoaded()) { writeDisplayMessage("Fire!"); fire(); } } } } *************************************************************************************** CommandMessage.java *************************************************************************************** /** * This is the msg that a commander sends to the server. */ package acsl.dTank.commandMessage; import acsl.dTank.Utility; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.commandMessage.parser.CommandParser; import acsl.dTank.controller.AFVController; import acsl.dTank.informationMessage.InformationMessage; public class CommandMessage { private static final String DELIMITORS = "[<: >]"; private double throttle, desiredHeading, desiredTurretHeading; private boolean settingThrottle = false, settingDesiredHeading = false, settingDesiredTurretHeading = false; private boolean fireGun; protected String input; protected double heading; protected boolean settingHeading; private boolean settingDesiredGunElevation; private double desiredGunElevation; private boolean settingFire; private String radioMessage; private boolean isSettingRadioMessage; private AFVType afvType; private Nationality nationality; private String from; protected String to; private double intendedRange; private boolean isSettingIntendedRange; public CommandMessage() { } public boolean isSettingThrottle() { return settingThrottle; } public boolean isSettingDesiredHeading() { return settingDesiredHeading; } public boolean isSettingDesiredTurretHeading() { return settingDesiredTurretHeading; } public boolean isFireGun() { return fireGun; } public double getThrottle() { return throttle; } public double getDesiredHeading() { return desiredHeading; } public double getDesiredTurretHeading() { return desiredTurretHeading; } // public static CommandMessage create(String input) { CommandMessage im = new CommandMessage(); im.input = input; String[] tokens = InformationMessage.dropBlanks(input.split(DELIMITORS)); int len = tokens.length; if (len < 4) throw new RuntimeException("Unknown command " + input); for (int i = 0; i < len;) { i += im.parse(tokens, i); } return im; } private int parse(String[] tokens, int i) { String typeString = tokens[i]; CommandParser it = CommandParser.lookup(typeString); if (it == null) throw new RuntimeException("Unknown command " + typeString); it.parse(tokens, i + 1, this); return it.getNArgs() + 1; // loc of next cmd } public void setThrottle(String string) { throttle = Double.parseDouble(string); settingThrottle = true; } public void setDesiredHeading(String string) { desiredHeading = Utility.parseHeading(string); settingDesiredHeading = true; } public void setDesiredTurretHeading(String string) { desiredTurretHeading = Utility.parseHeading(string); settingDesiredTurretHeading = true; } public boolean isSettingDesiredGunElevation() { return settingDesiredGunElevation; } public double getDesiredGunElevation() { return desiredGunElevation; } public void setDesiredGunElevation(String string) { desiredGunElevation = Utility.parseHeading(string); settingDesiredGunElevation = true; } public void setFire() { settingFire = true; } public boolean isSettingFire() { return settingFire; } public void setRadioMessage(String msg) { radioMessage = msg; isSettingRadioMessage = true; } public boolean isSettingRadioMessage() { return isSettingRadioMessage; } public String getRadioMessage() { return radioMessage; } public void setAFVType(AFVType afvType) { this.afvType = afvType; } public void setNationality(Nationality nationality) { this.nationality = nationality; } public String getFrom() { return from; } public Nationality getNationality() { return nationality; } public void setFrom(String from) { this.from = from; } public void setTo(String to) { this.to = to; } public AFVType getAFVType() { return afvType; } public boolean isSettingIntendedRange() { return isSettingIntendedRange; } public void setIntendedRange(String string) { intendedRange = Double.parseDouble(string); isSettingIntendedRange = true; } public double getIntendedRange() { return intendedRange; } } *************************************************************************************** CommandMessageTest.java *************************************************************************************** package acsl.dTank.commandMessage; import junit.framework.TestCase; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.TerrainType; public class CommandMessageTest extends TestCase { public static String input0 = ""; public static String input1 = ""; public static String input2 = ""; public static String input3 = ""; public static String input4 = ""; public static String input5 = ""; public void setUp() { Battlefield.create("testMaps/test20x20.map", 1000.0, 1000.0); } public void test1() { CommandMessage im = CommandMessage.create(input0); assertEquals(true, im.isSettingThrottle()); assertEquals(0.5, im.getThrottle(), 0.01); CommandMessage im1 = CommandMessage.create(input1); assertFalse(im1.isSettingThrottle()); assertTrue(im1.isSettingDesiredHeading()); assertEquals(225.3, im1.getDesiredHeading(), 0.01); CommandMessage im2 = CommandMessage.create(input2); assertEquals(false, im2.isSettingThrottle()); assertTrue(im2.isSettingDesiredTurretHeading()); assertEquals(45.6, im2.getDesiredTurretHeading(), 0.01); CommandMessage im3 = CommandMessage.create(input3); assertTrue(im3.isSettingDesiredGunElevation()); assertEquals(3.6, im3.getDesiredGunElevation(), 0.01); CommandMessage im4 = CommandMessage.create(input4); assertTrue(im4.isSettingFire()); } public static void main(String[] args) { System.out.println("==========CommandMessageTest=========="); CommandMessageTest test = new CommandMessageTest(); test.setUp(); test.test1(); } } *************************************************************************************** CommandParser.java *************************************************************************************** /** * These are all the elements that go into a CommandMessage. */ package acsl.dTank.commandMessage.parser; import java.util.HashMap; import acsl.dTank.commandMessage.CommandMessage; public abstract class CommandParser { private String name; private int nArgs; private static HashMap informationTypes = new HashMap(); public abstract void parse(String[] tokens, int i, CommandMessage message); public CommandParser(String name, int nArgs) { this.name = name; this.nArgs = nArgs; } public static void initialize() { initialize(new SetThrottleParser()); initialize(new SetDesiredHeadingParser()); initialize(new SetDesiredTurretHeadingParser()); initialize(new SetIntendedRangeParser()); initialize(new SetDesiredGunElevationParser()); initialize(new SetFireParser()); initialize(new SendRadioMessageParser()); initialize(new SetNationalityParser()); initialize(new SetAFVTypeParser()); initialize(new SetToParser()); initialize(new SetFromParser()); } public static void initialize(CommandParser it) { informationTypes.put(it.getName(), it); } public int getNArgs() { return nArgs; } public String getName() { return name; } public static CommandParser lookup(String typeString) { return (CommandParser) informationTypes.get(typeString); } } *************************************************************************************** SendRadioMessageParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SendRadioMessageParser extends CommandParser { SendRadioMessageParser() { super("SetRadioMessage", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setRadioMessage(tokens[i]); } } *************************************************************************************** SetAFVTypeParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.afv.AFVType; import acsl.dTank.commandMessage.CommandMessage; public class SetAFVTypeParser extends CommandParser { SetAFVTypeParser() { super("SetAFVType", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setAFVType(AFVType.lookup(tokens[i])); } } *************************************************************************************** SetDesiredGunElevationParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetDesiredGunElevationParser extends CommandParser { SetDesiredGunElevationParser() { super("SetDesiredGunElevation", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setDesiredGunElevation(tokens[i]); } } *************************************************************************************** SetDesiredHeadingParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetDesiredHeadingParser extends CommandParser { SetDesiredHeadingParser() { super("SetDesiredHeading", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setDesiredHeading(tokens[i]); } } *************************************************************************************** SetDesiredTurretHeadingParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetDesiredTurretHeadingParser extends CommandParser { SetDesiredTurretHeadingParser() { super("SetDesiredTurretHeading", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setDesiredTurretHeading(tokens[i]); } } *************************************************************************************** SetFireParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetFireParser extends CommandParser { SetFireParser() { super("SetFire", 0); } public void parse(String[] tokens, int i, CommandMessage message) { message.setFire(); } } *************************************************************************************** SetFromParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetFromParser extends CommandParser { SetFromParser() { super("From", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setFrom(tokens[i]); } } *************************************************************************************** SetIntendedRangeParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetIntendedRangeParser extends CommandParser { SetIntendedRangeParser() { super("SetIntendedRange", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setIntendedRange(tokens[i]); } } *************************************************************************************** SetNationalityParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.afv.Nationality; import acsl.dTank.commandMessage.CommandMessage; public class SetNationalityParser extends CommandParser { SetNationalityParser() { super("SetNationality", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setNationality(Nationality.lookup(tokens[i])); } } *************************************************************************************** SetThrottleParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetThrottleParser extends CommandParser { SetThrottleParser() { super("SetThrottle", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setThrottle(tokens[i]); } } *************************************************************************************** SetToParser.java *************************************************************************************** package acsl.dTank.commandMessage.parser; import acsl.dTank.commandMessage.CommandMessage; public class SetToParser extends CommandParser { SetToParser() { super("To", 1); } public void parse(String[] tokens, int i, CommandMessage message) { message.setTo(tokens[i]); } } *************************************************************************************** CommanderCommunicator.java *************************************************************************************** /** * This is the base class for the communicator which knows how to talk * to the server. */ package acsl.dTank.communicator; import acsl.dTank.Utility; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.informationMessage.InformationMessage; public abstract class CommanderCommunicator { protected String cmdrName, afvName = "Server"; public InformationMessage initialize(Nationality nationality, AFVType afvType, String cmdrName) { this.cmdrName = cmdrName; sendMessage("SetNationality:" + nationality.getName() + " SetAFVType:" + afvType.getName()); InformationMessage m = readMessage(); afvName = m.getFrom(); return m; } public void setThrottle(double throttle) { sendMessage(" SetThrottle:" + throttle); } public void setFire() { sendMessage(" SetFire:"); } public void setDesiredHeading(double heading) { heading = Utility.normalizeAngle(heading); sendMessage(" SetDesiredHeading:" + heading); } public void setDesiredTurretHeading(double heading) { heading = Utility.normalizeAngle(heading); sendMessage(" SetDesiredTurretHeading:" + heading); } protected void sendDebugMessage(String cmd) { throw new RuntimeException("Cannot send a debug message " + cmd); } protected void sendMessage(String cmd) { throw new RuntimeException("sendMessage() not implemented" + cmd); } public abstract void sendEncodedMsg(String cmd); public abstract String dequeueEncodedMsg(); public abstract InformationMessage readMessage(); public void sendRadioMessage(String radioMsg) { sendMessage(" SetRadioMessage:" + radioMsg); } public void setIntendedRange(double d) { sendMessage(" SetIntendedRange:" + d); } public void setResetBattle() { sendDebugMessage(" SetResetBattle:"); } public void setRealTimeMode(boolean z) { sendDebugMessage(" SetRealTimeMode:" + z); } public void setStep(int i) { sendDebugMessage(" SetStep:" + i); } public void setPause(boolean z) { sendDebugMessage(" SetPause:" + z); } } *************************************************************************************** CommanderDebuggerSocketCommunicator.java *************************************************************************************** package acsl.dTank.communicator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import acsl.dTank.Logger; import acsl.dTank.debugMessage.DebugMessage; import acsl.dTank.informationMessage.InformationMessage; public class CommanderDebuggerSocketCommunicator extends CommanderCommunicator { BufferedReader inStream; PrintStream outStream; public final static String LOOPBACK = "localhost"; // "127.0.0.1"; public final static int PORT = 3501; private static String serverName = LOOPBACK;// static because it cannot // connect to multiple servers. public CommanderDebuggerSocketCommunicator() { } CommanderDebuggerSocketCommunicator(String serverName) { CommanderDebuggerSocketCommunicator.serverName = serverName; } public void initialize(String cmdrName) { try { this.cmdrName = cmdrName; Socket s = new Socket(serverName, PORT); inStream = new BufferedReader(new InputStreamReader(s .getInputStream())); outStream = new PrintStream(s.getOutputStream()); } catch (IOException e) { System.out.println("Could not connect to the dTank debugger at: " + serverName + ":" + PORT); throw new RuntimeException("Initialization error: " + e); } } /** * Encode and send the message.
* The message will appear to be sent from cmdrName to afvName.
* That's exactly how a commander order should be. */ public void sendDebugMessage(String cmd) { String s = ""; Logger.log(s); outStream.println(s); } // public DebugMessage readDebugMessage() { // String input; // try { // input = inStream.readLine(); // if (input == null) // return null; // DebugMessage cm = DebugMessage.create(input); // return cm; // } catch (Exception e) { // throw new RuntimeException(e); // // return null; // } // } public static void setServerName(String serverName) { CommanderDebuggerSocketCommunicator.serverName = serverName; } @Override public String dequeueEncodedMsg() { throw new RuntimeException("NO"); } @Override public void sendEncodedMsg(String cmd) { throw new RuntimeException("NO"); } @Override public InformationMessage readMessage() { throw new RuntimeException("NO"); } } *************************************************************************************** CommanderDirectCommunicator.java *************************************************************************************** /** * This communicator skips over the socket because we know we're in the same process * as the server. (If we were really clever, we'd skip building the string too.) */ package acsl.dTank.communicator; import java.util.ArrayList; import java.util.List; import acsl.dTank.Logger; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.server.Server; public class CommanderDirectCommunicator extends CommanderCommunicator { ServerDirectCommunicator communicator; private List messageStrings = new ArrayList(); public InformationMessage initialize(Nationality nationality, AFVType afvType, String cmdrName) { communicator = Server.registerCommander(this); return super.initialize(nationality, afvType, cmdrName); } public void sendMessage(String msg) { String s = ""; communicator.enqueueMessage(s); Logger.log(s); } public synchronized InformationMessage readMessage() { while (messageStrings.size() == 0) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } return InformationMessage.create((String) messageStrings.remove(0)); } public synchronized void enqueueMessage(String msg) { messageStrings.add(msg); notifyAll(); } public synchronized String dequeueEncodedMsg() { while (messageStrings.size() == 0) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } return (String) messageStrings.remove(0); } public void sendEncodedMsg(String cmd) { enqueueMessage(cmd); } } *************************************************************************************** CommanderSocketCommunicator.java *************************************************************************************** /** * This is the normal communicator that runs over a socket. It works for remote processes * as well as local threads. */ package acsl.dTank.communicator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import acsl.dTank.Logger; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.informationMessage.InformationMessage; public class CommanderSocketCommunicator extends CommanderCommunicator { BufferedReader inStream; PrintStream outStream; public final static String LOOPBACK = "localhost"; // "127.0.0.1"; public final static int PORT = 3500; private static String serverName = LOOPBACK;// static because it cannot connect to multiple servers. public CommanderSocketCommunicator() { } CommanderSocketCommunicator(String serverName) { CommanderSocketCommunicator.serverName = serverName; } public InformationMessage initialize(Nationality nationality, AFVType afvType, String cmdrName) { try { Socket s = new Socket(serverName, PORT); inStream = new BufferedReader(new InputStreamReader(s.getInputStream())); outStream = new PrintStream(s.getOutputStream()); return super.initialize(nationality, afvType, cmdrName); } catch (IOException e) { System.out.println("Could not connect to the dTank server at: " + serverName + ":" + PORT); throw new RuntimeException("Initialization error: " + e); } } /** * Encode and send the message.
* The message will appear to be sent from cmdrName to afvName.
* That's exactly how a commander order should be. */ public void sendMessage(String cmd) { String s = ""; Logger.log(s); outStream.println(s); } /** * Sends an already encoded message to the output socket * @author matteo pedrotti * @param msg */ public void sendEncodedMsg (String msg) { outStream.println(msg); } public String dequeueEncodedMsg () { try { return inStream.readLine(); } catch (IOException e) { System.err.println ( "Exception reading from socket" ); e.printStackTrace(); return null; } } public InformationMessage readMessage() { String input; try { //input = inStream.readLine(); input=dequeueEncodedMsg(); if (input == null) return null; InformationMessage cm = InformationMessage.create(input); return cm; } catch (Exception e) { throw new RuntimeException(e); // return null; } } public static void setServerName(String serverName) { CommanderSocketCommunicator.serverName = serverName; } } *************************************************************************************** ServerCommunicator.java *************************************************************************************** /** * This is the base class for the server which communicates with the commanders. */ package acsl.dTank.communicator; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Battlefield; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.controller.AFVController; import acsl.dTank.controller.DeterministicAFVController; import acsl.dTank.controller.MagicAFVController; import acsl.dTank.controller.RealisticAFVController; import acsl.dTank.afv.Location; // public abstract class ServerCommunicator implements Runnable { public static final String DELIMITORS = "[< :>]"; protected AFVController controller; public void run() { CommandMessage m = readMessage(); try { startListenerLoop(m.getFrom(), m.getNationality().getName(), m.getAFVType().getName()); } catch (Exception e) { if (Parameters.isTesting()) { e.printStackTrace(); throw new RuntimeException("Socket closed while testing " + e); } // If not testing, allow commanders to close their sockets w/o error message. e.printStackTrace(); System.exit(1); //Na. Die! } } private void startListenerLoop(String cmdrName, String nationalityString, String afvType) { AFVController c; if (Parameters.isMagicMode()) c = MagicAFVController.create(cmdrName, nationalityString, afvType, this); else if (Parameters.isRealisticMode()) c = RealisticAFVController.create(cmdrName, nationalityString, afvType, this); else if (Parameters.isDeterministicMode()) c = DeterministicAFVController.create(cmdrName, nationalityString, afvType, this); else throw new RuntimeException("No such mode"); if (controller != null) { Nationality nationality = controller.getNationality(); AFV afv = controller.getAFV(); if (nationality == Nationality.BLUE) { if (Parameters.getNoBlueSpawnPoints() == 0) { afv.setLocation(Parameters.getInjectionPointX(Nationality.BLUE), Parameters .getInjectionPointY(Nationality.BLUE)); } else { Location l = Parameters.getNextBlueSpawn(); afv.setLocation(l.getX(), l.getY()); } } else if (nationality == Nationality.RED) { if (Parameters.getNoRedSpawnPoints() == 0) { afv.setLocation(Parameters.getInjectionPointX(Nationality.RED), Parameters .getInjectionPointY(Nationality.RED)); } else { Location l = Parameters.getNextRedSpawn(); afv.setLocation(l.getX(), l.getY()); } } else if (nationality == Nationality.WHITE) { if (Parameters.getNoWhiteSpawnPoints() == 0) { afv.setLocation(Parameters.getInjectionPointX(Nationality.WHITE), Parameters .getInjectionPointY(Nationality.WHITE)); } else { Location l = Parameters.getNextWhiteSpawn(); afv.setLocation(l.getX(), l.getY()); } } } // sendAcknowledgement(controller.getName(), controller.getCmdrName()); Battlefield.addTank(c.getAFV()); while (true) { CommandMessage m = readMessage(); controller.accept(m); } } private void sendAcknowledgement(String name, String cmdrName) { sendMessage("Dimensions:" + Battlefield.getPhysicalWidth() + ":" + Battlefield.getPhysicalHeight() + " FeatureSize:" + Battlefield.getFeatureSize()); } public abstract CommandMessage readMessage(); public abstract void sendMessage(String msg); public void setController(AFVController c) { controller = c; } } *************************************************************************************** ServerCommunicatorTest.java *************************************************************************************** package acsl.dTank.communicator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.Parameters; import acsl.dTank.battle.Battlefield; public class ServerCommunicatorTest extends TestCase { private String expectedInitialization = "\n"; BufferedReader inStream; PrintStream outStream; private String expectedACK = ""; public void setUp() throws IOException, InterruptedException { Parameters.setLoggingToTTY(true); Battlefield.create("testMaps/empty20x20.map", 1000.0, 1000.0); new Thread(new SCTListener()).start(); synchronized (SCTListener.class) { while (!SCTListener.ready) SCTListener.class.wait(); } Socket s = new Socket(CommanderSocketCommunicator.LOOPBACK, CommanderSocketCommunicator.PORT + 10); inStream = new BufferedReader(new InputStreamReader(s.getInputStream())); outStream = new PrintStream(s.getOutputStream()); } public void test1() throws IOException { outStream.print(expectedInitialization); String input = inStream.readLine(); assertEquals(expectedACK, input); } public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { System.out.println("==========ServerCommunicatorTest=========="); ServerCommunicatorTest test = new ServerCommunicatorTest(); test.setUp(); test.test1(); // test.test2(); } } class SCTListener implements Runnable { public static boolean ready = false; private static boolean alreadyRunning = false; public void run() { if (alreadyRunning) return; try { alreadyRunning = true; ServerSocket listenSocket = new ServerSocket( Parameters.getPort() + 10); synchronized (SCTListener.class) { ready = true; SCTListener.class.notify(); } Socket s = listenSocket.accept(); ServerSocketCommunicator.create(s); listenSocket.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } } *************************************************************************************** ServerDebuggerCommunicator.java *************************************************************************************** package acsl.dTank.communicator; import acsl.dTank.controller.AFVController; import acsl.dTank.debugMessage.DebugMessage; public abstract class ServerDebuggerCommunicator implements Runnable { public static final String DELIMITORS = "[< :>]"; protected AFVController controller; public abstract DebugMessage readDebugMessage(); public abstract void sendDebugMessage(String msg); } *************************************************************************************** ServerDebuggerSocketCommunicator.java *************************************************************************************** package acsl.dTank.communicator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.battle.Battlefield; import acsl.dTank.battle.Simulation; import acsl.dTank.debugMessage.DebugMessage; public class ServerDebuggerSocketCommunicator extends ServerDebuggerCommunicator { protected BufferedReader inStream; protected PrintStream outStream; private ServerDebuggerSocketCommunicator(Socket socket, BufferedReader inStream, PrintStream outStream) { this.inStream = inStream; this.outStream = outStream; } public static ServerDebuggerSocketCommunicator create(Socket socket) { BufferedReader inStream; try { inStream = new BufferedReader(new InputStreamReader(socket .getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); ServerDebuggerSocketCommunicator c = new ServerDebuggerSocketCommunicator( socket, inStream, outStream); new Thread(c, "ServerDebuggerSocketCommunicator").start(); return c; } catch (IOException e) { throw new RuntimeException(e); } } // Not used now. Never? public void sendDebugMessage(String msg) { String s = ""; outStream.println(s); Logger.log("Sending: " + s); } public DebugMessage readDebugMessage() { String input; try { input = inStream.readLine(); // System.out.println(input); if (input == null) throw new RuntimeException("Input stream closed for " + controller.getName()); DebugMessage cm = DebugMessage.create(input); return cm; } catch (IOException e) { throw new RuntimeException("Initialization error " + e); // return null; } } public void run() { try { startListenerLoop(); } catch (Exception e) { if (Parameters.isTesting()) { e.printStackTrace(); throw new RuntimeException("Socket closed while testing " + e); } e.printStackTrace(); System.exit(1); // Na. Die! } } private void startListenerLoop() { while (true) { DebugMessage m = readDebugMessage(); process(m); } } private void process(DebugMessage m) { if (m.isResettingBattle()) { Simulation.endBattle(); } if (m.isPausing()) { Simulation.setPause(m.getPause()); } if (m.isStepping()) { Simulation.step(m.getStep()); } if (m.isSettingRealTimeMode()) { Simulation.setRealTime(m.getRealTimeMode()); } } } *************************************************************************************** ServerDirectCommunicator.java *************************************************************************************** /** * This communicator skips over the socket because we know the commander is in the same process. * . (If we were really clever, we'd skip building the string too.) */ package acsl.dTank.communicator; import java.util.ArrayList; import java.util.List; import acsl.dTank.Logger; import acsl.dTank.battle.Battlefield; import acsl.dTank.commandMessage.CommandMessage; public class ServerDirectCommunicator extends ServerCommunicator { private CommanderDirectCommunicator commanderCommunicator; private List messageStrings = new ArrayList(); public ServerDirectCommunicator(CommanderDirectCommunicator commanderCommunicator) { this.commanderCommunicator = commanderCommunicator; } public static ServerDirectCommunicator create(CommanderDirectCommunicator communicator) { ServerDirectCommunicator c = new ServerDirectCommunicator(communicator); new Thread(c, "Communicator").start(); return c; } public void sendMessage(String msg) { String s = ""; commanderCommunicator.enqueueMessage(s); Logger.log("Sending: " + s); } public synchronized CommandMessage readMessage() { while (messageStrings.size() == 0) try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } return CommandMessage.create((String) messageStrings.remove(0)); } public synchronized void enqueueMessage(String msg) { messageStrings.add(msg); notifyAll(); } } *************************************************************************************** ServerSocketCommunicator.java *************************************************************************************** /** * This is the normal communicator that runs over a socket. It works for remote processes * as well as local threads. */ package acsl.dTank.communicator; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import acsl.dTank.Logger; import acsl.dTank.battle.Battlefield; import acsl.dTank.commandMessage.CommandMessage; public class ServerSocketCommunicator extends ServerCommunicator { protected BufferedReader inStream; protected PrintStream outStream; private ServerSocketCommunicator(Socket socket, BufferedReader inStream, PrintStream outStream) { this.inStream = inStream; this.outStream = outStream; } public static ServerSocketCommunicator create(Socket socket) { BufferedReader inStream; try { inStream = new BufferedReader(new InputStreamReader(socket .getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); ServerSocketCommunicator c = new ServerSocketCommunicator(socket, inStream, outStream); new Thread(c, "ServerSocket").start(); return c; } catch (IOException e) { throw new RuntimeException(e); } } public void sendMessage(String msg) { String s = ""; outStream.println(s); Logger.log("Sending: " + s); } public CommandMessage readMessage() { String input; try { input = inStream.readLine(); if (input == null) throw new RuntimeException("Input stream closed for "+ controller.getName()); CommandMessage cm = CommandMessage.create(input); return cm; } catch (IOException e) { throw new RuntimeException("Initialization error " + e); // return null; } } } *************************************************************************************** AFVController.java *************************************************************************************** /** * This is the base class for AFVcontrollers (which receive messages from the * communicators and then tell the AFV what to do). */ package acsl.dTank.controller; import acsl.dTank.Logger; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Nationality; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.communicator.ServerCommunicator; public abstract class AFVController { private static int counter = 0; private Nationality nationality; AFV afv; private String cmdrName; private ServerCommunicator communicator; public AFVController(String cmdrName, Nationality nationality, ServerCommunicator communicator) { this.nationality = nationality; this.cmdrName = cmdrName;// +counter; counter++; this.communicator = communicator; } public Nationality getNationality() { return nationality; } public String getCmdrName() { return cmdrName; } public void setAFV(AFV tank0) { afv = tank0; } public void accept(CommandMessage m) { if (m.isSettingThrottle()) afv.setThrottle(m.getThrottle()); if (m.isSettingDesiredHeading()) afv.setDesiredHeading(m.getDesiredHeading()); if (m.isSettingDesiredTurretHeading()) afv.setDesiredTurretHeading(m.getDesiredTurretHeading()); if (m.isSettingDesiredGunElevation()) afv.setDesiredGunElevation(m.getDesiredGunElevation()); if (m.isSettingIntendedRange()) afv.setIntendedRange(m.getIntendedRange()); if (m.isSettingRadioMessage()) sendRadioMessage(m); } private void sendRadioMessage(CommandMessage msg) { // synchronized (Battlefield.class) { // for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { // AFVMover m = (AFVMover) Battlefield.getAFVMover(i); // AFV afv = m.getAFV(); // if (afv.getNationality() != nationality) // continue; // afv.sendRadioMessage(msg.getRadioMessage()); // } // } } public void sendMessage(String msg) { //System.out.println(" message " + msg); if (Parameters.isTesting() && communicator == null) { Logger.log("Would have sent: " + msg); return; } communicator.sendMessage(msg); } public AFV getAFV() { return afv; } public void sendRadioMessage(String radioMessage) { sendMessage(" ReceiveRadioMessage:" + radioMessage); } public String getName() { return afv.getName(); } } *************************************************************************************** DeterministicAFVController.java *************************************************************************************** package acsl.dTank.controller; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Nationality; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.communicator.ServerCommunicator; public class DeterministicAFVController extends AFVController { public DeterministicAFVController(String name, Nationality nationality, ServerCommunicator serverCommunicator) { super(name, nationality, serverCommunicator); } public static DeterministicAFVController create(String cmdrName, String nationality, String afvType, ServerCommunicator communicator) { DeterministicAFVController c = new DeterministicAFVController(cmdrName, Nationality.lookup(nationality), communicator); AFV afv = AFV.create(afvType, c); c.setAFV(afv); communicator.setController(c); return c; } public void accept(CommandMessage m) { super.accept(m); if (m.isSettingThrottle()) afv.setSpeedMPS(afv.getDesiredSpeedMPS()); if (m.isSettingDesiredHeading()) afv.setHeading(m.getDesiredHeading()); if (m.isSettingDesiredTurretHeading()) afv.setTurretHeading(m.getDesiredTurretHeading()); if (m.isSettingDesiredGunElevation()) afv.setGunElevation(m.getDesiredGunElevation()); if (m.isSettingFire()) { double h = afv.getTurretHeading(); afv.fire(h); } } } *************************************************************************************** DullAFVController.java *************************************************************************************** /** * Just used for tests */ package acsl.dTank.controller; import acsl.dTank.afv.Nationality; public class DullAFVController extends AFVController { public DullAFVController(Nationality nationality) { super("Cmdr", nationality, null); } public static void main(String[] args) { // TODO Auto-generated method stub } public static AFVController create(Nationality nationality) { AFVController c = new DullAFVController(nationality); return c; } public void run() { double h = 0.0; try { while (true) { Thread.sleep(5000); afv.setHeading(h); afv.setThrottle(1.0); h += 50.0; afv.fire(afv.getTurretHeading()); afv.setTurretHeading(h + 50); } } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** DullAFVControllerTest.java *************************************************************************************** package acsl.dTank.controller; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; public class DullAFVControllerTest extends TestCase { private AFV tank0; AFVController c0, c1; public void setUp() { Parameters.setTesting(true); Initializer.initializeAll(); Battlefield.create("testMaps/Test20x20.map", 1000.0, 1000.0); c0 = DullAFVController.create(Nationality.BLUE); tank0 = Tank.create(AFVType.SHERMAN, c0); tank0.setLocation(949.0, 500.0); c0.setAFV(tank0); Battlefield.addTank(tank0); assertEquals("", 0.0, tank0.getSpeed(), 0.01); } public void test1() { Battlefield.update(1.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.01); assertTrue(tank0.atLocation(949.0, 500.0)); tank0.setSpeedKPH(-20.0); tank0.setThrottle(-1.0); Battlefield.update(1.0); assertEquals(-20.0, tank0.getSpeedKPH(), 0.01); assertEquals(949.0, tank0.getX(), 0.1); } public static void main(String[] args) { System.out.println("==========DullControllerTest=========="); DullAFVControllerTest test = new DullAFVControllerTest(); test.setUp(); test.test1(); // test.test2(); } } *************************************************************************************** DullerAFVController.java *************************************************************************************** package acsl.dTank.controller; import acsl.dTank.afv.Nationality; public class DullerAFVController extends AFVController { public DullerAFVController(Nationality nationality) { super("Cmdr", nationality, null); } public static AFVController create(Nationality nationality) { AFVController c = new DullerAFVController(nationality); return c; } public void run() { } } *************************************************************************************** DumbAFVController.java *************************************************************************************** /** * Just used for tests */ package acsl.dTank.controller; import acsl.dTank.afv.Nationality; public class DumbAFVController extends AFVController { public DumbAFVController(Nationality nationality) { super("Cmdr", nationality, null); } public static void main(String[] args) { // TODO Auto-generated method stub } public static AFVController create(Nationality nationality) { AFVController c = new DumbAFVController(nationality); return c; } public void run() { double h = 0.0; try { while (true) { Thread.sleep(5000); afv.setHeading(h); afv.setThrottle(1.0); h += 50.0; afv.fire(afv.getTurretHeading()); afv.setTurretHeading(h + 50); } } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** DumbAFVControllerTest.java *************************************************************************************** package acsl.dTank.controller; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; public class DumbAFVControllerTest extends TestCase { private AFV tank0; AFVController c0, c1; public void setUp() { Parameters.setTesting(true); Initializer.initializeAll(); Battlefield.create("testMaps/Test20x20.map", 1000.0, 1000.0); c0 = DumbAFVController.create(Nationality.BLUE); tank0 = Tank.create(AFVType.SHERMAN, c0); tank0.setLocation(949.0, 500.0); c0.setAFV(tank0); Battlefield.addTank(tank0); assertEquals("", 0.0, tank0.getSpeed(), 0.01); } public void test1() { Battlefield.update(1.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.01); assertTrue(tank0.atLocation(949.0, 500.0)); tank0.setSpeedKPH(-20.0); tank0.setThrottle(-1.0); Battlefield.update(1.0); assertEquals(-20.0, tank0.getSpeedKPH(), 0.01); assertEquals(949.0, tank0.getX(), 0.1); } public static void main(String[] args) { System.out.println("==========DumbControllerTest=========="); DumbAFVControllerTest test = new DumbAFVControllerTest(); test.setUp(); test.test1(); // test.test2(); } } *************************************************************************************** DumberAFVController.java *************************************************************************************** package acsl.dTank.controller; import acsl.dTank.afv.Nationality; public class DumberAFVController extends AFVController { public DumberAFVController(Nationality nationality) { super("Cmdr", nationality, null); } public static AFVController create(Nationality nationality) { AFVController c = new DumberAFVController(nationality); return c; } public void run() { } } *************************************************************************************** ExactControllerTest.java *************************************************************************************** package acsl.dTank.controller; import java.io.IOException; import java.net.UnknownHostException; import junit.framework.TestCase; import acsl.dTank.afv.AFV; import acsl.dTank.battle.Battlefield; import acsl.dTank.battle.Simulation; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.communicator.ServerCommunicator; import acsl.dTank.communicator.ServerDirectCommunicator; public class ExactControllerTest extends TestCase { public static String input1 = ""; public static String input2 = ""; AFVController controller; ServerCommunicator communicator; AFV afv; public void setUp() throws IOException, InterruptedException { Battlefield.create("testMaps/empty20x20.map", 1000.0, 1000.0); communicator = ServerDirectCommunicator.create(null); controller = MagicAFVController.create("Cmdr33", "Blue", "Sherman", communicator); afv = controller.getAFV(); } public void test1() throws IOException { CommandMessage m = CommandMessage.create(input1); int ammo = afv.getAmmunitionRemaining(); for (int i = 0; i < 100; i++) Simulation.incrementTime(); // Default of 0.4 secs/increment controller.accept(m); assertEquals(225.2, afv.getDesiredHeading(), 0.1); assertEquals(0.4, afv.getThrottle(), 0.1); assertEquals(ammo - 1, afv.getAmmunitionRemaining()); // 10s for reload // assertEquals(10.4, afv.getDesiredSpeed(), 0.1); } public void test2() throws IOException { CommandMessage m = CommandMessage.create(input2); controller.accept(m); assertEquals(0.4, afv.getDesiredGunElevation(), 0.1); assertEquals(25.2, afv.getDesiredTurretHeading(), 0.1); // assertEquals(10.4, afv.getDesiredSpeed(), 0.1); } public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { ExactControllerTest test = new ExactControllerTest(); test.setUp(); test.test1(); } } *************************************************************************************** MagicAFVController.java *************************************************************************************** /** * This controller is for "video game" style behavior. For example, it sets speed * immediately, instead of progressively increasing it. */ package acsl.dTank.controller; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Nationality; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.communicator.ServerCommunicator; public class MagicAFVController extends AFVController { public MagicAFVController(String name, Nationality nationality, ServerCommunicator communicator) { super(name, nationality, communicator); } public static MagicAFVController create(String cmdrName, String nationality, String afvType, ServerCommunicator communicator) { MagicAFVController c = new MagicAFVController(cmdrName, Nationality.lookup(nationality), communicator); AFV afv = AFV.create(afvType, c); c.setAFV(afv); communicator.setController(c); return c; } public void accept(CommandMessage m) { super.accept(m); if (m.isSettingThrottle()) afv.setSpeedMPS(afv.getDesiredSpeedMPS()); if (m.isSettingDesiredHeading()) afv.setHeading(m.getDesiredHeading()); // Do instaniously if (m.isSettingDesiredTurretHeading()) afv.setTurretHeading(m.getDesiredTurretHeading()); if (m.isSettingDesiredGunElevation()) afv.setGunElevation(m.getDesiredGunElevation()); if (m.isSettingFire()) { afv.fire(afv.getTurretHeading()); } } } *************************************************************************************** RealisticAFVController.java *************************************************************************************** /** * This controller is for realistic behavior. */ package acsl.dTank.controller; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Battlefield; import acsl.dTank.commandMessage.CommandMessage; import acsl.dTank.communicator.ServerCommunicator; public class RealisticAFVController extends AFVController { public RealisticAFVController(String name, Nationality nationality, ServerCommunicator serverCommunicator) { super(name, nationality, serverCommunicator); } public static RealisticAFVController create(String cmdrName, String nationality, String afvType, ServerCommunicator communicator) { RealisticAFVController c = new RealisticAFVController(cmdrName, Nationality.lookup(nationality), communicator); AFV afv = AFV.create(afvType, c); c.setAFV(afv); communicator.setController(c); return c; } public void accept(CommandMessage m) { super.accept(m); if (m.isSettingThrottle()) afv.setSpeedMPS(afv.getDesiredSpeedMPS()); if (m.isSettingDesiredHeading()) afv.setHeading(m.getDesiredHeading()); if (m.isSettingDesiredTurretHeading()) afv.setTurretHeading(m.getDesiredTurretHeading()); if (m.isSettingDesiredGunElevation()) afv.setGunElevation(m.getDesiredGunElevation()); if (m.isSettingFire()) { double h = afv.getTurretHeading(); // Firing when moving (or recently moving) is inaccurate if (afv.getSpeed() == 0.0 && (afv.stationarySince() + 5000) < Battlefield.getGameTime()) { h += (Math.random() * 1.0);// Stationary long enough to be more accurate } else { if (afv.isStabilized()) h += (Math.random() * 2.0);// Stabilized guns (Sherman only) are better else h += (Math.random() * 4.0);// Non-stabilized guns are less accurate when moving. } afv.fire(h); } } } *************************************************************************************** DebugMessage.java *************************************************************************************** package acsl.dTank.debugMessage; import acsl.dTank.debugMessage.parser.DebugParser; import acsl.dTank.informationMessage.InformationMessage; public class DebugMessage { private static final String DELIMITORS = "[<: >]"; protected String input; private boolean resetBattle; private String from; private int nSteps; private boolean pause; private boolean isStepping; private boolean isSettingPause; private boolean isResettingBattle; private boolean isSettingRealTimeMode; private boolean realTimeMode; // public static DebugMessage create(String input) { System.out.println(input); DebugMessage im = new DebugMessage(); im.input = input; String[] tokens = InformationMessage .dropBlanks(input.split(DELIMITORS)); int len = tokens.length; if (len < 2) throw new RuntimeException("Unknown command " + input); for (int i = 0; i < len;) { // Skip From & To i += im.parse(tokens, i); } return im; } private int parse(String[] tokens, int i) { String typeString = tokens[i]; DebugParser it = DebugParser.lookup(typeString); if (it == null) throw new RuntimeException("Unknown command " + typeString); it.parse(tokens, i + 1, this); return it.getNArgs() + 1; // loc of next cmd } public void setResetBattle() { resetBattle = true; isResettingBattle = true; } public boolean isResettingBattle() { return isResettingBattle; } public boolean getResetBattle() { return resetBattle; } public void setPause(boolean z) { pause = z; isSettingPause = true; } public boolean getPause() { return pause; } public boolean isPausing() { return isSettingPause; } public void setStep(int i) { nSteps = i; isStepping = true; } public int getStep() { return nSteps; } public boolean isStepping() { return isStepping; } public void setFrom(String from) { this.from = from; } public String getFrom() { return from; } public boolean isSettingRealTimeMode() { return isSettingRealTimeMode; } public boolean getRealTimeMode() { return realTimeMode; } public void setRealTimeMode(boolean z) { realTimeMode = z; isSettingRealTimeMode = true; } } *************************************************************************************** DebugParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import java.util.HashMap; import acsl.dTank.debugMessage.DebugMessage; public abstract class DebugParser { private String name; private int nArgs; private static HashMap informationTypes = new HashMap(); public DebugParser(String name, int nArgs) { this.name = name; this.nArgs = nArgs; } public static void initialize() { initialize(new SetResetBattleParser()); initialize(new SetFromParser()); initialize(new SetStepParser()); initialize(new SetPauseParser()); initialize(new SetRealTimeModeParser()); } public static void initialize(DebugParser p) { informationTypes.put(p.getName(), p); } public int getNArgs() { return nArgs; } public String getName() { return name; } public static DebugParser lookup(String typeString) { return (DebugParser) informationTypes.get(typeString); } public abstract void parse(String[] tokens, int i, DebugMessage controlMessage); } *************************************************************************************** SetFromParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import acsl.dTank.debugMessage.DebugMessage; public class SetFromParser extends DebugParser { SetFromParser() { super("From", 1); } public void parse(String[] tokens, int i, DebugMessage message) { message.setFrom(tokens[i]); } } *************************************************************************************** SetPauseParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import acsl.dTank.debugMessage.DebugMessage; public class SetPauseParser extends DebugParser { SetPauseParser() { super("SetPause", 1); } public void parse(String[] tokens, int i, DebugMessage message) { message.setPause(Boolean.parseBoolean(tokens[i])); } } *************************************************************************************** SetRealTimeModeParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import acsl.dTank.debugMessage.DebugMessage; public class SetRealTimeModeParser extends DebugParser { SetRealTimeModeParser() { super("SetRealTimeMode", 1); } public void parse(String[] tokens, int i, DebugMessage message) { message.setRealTimeMode(Boolean.parseBoolean(tokens[i])); } } *************************************************************************************** SetResetBattleParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import acsl.dTank.debugMessage.DebugMessage; public class SetResetBattleParser extends DebugParser { SetResetBattleParser() { super("SetResetBattle", 0); } @Override public void parse(String[] tokens, int i, DebugMessage message) { message.setResetBattle(); } } *************************************************************************************** SetStepParser.java *************************************************************************************** package acsl.dTank.debugMessage.parser; import acsl.dTank.debugMessage.DebugMessage; public class SetStepParser extends DebugParser { SetStepParser() { super("SetStep", 1); } public void parse(String[] tokens, int i, DebugMessage message) { message.setStep(Integer.parseInt(tokens[i])); } } *************************************************************************************** DetectedAFV.java *************************************************************************************** /* * This is the information about the AFVs that have been detected and sent * to the commander in an information message. It also takes care of the display * on the commander's display (if any), just like the Mover does in the Server. */ package acsl.dTank.informationMessage; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.ui.CommanderControlPanel; public class DetectedAFV { private Nationality nationality; private double y; private double x; private double heading, turretHeading; private boolean destroyed; private String bodyImageFilename = "tank.gif", turretImageFilename = "turret.gif"; private AFVType afvType; public DetectedAFV(Nationality nationality, boolean smoking, double x, double y, double heading, double turretHeading, AFVType ty) { this.nationality = nationality; this.destroyed = smoking; this.heading = heading; this.turretHeading = turretHeading; this.x = x; this.y = y; this.afvType = ty; } public double getY() { return y; } public double getX() { return x; } public void paint(Graphics2D g, CommanderControlPanel panel, double fs) { Image bodyImage = panel.getBodyImage(this); Image turretImage = panel.getTurretImage(this); double headingR = Math.toRadians(heading); double turretHeadingR = Math.toRadians(turretHeading); int fs4 = panel.convertPos(fs / 2); int xPixels = panel.convertPos(x); int yPixels = panel.convertPos(y); AffineTransform xform = new AffineTransform(); { xform.setToIdentity(); xform.translate(xPixels, yPixels); xform.rotate(headingR, fs4, fs4); boolean z = g.drawImage(bodyImage, xform, null); while (!z) { //I don't understand why Swing would require this. -Bil z = g.drawImage(bodyImage, xform, null); } } { xform.setToIdentity(); xform.translate(xPixels, yPixels); xform.rotate(turretHeadingR, fs4, fs4); g.drawImage(turretImage, xform, null); } { double halfArc = Math.toRadians(getVisibilityArc() / 2.0); int x2Pixels = (int) (xPixels + 200 * Math.sin(turretHeadingR + halfArc)); int y2Pixels = (int) (yPixels - 200 * Math.cos(turretHeadingR + halfArc)); int x3Pixels = (int) (xPixels + 200 * Math.sin(turretHeadingR - halfArc)); int y3Pixels = (int) (yPixels - 200 * Math.cos(turretHeadingR - halfArc)); g.drawLine(xPixels + fs4, yPixels + fs4, x2Pixels + fs4, y2Pixels + fs4); g.drawLine(xPixels + fs4, yPixels + fs4, x3Pixels + fs4, y3Pixels + fs4); } } private double getVisibilityArc() { return 45.0; } public Nationality getNationality() { return nationality; } public boolean isDestroyed() { return destroyed; } public void unpaint(Graphics2D g, CommanderControlPanel panel, double featureSize) { int px = panel.convertPos(x); int py = panel.convertPos(y); int fs = panel.convertPos(featureSize); g.drawImage(panel.getBackgroundImage(), px, py, px + fs, py + fs, px, py, px + fs, py + fs, null); } public AFVType getAFVType() { return AFVType.SHERMAN; } public boolean closeTo(DetectedAFV afv, int elapsedTime) { if (nationality != afv.getNationality()) return false; if (Math.abs(afv.getX() - getX()) > 10.0 * elapsedTime) return false; if (Math.abs(afv.getY() - getY()) > 10.0 * elapsedTime) return false; return true; } public String getBodyImageFilename() { return afvType.getBodyImageFilename(); } public String getTurretImageFilename() { return turretImageFilename; } } *************************************************************************************** InformationMessage.java *************************************************************************************** package acsl.dTank.informationMessage; import java.util.ArrayList; import java.util.List; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.informationMessage.parser.InformationParser; import acsl.dTank.informationMessage.parser.ProjectileParser; import acsl.dTank.map.TerrainType; public class InformationMessage { private static final String DELIMITORS = "[<: >]"; private double throttle, heading, turretHeading, gunElevation; private boolean settingThrottle = false, settingHeading = false, settingTurretHeading = false; private boolean settingLocation = false; private double x, y; // location // private double flashX, flashY; private List observableObjects = new ArrayList(), afvs = new ArrayList(), projectiles = new ArrayList(); private boolean settingSpeed = false; private double speed; private boolean settingGunElevation = false; private int ammunitionRemaining = 0; private boolean settingAmmunitionRemaining = false; private boolean radioGood = false; private boolean healthy = false; private boolean settingOperationalStatus = false; // private boolean settingFlash = false; private String input; double width, height, featureSize; String from; private String to; private int time; // ms from start of combat private boolean settingCollision; private String radioMessage; private boolean settingRadioMessage; private boolean isLoaded; private boolean isSettingLoaded; private double armorDamage; private boolean destroyed; private double fuelRemaining; private boolean isSettingFuelRemaining; private boolean exit; private boolean isProjectileScan; private boolean isTreadGood; private TerrainType collidedWithTerrainType; public InformationMessage() { } public boolean isSettingThrottle() { return settingThrottle; } public double getThrottle() { return throttle; } public double getHeading() { return heading; } public double getTurretHeading() { return turretHeading; } public static InformationMessage create(String input) { InformationMessage im = new InformationMessage(); im.input = input; String[] tokens = dropBlanks(input.split(DELIMITORS)); int len = tokens.length; if (len < 4) throw new RuntimeException("Unknown command " + input); for (int i = 0; i < len;) { i += im.parse(tokens, i); } return im; } public static String[] dropBlanks(String[] strings) { int n = 0; for (int i = 0, size = strings.length; i < size; i++) { if (strings[i].equals("")) n++; } if (n == 0) return strings; String[] ss = new String[strings.length - n]; for (int i = 0, size = strings.length, j = 0; i < size; i++) { if (!strings[i].equals("")) { ss[j] = strings[i]; j++; } } return ss; } private int parse(String[] tokens, int i) { String typeString = tokens[i]; InformationParser it = InformationParser.lookup(typeString); if (it == null) throw new RuntimeException("Unknown command " + typeString); it.parse(tokens, i + 1, this); return it.getNArgs() + 1; // loc of next cmd } public void setThrottle(String string) { throttle = Double.parseDouble(string); settingThrottle = true; } public boolean isSettingLocation() { return settingLocation; } public double getX() { return x; } public double getY() { return y; } public void setY(String string) { y = Double.parseDouble(string); settingLocation = true; } public void setX(String string) { x = Double.parseDouble(string); } public int getNObservableObjects() { return observableObjects.size(); } public ObservableObject getObservableObject(int i) { return (ObservableObject) observableObjects.get(i); } public void addObservableObject(ObservableObject oo) { observableObjects.add(oo); } public boolean isSettingSpeed() { return settingSpeed; } public double getSpeedKPH() { return speed; } public void setSpeedKPH(double speed) { this.speed = speed; settingSpeed = true; } public void setHeading(double heading) { this.heading = heading; settingHeading = true; } public boolean isSettingElevation() { return settingGunElevation; } public double getElevation() { return gunElevation; } public void setGunElevation(double elevation) { this.gunElevation = elevation; this.settingGunElevation = true; } public void setAmmunitionRemaining(int ammo) { ammunitionRemaining = ammo; settingAmmunitionRemaining = true; } public boolean isSettingAmmunitionRemaining() { return settingAmmunitionRemaining; } public int getAmmunitionRemaining() { return ammunitionRemaining; } public boolean isSettingOperationalStatus() { return settingOperationalStatus; } public boolean isHealthy() { return healthy; } public boolean isRadioGood() { return radioGood; } public boolean isLoaded() { return isLoaded; } public void setOperationalStatus(String operational, String healthy, String armorDamage, String radioGood, String treadGood) { if (operational.equals("false")) this.destroyed = true; if (healthy.equals("true")) this.healthy = true; if (radioGood.equals("true")) this.radioGood = true; if (treadGood.equals("true")) this.isTreadGood = true; this.armorDamage = Double.parseDouble(armorDamage); settingOperationalStatus = true; } public int getNAFVs() { return afvs.size(); } public DetectedAFV getAFV(int i) { return (DetectedAFV) afvs.get(i); } // public boolean isSettingFlash() { // return settingFlash; // } public boolean isSettingTurretHeading() { return settingTurretHeading; } public void addAFV(DetectedAFV detectedAFV) { afvs.add(detectedAFV); } // public void setFlash(double x, double y) { // //flashX = x; // //flashY = y; // settingFlash = true; // } public void setTurretHeading(double h) { this.turretHeading = h; this.settingTurretHeading = true; } public static String createAFVInformationMessageString(AFV afv) { StringBuffer sb = new StringBuffer(""); sb.append(" Location:"); sb.append(Utility.shorten(afv.getX())); sb.append(":"); sb.append(Utility.shorten(afv.getY())); sb.append(" Heading:"); sb.append(Utility.shorten(afv.getHeading())); sb.append(" Speed:"); double speed = (afv.getHeading() == afv.getHeading()) ? afv.getSpeedKPH() : -afv.getSpeedKPH(); sb.append(Utility.shorten(speed)); sb.append(" GunElevation:"); sb.append(Utility.shorten(afv.getGunElevation())); sb.append(" AmmunitionRemaining:"); sb.append(afv.getAmmunitionRemaining()); sb.append(" OperationalStatus:"); sb.append(afv.getOperational()); sb.append(":"); sb.append(afv.isCrewHealthy()); sb.append(":"); sb.append(Utility.shorten(afv.getArmorDamage())); sb.append(":"); sb.append(afv.isRadioOperational()); sb.append(":"); sb.append(afv.isTreadOperational()); sb.append(" Throttle:"); sb.append(Utility.shorten(afv.getThrottle())); sb.append(" TurretHeading:"); sb.append(Utility.shorten(afv.getTurretHeading())); sb.append(" Loaded:"); sb.append(afv.isLoaded()); sb.append(" FuelRemaining:"); sb.append(Utility.shorten(afv.getFuelRemaining())); return sb.toString(); } public boolean isSettingHeading() { return settingHeading; } public boolean isSettingGunElevation() { return settingGunElevation; } public double getGunElevation() { return gunElevation; } public String getFrom() { return from; } public double getWidth() { return width; } public double getHeight() { return height; } public double getFeatureSize() { return featureSize; } public void setDimensions(double w, double h) { width = w; height = h; } public void setFeatureSize(double featureSize) { this.featureSize = featureSize; } public void setTo(String string) { to = string; } public void setFrom(String string) { from = string; } public void setTime(int time) { this.time = time; } public int getTime() { return time; } public boolean isSettingCollision() { return settingCollision; } public void setCollision(TerrainType type) { settingCollision = true; collidedWithTerrainType = type; } public TerrainType getCollisionWithTerrainType( ) { return collidedWithTerrainType; } public List getAFVs() { return afvs; } public void addProjectile(ProjectileParser pi) { projectiles.add(pi); } public List getProjectiles() { return projectiles; } public void setRadioMessage(String msg) { radioMessage = msg; settingRadioMessage = true; } public boolean isSettingRadioMessage() { return settingRadioMessage; } public String getRadioMessage() { return radioMessage; } public void setLoaded(String isLoaded) { this.isLoaded = (isLoaded.equals("true")); isSettingLoaded = true; } public boolean getLoaded() { return isLoaded; } public boolean isSettingLoaded() { return isSettingLoaded; } public double getArmorDamage() { return armorDamage; } public boolean isDestroyed() { return destroyed; } public boolean isTreadGood() { return isTreadGood; } public void setFuelRemaining(double fuelRemaining) { this.fuelRemaining = fuelRemaining; isSettingFuelRemaining = true; } public double getFuelRemaining() { return fuelRemaining; } public boolean isSettingFuelRemaining() { return isSettingFuelRemaining; } public void setExit() { exit = true; } public boolean isExit() { return exit; } public boolean isProjectileScan() { return isProjectileScan; } public void setProjectileScan() { isProjectileScan = true; } } *************************************************************************************** InformationMessageCreateTest.java *************************************************************************************** package acsl.dTank.informationMessage; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Location; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.controller.AFVController; import acsl.dTank.controller.MagicAFVController; public class InformationMessageCreateTest extends TestCase { public static String info = " Location:949.0:500.0 Heading:45.1 Speed:-12.0 GunElevation:1.0 " + "AmmunitionRemaining:90 OperationalStatus:true:true:0.0:true " + "Throttle:0.5 TurretHeading:2.0 Loaded:false FuelRemaining:662.0"; public void setUp() { Parameters.setTesting(true); Initializer.initializeAll(); Location.initialize(1000.0, 1000.0, 50.0); } public void test1() { AFV afv = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr2", Nationality.BLUE, null)); afv.setLocation(949, 500); afv.setSpeedKPH(-12.0); afv.setThrottle(0.5); afv.setTurretHeading(2.01); afv.setHeading(45.1); afv.setGunElevation(1.0); String msg = InformationMessage.createAFVInformationMessageString(afv); assertEquals(info, msg); } public static void main(String[] args) { System.out.println("==========InformationMessageCreateTest=========="); InformationMessageCreateTest test = new InformationMessageCreateTest(); test.setUp(); test.test1(); } } *************************************************************************************** InformationMessageTest.java *************************************************************************************** package acsl.dTank.informationMessage; import java.util.List; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.afv.Velocity; import acsl.dTank.battle.Battlefield; import acsl.dTank.commander.AFVModel; import acsl.dTank.informationMessage.parser.ProjectileParser; import acsl.dTank.map.TerrainType; public class InformationMessageTest extends TestCase { public static String input0 = ""; public static String input1 = ""; public static String input2 = ""; public static String input3 = ""; public static String input4 = ""; public static String input5 = ""; public static String input6 = ""; public static String input7 = ""; public static String input8 = ""; public static String input9 = ""; public static String inputA = ""; public static String inputB = ""; public static String inputC = ""; public static String inputD = ""; public static String inputE = ""; public static String inputF = ""; public static String inputG = ""; public static String inputH = ""; public static double fs; public void setUp() { Battlefield.create("testMaps/test20x20.map", 1000.0, 1000.0); fs = Battlefield.getFeatureSize(); } public void test1() { InformationMessage im = InformationMessage.create(input0); assertEquals(true, im.isSettingThrottle()); assertEquals(0.5, im.getThrottle(), 0.01); InformationMessage im1 = InformationMessage.create(input1); assertEquals(false, im1.isSettingThrottle()); InformationMessage im2 = InformationMessage.create(input2); assertEquals(false, im2.isSettingThrottle()); assertTrue(im2.isSettingLocation()); assertEquals(235.678, im2.getX(), 0.01); assertEquals(998.0, im2.getY(), 0.01); InformationMessage im3 = InformationMessage.create(input3); assertEquals(1, im3.getNObservableObjects()); ObservableObject oo1 = im3.getObservableObject(0); ObservableObject oo0 = ObservableTerrain.create(TerrainType.STONE, 200.0, 950.0, fs); assertEquals(oo0.getX(), oo1.getX(), 0.01); assertEquals(TerrainType.STONE, oo1.getType()); } public void test2() { InformationMessage im3 = InformationMessage.create(input4); assertEquals(1, im3.getNObservableObjects()); ObservableObject oo1 = im3.getObservableObject(0); ObservableObject oo0 = ObservableTerrain.create(TerrainType.LOW_HILL, 0.0, 950.0, fs); assertEquals(oo0.getX(), oo1.getX(), 0.01); } public void test5() { InformationMessage im = InformationMessage.create(input5); assertEquals(2, im.getNObservableObjects()); ObservableObject oo0 = im.getObservableObject(0); ObservableObject oo1 = im.getObservableObject(1); assertEquals(200.0, oo0.getX(), 0.01); assertEquals(TerrainType.HIGH_HILL, oo0.getType()); assertEquals(200.0, oo1.getX(), 0.01); assertEquals(TerrainType.STONE, oo1.getType()); } public void test6() { InformationMessage im = InformationMessage.create(input6); assertEquals(1, im.getNObservableObjects()); ObservableObject oo0 = im.getObservableObject(0); assertEquals(200.0, oo0.getX(), 0.01); assertEquals(TerrainType.WOODS, oo0.getType()); } public void test7() { InformationMessage im = InformationMessage.create(input7); assertEquals(0, im.getNObservableObjects()); assertTrue(im.isSettingSpeed()); assertEquals(im.getSpeedKPH(), 25.0, 0.01); assertTrue(im.isSettingTurretHeading()); } public void test8() { InformationMessage im = InformationMessage.create(input8); assertTrue(im.isSettingElevation()); assertEquals(10.23, im.getElevation(), 0.01); assertTrue(im.isSettingAmmunitionRemaining()); assertEquals(15, im.getAmmunitionRemaining()); } public void test9() { InformationMessage im = InformationMessage.create(input9); assertTrue(im.isSettingOperationalStatus()); assertTrue(im.isHealthy()); assertFalse(im.isDestroyed()); assertTrue(im.isRadioGood()); assertEquals(0.3, im.getArmorDamage(), 0.1); } public void testA() { InformationMessage im = InformationMessage.create(inputA); assertEquals(1, im.getNAFVs()); DetectedAFV ai = im.getAFV(0); assertEquals(123.4, ai.getX(), 0.01); assertEquals(555.6, ai.getY(), 0.01); // assertTrue(im.isSettingFlash()); } public void testC() { InformationMessage im = InformationMessage.create(inputC); assertEquals(0, im.getNAFVs()); assertTrue(im.isSettingCollision()); } public void testB() { InformationMessage im = InformationMessage.create(inputB); assertEquals(1000.0, im.getWidth(), 0.01); assertEquals(50.0, im.getFeatureSize(), 0.01); assertEquals(false, im.isProjectileScan()); } public void testD() { InformationMessage im = InformationMessage.create(inputD); assertEquals(true, im.isProjectileScan()); List ps = im.getProjectiles(); ProjectileParser p = (ProjectileParser) ps.get(0); assertEquals("InFlight", p.getState()); } public void testE() { InformationMessage im = InformationMessage.create(inputE); assertEquals(true, im.isProjectileScan()); List ps = im.getProjectiles(); ProjectileParser p = (ProjectileParser) ps.get(0); assertEquals("Explosion1", p.getState()); } public void testF() { InformationMessage im = InformationMessage.create(inputF); assertEquals(true, im.isProjectileScan()); List ps = im.getProjectiles(); ProjectileParser p = (ProjectileParser) ps.get(0); assertEquals("Explosion2", p.getState()); } public void testG() { InformationMessage im = InformationMessage.create(inputG); assertEquals(false, im.isProjectileScan()); List ps = im.getProjectiles(); ProjectileParser p = (ProjectileParser) ps.get(0); assertEquals("Explosion3", p.getState()); } public static void main(String[] args) { System.out.println("==========InformationMessageTest=========="); InformationMessageTest test = new InformationMessageTest(); test.setUp(); test.test1(); test.test2(); test.test5(); test.test6(); test.test7(); test.test8(); test.test9(); test.testA(); test.testB(); test.testC(); } } *************************************************************************************** ObservableAFV.java *************************************************************************************** /** * This is used to create the information message. The commander does not see this. */ package acsl.dTank.informationMessage; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; public class ObservableAFV extends ObservableObject { private AFV afv; public ObservableAFV(AFV afv) { this.afv = afv; type = ObservableType.AFV; location = new Location(afv.getX(), afv.getY()); } public String createMessageString() { StringBuffer sb = new StringBuffer(" AFV:"); sb.append(afv.getNationality().getName()); sb.append(":"); String isSmoking = afv.isDestroyed() ? "Smoking" : "OK"; sb.append(isSmoking); sb.append(":"); sb.append(Utility.shorten(getX())); sb.append(":"); sb.append(Utility.shorten(getY())); sb.append(":"); sb.append(Utility.shorten(getHeading()));// heading sb.append(":"); sb.append(Utility.shorten(getTurretHeading())); // turret heading sb.append(":"); sb.append(afv.getAFVType().getName()); // turret heading // System.out.println(sb); return sb.toString(); } public boolean isDestroyed() { return afv.isDestroyed(); } private double getHeading() { return afv.getHeading(); } private double getTurretHeading() { return afv.getTurretHeading(); } } *************************************************************************************** ObservableObject.java *************************************************************************************** /** * This is the base type for objects used for creating information messages. */ package acsl.dTank.informationMessage; import acsl.dTank.Utility; import acsl.dTank.afv.Location; public class ObservableObject { ObservableType type; Location location; public ObservableObject() { } public ObservableObject(ObservableType type, Location location) { this.type = type; this.location = location; } public boolean equals(Object o) { if (!(o instanceof ObservableObject)) return false; ObservableObject oo = (ObservableObject) o; if (oo.getType() != type) return false; if (oo.getX() != getX()) return false; if (oo.getY() != getY()) return false; return true; } public String createMessageString() { StringBuffer sb = new StringBuffer(" "); sb.append(getName()); // STONE sb.append(":"); sb.append(Utility.shorten(getX())); sb.append(":"); sb.append(Utility.shorten(getY())); return sb.toString(); } String getName() { return type.getName(); } public double getX() { return location.getX(); } public double getY() { return location.getY(); } public ObservableType getType() { return type; } } *************************************************************************************** ObservableProjectile.java *************************************************************************************** package acsl.dTank.informationMessage; import acsl.dTank.Utility; import acsl.dTank.afv.Location; import acsl.dTank.projectile.Projectile; public class ObservableProjectile extends ObservableObject { private Projectile projectile; public ObservableProjectile(Projectile p) { super(ObservableType.PROJECTILE, new Location(p.getX(), p.getY())); projectile = p; } public Projectile getProjectile() { return projectile; } public String createMessageString() { StringBuffer sb = new StringBuffer(" "); sb.append(getName()); // STONE sb.append(":"); sb.append(projectile.getState()); sb.append(":"); sb.append(Utility.shorten(getX())); sb.append(":"); sb.append(Utility.shorten(getY())); return sb.toString(); } } *************************************************************************************** ObservableTerrain.java *************************************************************************************** package acsl.dTank.informationMessage; import acsl.dTank.afv.Location; import acsl.dTank.map.TerrainType; public class ObservableTerrain extends ObservableObject { public ObservableTerrain(TerrainType type, double x, double y, double fs) { this.type = type; x = ((int) x) - ((int) x) % ((int) fs); y = ((int) y) - ((int) y) % ((int) fs); this.location = new Location(x, y); } public ObservableTerrain(TerrainType type, double x, double y) { this.type = type; this.location = new Location(x, y); } public static ObservableObject create(TerrainType type, double x, double y, double fs) { return new ObservableTerrain(type, x, y, fs); } public static ObservableObject create(TerrainType type, double x, double y) { return new ObservableTerrain(type, x, y); } } *************************************************************************************** ObservableType.java *************************************************************************************** package acsl.dTank.informationMessage; public class ObservableType { String typeName; public ObservableType(String name) { this.typeName = name; } public String getName() { return typeName; } public static final ObservableType AFV = new ObservableType("AFV"); public static final ObservableType PROJECTILE = new ObservableType("Projectile"); } *************************************************************************************** AFVParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.InformationMessage; public class AFVParser extends InformationParser { AFVParser() { super("AFV", 7); } public void parse(String[] tokens, int i, InformationMessage message) { Nationality nationality = Nationality.lookup(tokens[i]); boolean smoking = (tokens[i + 1].equals("Smoking")); double x = Double.parseDouble(tokens[i + 2]); double y = Double.parseDouble(tokens[i + 3]); double h = Double.parseDouble(tokens[i + 4]); double th = Double.parseDouble(tokens[i + 5]); AFVType ty = AFVType.lookup(tokens[i + 6]); message.addAFV(new DetectedAFV(nationality, smoking, x, y, h, th, ty)); } } *************************************************************************************** AmmunitionRemainingParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class AmmunitionRemainingParser extends InformationParser { AmmunitionRemainingParser() { super("AmmunitionRemaining", 1); } public void parse(String[] tokens, int i, InformationMessage message) { int ammo = Integer.parseInt(tokens[i]); message.setAmmunitionRemaining(ammo); } } *************************************************************************************** CollisionParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.map.TerrainType; public class CollisionParser extends InformationParser { CollisionParser() { super("Collision", 3); } public void parse(String[] tokens, int i, InformationMessage message) { TerrainType type = TerrainType.lookup(tokens[i]); double x = Double.parseDouble(tokens[i+1]); double y = Double.parseDouble(tokens[i + 2]); message.setCollision(type); } } *************************************************************************************** DimensionsParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class DimensionsParser extends InformationParser { DimensionsParser() { super("Dimensions", 2); } public void parse(String[] tokens, int i, InformationMessage message) { double w = Double.parseDouble(tokens[i]); double h = Double.parseDouble(tokens[i + 1]); message.setDimensions(w, h); } } *************************************************************************************** ExitParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class ExitParser extends InformationParser { ExitParser() { super("Exit", 0); } public void parse(String[] tokens, int i, InformationMessage message) { message.setExit(); } } *************************************************************************************** FeatureSizeParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class FeatureSizeParser extends InformationParser { FeatureSizeParser() { super("FeatureSize", 1); } public void parse(String[] tokens, int i, InformationMessage message) { double w = Double.parseDouble(tokens[i]); message.setFeatureSize(w); } } *************************************************************************************** FlashParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class FlashParser extends InformationParser { FlashParser() { super("Flash", 2); } public void parse(String[] tokens, int i, InformationMessage message) { double x = Double.parseDouble(tokens[i]); double y = Double.parseDouble(tokens[i + 1]); // message.setFlash(x, y); } } *************************************************************************************** FromParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class FromParser extends InformationParser { FromParser() { super("From", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setFrom(tokens[i]); } } *************************************************************************************** FuelRemaining.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class FuelRemainingParser extends InformationParser { FuelRemainingParser() { super("FuelRemaining", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setFuelRemaining(Double.parseDouble(tokens[i])); } } *************************************************************************************** GunElevationParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class GunElevationParser extends InformationParser { GunElevationParser() { super("GunElevation", 1); } public void parse(String[] tokens, int i, InformationMessage message) { double heading = Double.parseDouble(tokens[i]); message.setGunElevation(heading); } } *************************************************************************************** HeadingParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class HeadingParser extends InformationParser { HeadingParser() { super("Heading", 1); } public void parse(String[] tokens, int i, InformationMessage message) { double heading = Double.parseDouble(tokens[i]); message.setHeading(heading); } } *************************************************************************************** InformationParser.java *************************************************************************************** /** * The base class for information message parsers. */ package acsl.dTank.informationMessage.parser; import java.util.HashMap; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.map.TerrainType; public abstract class InformationParser { private String name; private int nArgs; private static HashMap informationTypes = new HashMap(); private static InformationParser terrainParser; static { initialize(); } public InformationParser(String name, int nArgs) { this.name = name; this.nArgs = nArgs; } public abstract void parse(String[] tokens, int i, InformationMessage message); private static void initialize() { initialize(new ThrottleParser()); initialize(new LocationParser()); initialize(new VelocityParser()); initialize(new HeadingParser()); initialize(new GunElevationParser()); initialize(new AmmunitionRemainingParser()); initialize(new OperationalStatusParser()); initialize(new AFVParser()); // initialize(new FlashParser()); initialize(new TurretHeadingParser()); initialize(new FeatureSizeParser()); initialize(new DimensionsParser()); initialize(new ToParser()); initialize(new FromParser()); initialize(new TimeParser()); initialize(new CollisionParser()); initialize(new ProjectileParser()); initialize(new RadioMessageParser()); initialize(new LoadedParser()); initialize(new FuelRemainingParser()); initialize(new ExitParser()); initialize(new ProjectileScanParser()); terrainParser = new TerrainParser("TERRAIN", 2); } public static void initialize(InformationParser it) { informationTypes.put(it.getName(), it); } public int getNArgs() { return nArgs; } public String getName() { return name; } public static InformationParser lookup(String typeString) { InformationParser pt = (InformationParser) informationTypes.get(typeString); if (pt == null) { if (TerrainType.lookup(typeString) == null) throw new RuntimeException("No such terrain type " + typeString); return terrainParser; } return pt; } } *************************************************************************************** LoadedParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class LoadedParser extends InformationParser { LoadedParser() { super("Loaded", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setLoaded(tokens[i]); } } *************************************************************************************** LocationParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class LocationParser extends InformationParser { LocationParser() { super("Location", 2); } public void parse(String[] tokens, int i, InformationMessage message) { message.setX(tokens[i]); message.setY(tokens[i + 1]); } } *************************************************************************************** LowHillParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.battle.Battlefield; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.informationMessage.ObservableObject; import acsl.dTank.informationMessage.ObservableTerrain; import acsl.dTank.map.TerrainType; public class LowHillParser extends ObservableParser { LowHillParser() { super(TerrainType.LOW_HILL); } public void parse(String[] tokens, int i, InformationMessage message) { TerrainType type = TerrainType.lookup(tokens[i-1]); double x = Double.parseDouble(tokens[i]); double y = Double.parseDouble(tokens[i + 1]); double fs = Battlefield.getFeatureSize(); ObservableObject oo = ObservableTerrain.create(type, x, y, fs); message.addObservableObject(oo); } } *************************************************************************************** ObservableParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.map.TerrainType; public abstract class ObservableParser extends InformationParser { public final TerrainType type; public ObservableParser(TerrainType type) { super(type.getName(), 2); this.type = type; } } *************************************************************************************** OffMapParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.map.TerrainType; public class OffMapParser extends ObservableParser { OffMapParser() { super(TerrainType.OFF_MAP); } public void parse(String[] tokens, int i, InformationMessage message) { // No need to put this on the map. Gets sent by message when colliding // at map edge. } } *************************************************************************************** OperationStatusParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class OperationalStatusParser extends InformationParser { OperationalStatusParser() { super("OperationalStatus", 5); } public void parse(String[] tokens, int i, InformationMessage message) { message.setOperationalStatus(tokens[i], tokens[i + 1], tokens[i + 2], tokens[i + 3], tokens[i + 4]); } } *************************************************************************************** ProjectileParser.java *************************************************************************************** // todo: This is used for two purposes. FIX! package acsl.dTank.informationMessage.parser; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.CommanderControlPanel; public class ProjectileParser extends InformationParser { private double y; private double x; String state; ProjectileParser() { super("Projectile", 3); } public ProjectileParser(double x, double y, String state) { super("Projectile", 3); this.x = x; this.y = y; this.state = state; } public void parse(String[] tokens, int i, InformationMessage message) { double x = Double.parseDouble(tokens[i + 1]); double y = Double.parseDouble(tokens[i + 2]); message.addProjectile(new ProjectileParser(x, y, tokens[i])); } public double getY() { return y; } public double getX() { return x; } public void paint(Graphics2D g, CommanderControlPanel panel) { Image im = Projectile.getImage(state); AffineTransform xform = new AffineTransform(); xform.setToIdentity(); xform.translate(panel.convertPos(x), panel.convertPos(y)); g.drawImage(im, xform, null); } public Object getState() { return state; } } *************************************************************************************** ProjectileScanParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class ProjectileScanParser extends InformationParser { ProjectileScanParser() { super("ProjectileScan", 0); } public void parse(String[] tokens, int i, InformationMessage message) { message.setProjectileScan(); } } *************************************************************************************** RadioMessageParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class RadioMessageParser extends InformationParser { RadioMessageParser() { super("ReceiveRadioMessage", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setRadioMessage(tokens[i]); } } *************************************************************************************** TerrainParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.informationMessage.ObservableObject; import acsl.dTank.informationMessage.ObservableTerrain; import acsl.dTank.map.TerrainType; public class TerrainParser extends InformationParser { public TerrainParser(String name, int nArgs) { super(name, nArgs); } public void parse(String[] tokens, int i, InformationMessage message) { TerrainType type = TerrainType.lookup(tokens[i - 1]); double x = Double.parseDouble(tokens[i]); double y = Double.parseDouble(tokens[i + 1]); ObservableObject oo = ObservableTerrain.create(type, x, y); message.addObservableObject(oo); } } *************************************************************************************** ThrottleParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class ThrottleParser extends InformationParser { ThrottleParser() { super("Throttle", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setThrottle(tokens[i]); } } *************************************************************************************** TimeParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class TimeParser extends InformationParser { TimeParser() { super("Time", 1); } public void parse(String[] tokens, int i, InformationMessage message) { int time = Integer.parseInt(tokens[i]); message.setTime(time); } } *************************************************************************************** ToParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class ToParser extends InformationParser { ToParser() { super("To", 1); } public void parse(String[] tokens, int i, InformationMessage message) { message.setTo(tokens[i]); } } *************************************************************************************** TurretHeadingParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class TurretHeadingParser extends InformationParser { TurretHeadingParser() { super("TurretHeading", 1); } public void parse(String[] tokens, int i, InformationMessage message) { double h = Double.parseDouble(tokens[i]); message.setTurretHeading(h); } } *************************************************************************************** VelocityParser.java *************************************************************************************** package acsl.dTank.informationMessage.parser; import acsl.dTank.informationMessage.InformationMessage; public class VelocityParser extends InformationParser { VelocityParser() { super("Speed", 1); } public void parse(String[] tokens, int i, InformationMessage message) { double speed = Double.parseDouble(tokens[i]); message.setSpeedKPH(speed); } } *************************************************************************************** CommanderMap.java *************************************************************************************** /** * The map used by the commander. */ package acsl.dTank.map; import java.util.ArrayList; import java.util.List; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.informationMessage.ObservableObject; import acsl.dTank.informationMessage.ObservableType; import acsl.dTank.informationMessage.parser.ProjectileParser; public class CommanderMap extends Map { private List afvs = new ArrayList(), projectiles = new ArrayList(); // private List previousAfvs = new ArrayList(), previousProjectiles = new ArrayList(); public static CommanderMap create(double width, double height, double featureSize) { CommanderMap cm = new CommanderMap(width, height, featureSize); cm.map = new TerrainType[cm.widthInFeatures][cm.heightInFeatures]; cm.setAllGrass(); return cm; } private CommanderMap(double width, double height, double featureSize) { super(width, height, featureSize); } public synchronized void reset(InformationMessage m) { setAllGrass(); for (int i = 0, size = m.getNObservableObjects(); i < size; i++) { ObservableObject oo = m.getObservableObject(i); ObservableType ot = oo.getType(); if (ot instanceof TerrainType) { TerrainType mt = (TerrainType) ot; set(oo.getX(), oo.getY(), mt); } } // previousAfvs=afvs; afvs = m.getAFVs(); projectiles = m.getProjectiles(); } public synchronized void setProjectiles(List projectiles) { this.projectiles = projectiles; } public int getNAFVs() { return afvs.size(); } public DetectedAFV getAFV(int i) { return (DetectedAFV) afvs.get(i); } public int getNProjectiles() { return projectiles.size(); } public ProjectileParser getProjectile(int i) { return (ProjectileParser) projectiles.get(i); } public synchronized void addAFVModel(DetectedAFV detectedAFV) { afvs.add(detectedAFV); } // public DetectedAFV getPreviousAFV(int i) { // return (DetectedAFV) previousAfvs.get(i); // } // public int getNPreviousAFVs() { // return previousAfvs.size(); // } public boolean probablyContains(DetectedAFV currentTarget, int elapsedTime) { if (currentTarget == null) return false; for (int i = 0, size = afvs.size(); i < size; i++) { DetectedAFV afv = (DetectedAFV) afvs.get(i); if (currentTarget.closeTo(afv, elapsedTime)) return true; } return false; } public DetectedAFV probablySame(DetectedAFV currentTarget, int elapsedTime) { if (currentTarget == null) return null; for (int i = 0, size = afvs.size(); i < size; i++) { DetectedAFV afv = (DetectedAFV) afvs.get(i); if (currentTarget.closeTo(afv, elapsedTime)) return afv; } return null; } } *************************************************************************************** Map.java *************************************************************************************** /** * The Map is a representation of a field of size WIDTH*HEIGHT, * measured in meters. The array used to define the location of * objects on the map is a widthInFeatures * heightInFeatures array * of bytes. The bytes encode the terrain via a mapping to MapType * objects (e.g., 255=>GRASS). * * (All maps must be square for the time being. And have an integral * ratio with the screen size (500 pixels). It's not worth the testing.) * * All external communications are performed in real world coordinates * {x, y} (meters from {0.0, 0.0}). All velocities are in m/s * (there are Km/Hr interfaces that translate to m/s). All angles in * degrees (North is up on the display). Min map size is 500m (smaller * makes no realistic sense and complicates things). Effective maps are * 1-10km (there's room for interesting features and feature sizes aren't * too large). * * Coordinates outside of the battlefield map to OFF_SCREEN. The field * runs from {0.0, 0.0} to {width, height}. * * The location of features is defined in a text map file or a GIF (soon). * That file defines the number of row and columns it has, effectively * defining a feature size (width/nRows). A 1km map with a text map file * containing 20 rows & cols yields a feature size of 50m. (Kinda large.) * A map file with 50x50 is more reasonable. */ package acsl.dTank.map; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.List; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.Location; public class Map { protected int widthInFeatures, heightInFeatures; protected TerrainType[][] map; private double physicalWidth, physicalHeight; private double featureSize; protected Map(double physicalWidth, double physicalHeight) { this.physicalWidth = physicalWidth; this.physicalHeight = physicalHeight; } protected Map(double physicalWidth, double physicalHeight, double featureSize) { this.physicalWidth = physicalWidth; this.physicalHeight = physicalHeight; this.featureSize = featureSize; this.widthInFeatures = (int) (physicalWidth / featureSize); this.heightInFeatures = (int) (physicalHeight / featureSize); } protected void setAllGrass() { for (int i = 0; i < widthInFeatures; i++) { for (int j = 0; j < heightInFeatures; j++) { set(i, j, TerrainType.GRASS.clone()); } } } public static Map create(String filename, double physicalWidth, double physicalHeight) { List lines = read(filename); return create(lines, physicalWidth, physicalHeight); } public static Map create(List lines, double physicalWidth, double physicalHeight) { Map m = new Map(physicalWidth, physicalHeight); m.initialize(lines); m.checkLegality(); return m; } private void checkLegality() { if (physicalWidth != physicalHeight || physicalWidth < 20) throw new RuntimeException("Map bad size " + physicalWidth + " x " + physicalHeight); if (widthInFeatures > 1000) throw new RuntimeException("Map too large " + widthInFeatures + " x " + heightInFeatures); if (!Parameters.emptyBoardersRequired()) return; for (int i = 0; i < widthInFeatures; i++) { if (!getByIndex(i, 0).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass"); if (!getByIndex(i, heightInFeatures - 1).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass"); if (!getByIndex(0, i).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass"); if (!getByIndex(1, i).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass: " + i); if (!getByIndex(widthInFeatures - 1, i).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass"); if (!getByIndex(widthInFeatures - 2, i).equals(TerrainType.GRASS)) throw new RuntimeException("Bad map: Edges must be grass: " + i); } } private static BufferedReader createMapReader(String mapFileName) throws IOException { InputStream is = null; File f1 = new File(mapFileName); if (f1.exists()) { is = new FileInputStream(f1); } else { URL sr = ClassLoader.getSystemResource(mapFileName); is = sr.openStream(); } return new BufferedReader(new InputStreamReader(is)); } public static List read(String mapFileName) { try { BufferedReader inStream = createMapReader(mapFileName); List lines = new ArrayList(); while (true) { String line = inStream.readLine(); if (line == null) break; lines.add(line.split(" ")); } inStream.close(); return lines; } catch (Exception e) { System.err.println("Specified map file " + mapFileName + " could not be found/read! Aborting!"); throw new RuntimeException(e); } } protected void initialize(List lines) { widthInFeatures = heightInFeatures = lines.size(); if (widthInFeatures == 0) throw new RuntimeException("IMPOSSIBLE"); map = new TerrainType[widthInFeatures][heightInFeatures]; setAllGrass(); widthInFeatures = Parameters.getWidthInFeatures(); heightInFeatures = Parameters.getHeightInFeatures(); if ((widthInFeatures != heightInFeatures) || (heightInFeatures > 100)) throw new RuntimeException("size"); featureSize = physicalWidth / widthInFeatures; Initializer.initializeAll(); for (int y = 0; y < heightInFeatures; y++) { processLine(lines.get(y), y); } // getRedBlueSpawns(); } public void reset(String filename) { List lines = read(filename); widthInFeatures = heightInFeatures = lines.size(); if (widthInFeatures == 0) throw new RuntimeException("IMPOSSIBLE"); map = new TerrainType[widthInFeatures][heightInFeatures]; setAllGrass(); widthInFeatures = Parameters.getWidthInFeatures(); heightInFeatures = Parameters.getHeightInFeatures(); if ((widthInFeatures != heightInFeatures) || (heightInFeatures > 100)) throw new RuntimeException("size"); featureSize = physicalWidth / widthInFeatures; Initializer.initializeAll(); for (int y = 0; y < heightInFeatures; y++) { processLine((String[]) lines.get(y), y); } // getRedBlueSpawns(); } private void processLine(String[] tokens, int y) { for (int x = 0; x < widthInFeatures; x++) { set(x, y, TerrainType.lookup(tokens[x]).clone()); } } public double getFeatureSize() { return featureSize; } public void set(int i, int j, TerrainType type) { if (i >= this.widthInFeatures || j >= this.heightInFeatures || i < 0 || j < 0) return; map[i][j] = type; } public void set(double x, double y, TerrainType mt) { set((int) (x / featureSize), (int) (y / featureSize), mt); } public void set(Location loc, TerrainType tt) { set(loc.getX(), loc.getY(), tt); } public TerrainType get(Location l) { return get(l.getX(), l.getY()); } public TerrainType get(double x, double y) { if (x < 0 || x >= physicalWidth || y < 0 || y >= physicalHeight) return TerrainType.OFF_MAP; return getByIndex((int) (x / featureSize), (int) (y / featureSize)); } private TerrainType getByIndex(int x, int y) { if (x < 0 || x >= widthInFeatures || y < 0 || y >= heightInFeatures) return TerrainType.OFF_MAP; return map[x][y]; } public int getWidthInFeatures() { return map.length; } public double getWidthPhysical() { return physicalWidth; } public double getHeightPhysical() { return physicalHeight; } public void getRedBlueSpawns() { List blueSpawns = new ArrayList(), redSpawns = new ArrayList(), whiteSpawns = new ArrayList(); for (int i = 0; i < widthInFeatures; i++) { for (int j = 0; j < heightInFeatures; j++) { if (map[i][j].equals(TerrainType.BLUE)) { map[i][j] = TerrainType.GRASS.clone(); Location t = new Location(i, j); Location loc = new Location(t.getX() * featureSize, t .getY() * featureSize); blueSpawns.add((Location) loc); } else if (map[i][j].equals(TerrainType.RED)) { map[i][j] = TerrainType.GRASS.clone(); Location t = new Location(i, j); Location loc = new Location(t.getX() * featureSize, t .getY() * featureSize); redSpawns.add((Location) loc); } else if (map[i][j].equals(TerrainType.WHITE)) { map[i][j] = TerrainType.GRASS.clone(); Location t = new Location(i, j); Location loc = new Location(t.getX() * featureSize, t .getY() * featureSize); whiteSpawns.add((Location) loc); } } } Parameters.setBlueSpawnPoints(blueSpawns); Parameters.setRedSpawnPoints(redSpawns); Parameters.setWhiteSpawnPoints(whiteSpawns); } } *************************************************************************************** MapTest.java *************************************************************************************** package acsl.dTank.map; import junit.framework.TestCase; import acsl.dTank.Parameters; public class MapTest extends TestCase { public static final String TEST_MAP = "testMaps/test20x20.map"; private static final String BAD_TEST_MAP_0x0 = "testMaps/BadTestAt0x0.map"; private static final String BAD_TEST_MAP_1x0 = "testMaps/BadTestAt1x0.map"; private static final String BAD_TEST_MAP_0x1 = "testMaps/BadTestAt0x1.map"; private static final String BAD_TEST_MAP_1x1 = "testMaps/BadTestAt1x1.map"; private Map map; public void setUp() { Parameters.setSize(20,20); map = Map.create(TEST_MAP, 100.0, 100.0); assertEquals("", 5.0, map.getFeatureSize(), 0.1); } public void test1() { assertEquals(TerrainType.GRASS, map.get(0, 0)); assertEquals(TerrainType.GRASS, map.get(4, 4)); assertEquals(TerrainType.GRASS, map.get(9, 4)); assertEquals(TerrainType.GRASS, map.get(5, 5)); assertEquals(TerrainType.LOW_HILL, map.get(10, 10)); assertEquals(TerrainType.HIGH_HILL, map.get(15, 10)); assertEquals(TerrainType.WOODS, map.get(21, 10)); assertEquals(TerrainType.GRASS, map.get(25, 10)); assertEquals(TerrainType.GRASS, map.get(99, 99)); assertEquals(TerrainType.OFF_MAP, map.get(100, 99)); } public void test2() { boolean succeeded = true; try { Map.create(TEST_MAP, 100.0, 100.0); } catch (Exception e) { succeeded = false; } assertTrue(succeeded); try {succeeded = true; Map.create(TEST_MAP, 10000.0, 10000.0); } catch (Exception e) { succeeded = false; } assertTrue(succeeded); try {succeeded = true; Map.create(BAD_TEST_MAP_0x0, 100.0, 100.0); } catch (Exception e) { succeeded = false; } assertFalse(succeeded); try {succeeded = true; Map.create(BAD_TEST_MAP_1x0, 100.0, 100.0); } catch (Exception e) { succeeded = false; } assertFalse(succeeded); try {succeeded = true; Map.create(BAD_TEST_MAP_0x1, 100.0, 100.0); } catch (Exception e) { succeeded = false; } assertFalse(succeeded); try {succeeded = true; Map.create(BAD_TEST_MAP_1x1, 100.0, 100.0); } catch (Exception e) { succeeded = false; } assertFalse(succeeded); } public static void main(String[] args) { System.out.println("==========MapTest=========="); MapTest test = new MapTest(); test.setUp(); test.test1(); test.test2(); System.out.println("==========End MapTest=========="); } } *************************************************************************************** TerrainType.java *************************************************************************************** package acsl.dTank.map; import java.awt.Image; import java.awt.MediaTracker; import java.net.URL; import java.util.HashMap; import javax.swing.ImageIcon; import acsl.dTank.informationMessage.ObservableType; public class TerrainType extends ObservableType { public static final TerrainType OFF_MAP = new TerrainType("OFF_MAP", "grass.gif", "?"); public static final TerrainType STONE = new TerrainType("STONE", "rock2.gif", "*"); public static final TerrainType WOODS = new TerrainType("WOODS", "Woods.JPEG", "W"); public static final TerrainType LOW_HILL = new TerrainType("LOW_HILL", "LowHills.JPEG", "L"); public static final TerrainType HIGH_HILL = new TerrainType("HIGH_HILL", "HighHills.jpg", "H"); public static final TerrainType GRASS = new TerrainType("GRASS", "grass.gif", "0"); public static final TerrainType ROAD = new TerrainType("ROAD", "road.jpg", "R"); public static final TerrainType CRATER = new TerrainType("CRATER", "crater.jpg", "C"); // These are hacks to indicate the injection location for tanks. public static final TerrainType BLUE = new TerrainType("BLUE", "grass.gif", "b"); public static final TerrainType RED = new TerrainType("RED", "grass.gif", "r"); public static final TerrainType WHITE = new TerrainType("WHITE", "grass.gif", "w"); /** * Creates a new terrain type (undamaged) * * @param type * @return */ public static TerrainType createTerrain(String type) { return TerrainType.lookup(type).clone(); } private static HashMap typesTable = new HashMap(); // a list of avail // terrains private static HashMap imagesTable = new HashMap(); // a list of preloaded // images // private static boolean initialized; // private Image image; private String mapSymbol; private String imageFilename; private double damage; private double armor; /** * Get a lower version of the the current terrain type.
* This method is analog to the clone method the new terrain will have no * damage * * @return */ public TerrainType lower() { if (this.equals(HIGH_HILL) || this.equals(STONE)) { return LOW_HILL.clone(); } if (this.equals(WOODS) || this.equals(LOW_HILL)) { return GRASS.clone(); } if (this.equals(GRASS)) { return CRATER.clone(); } // default... return CRATER.clone(); } public TerrainType clone() { return new TerrainType(super.getName(), this.imageFilename, this.mapSymbol); } public TerrainType(String type, String imageFilename, String mapSymbol) { super(type); this.mapSymbol = mapSymbol; this.imageFilename = imageFilename; this.damage = 0.0; // assume a volume and a weight this.armor = Math.pow(15.0, 3) * getSpecificWeight(this); } private void initialize() { typesTable.put(getName(), this); typesTable.put(mapSymbol, this); } /** * Get the specific weight of the terrain type specified.
* The type can be a TerrainType, a String or a SymbolChar.
* The weight is intended in Kg/dm3 * * @param type * @return */ private static double getSpecificWeight(Object o) { TerrainType tt = null; if (o instanceof TerrainType) { tt = (TerrainType) o; } else if (o instanceof String) { tt = lookup(o.toString()); } if (tt == null) { return 0.0; // unknown material } else if (tt.equals(STONE) || tt.equals(HIGH_HILL) || tt.equals(LOW_HILL)) { return 2.5; } else if (tt.equals(WOODS)) { return 0.5; // depends on wood type, but 0.3 is a good average (soft // wood) } else if (tt.equals(GRASS)) { return 0.3; // very soft wood } else if (tt.equals(ROAD)) { return 1.7; // hard mud } else { return 1.0; // standard material (water like) } } /* * * t=new MediaTracker(this); b=getImage(getDocumentBase(), "borderex1.gif"); * t.addImage(b,0); for (int i = 1; i <= 10; i++) { m[j] = * getImage(getDocumentBase(), "T"+i+".gif"); t.addImage(m[j],1); j++; } try { * t.waitForID(0); t.waitForID(1); } catch (InterruptedException e) { * return; } */ public static void initializeAll() { OFF_MAP.initialize(); STONE.initialize(); LOW_HILL.initialize(); WOODS.initialize(); HIGH_HILL.initialize(); GRASS.initialize(); ROAD.initialize(); CRATER.initialize(); // BLUE.initialize(); RED.initialize(); WHITE.initialize(); } public Image getImage() { return (Image) imagesTable.get(imageFilename); } public double getDamage() { return damage; } public void addDamage(double damage) { setDamage(this.damage + damage); } /** * Set the current amount of damage for the current terrain * * @param damage * @return */ public void setDamage(double damage) { if (damage > 1.0) damage = 1.0; this.damage = damage; } public boolean isDestroyed() { return this.damage >= 1.0; } public double getArmor() { return this.armor; } public void initializeImage(int fs) { String path = "images/" + imageFilename; URL f = ClassLoader.getSystemResource(path); if (f == null) throw new RuntimeException("Can't find: " + path); ImageIcon ii = new ImageIcon(f); while (ii.getImageLoadStatus() != MediaTracker.COMPLETE) { } Image image = ii.getImage(); image = image.getScaledInstance(fs, fs, 0); imagesTable.put(imageFilename, image); } public static synchronized void initializeImages(int fs) { OFF_MAP.initializeImage(fs); GRASS.initializeImage(fs); LOW_HILL.initializeImage(fs); WOODS.initializeImage(fs); HIGH_HILL.initializeImage(fs); STONE.initializeImage(fs); ROAD.initializeImage(fs); CRATER.initializeImage(fs); // BLUE.initializeImage(fs); RED.initializeImage(fs); WHITE.initializeImage(fs); } public double getHeight() { if (this.equals(HIGH_HILL)) return 1.0; if (this.equals(STONE)) return 1.0; if (this.equals(LOW_HILL)) return 0.5; if (this.equals(WOODS)) return 0.5; if (this.equals(CRATER)) return -0.1; return 0.0; } public boolean isNavigable() { if (this.equals(HIGH_HILL) || this.equals(STONE) || this.equals(OFF_MAP)) return false; return true; } public static TerrainType lookup(String name) { TerrainType type = (TerrainType) typesTable.get(name); if (type == null) throw new RuntimeException("no such type: " + name); return type; } public boolean isOffMap() { return this.equals(OFF_MAP); } public boolean isFullyTransparent() { if (this.equals(ROAD)) return true; if (this.equals(GRASS)) return true; if (this.equals(CRATER)) return true; return false; } public double getPassibility() { if (this.equals(ROAD)) return 1.0; if (this.equals(GRASS)) return 0.7; if (this.equals(LOW_HILL)) return 0.5; if (this.equals(WOODS)) return 0.5; if (this.equals(CRATER)) return 0.4; return 0.0; } public boolean equals(Object o) { if (o instanceof TerrainType) { return ((TerrainType) o).getName().equals(this.getName()); } return false; } } *************************************************************************************** AFVMover.java *************************************************************************************** /** * The base class for AFVmovers. */ package acsl.dTank.mover; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import java.util.ArrayList; import java.util.List; import acsl.dTank.Parameters; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.AFVController; import acsl.dTank.informationMessage.InformationMessage; import acsl.dTank.informationMessage.ObservableAFV; import acsl.dTank.informationMessage.ObservableObject; import acsl.dTank.informationMessage.ObservableProjectile; import acsl.dTank.informationMessage.ObservableTerrain; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.ServerControlPanel; public abstract class AFVMover extends Mover { AFV afv; private boolean isDestroyed; private long timeForNextMessage; private int xPixelPosOld; private int yPixelPosOld; public AFVMover(AFV afv) { this.afv = afv; } public AFV getAFV() { return afv; } public void sendExitMessage() { AFVController c = afv.getController(); c.sendMessage(" Exit:"); } public void sendMessage(long time) { if (isDestroyed) return; if (time < timeForNextMessage) { return; } AFVController c = afv.getController(); String msg0 = scanForProjectiles(); if (msg0 != null) { //if (time < timeForNextMessage) // c.sendMessage(" ProjectileScan:" + msg0); } else msg0 = ""; timeForNextMessage = time + Parameters.getMessagePeriod(); if (afv.isDestroyed()) // do one last update isDestroyed = true; String msg1 = scanForAFVs(); if (msg1 == null) msg1 = ""; String msg2 = scanForTerrain(); if (msg2 == null) msg2 = ""; String msg3 = InformationMessage.createAFVInformationMessageString(afv); c.sendMessage(msg0 + msg1 + msg2 + msg3); } public String scanForAFVs() { List observedObjects = new ArrayList(); synchronized (Battlefield.class) { for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { AFVMover m = (AFVMover) Battlefield.getAFVMover(i); if (m == this) continue; AFV a = m.getAFV(); double x1 = a.getX(); double y1 = a.getY(); if (canSee(x1, y1)) observedObjects.add(new ObservableAFV(a)); } if (observedObjects.size() == 0) return null; StringBuffer sb = new StringBuffer(""); for (int i = 0, size = observedObjects.size(); i < size; i++) { ObservableObject oo = (ObservableObject) observedObjects.get(i); sb.append(oo.createMessageString()); } return sb.toString(); } } public String scanForProjectiles() { List observedObjects = new ArrayList(); synchronized (Battlefield.class) { for (int i = 0, size = Battlefield.getNProjectiles(); i < size; i++) { ProjectileMover m = (ProjectileMover) Battlefield.getProjectile(i); Projectile p = m.getProjectile(); double x1 = p.getX(); double y1 = p.getY(); if (canSee(x1, y1)) observedObjects.add(new ObservableProjectile(p)); } if (observedObjects.size() == 0) return null; StringBuffer sb = new StringBuffer(""); for (int i = 0, size = observedObjects.size(); i < size; i++) { ObservableProjectile oo = (ObservableProjectile) observedObjects.get(i); sb.append(oo.createMessageString()); } return sb.toString(); } } /** * Tells if the current AFV can see the point at coordinates x1, y1 * @param x1 * @param y1 * @return */ private boolean canSee(double x1, double y1) { Map map = Battlefield.getMap(); double x0 = afv.getX(); double y0 = afv.getY(); //double dx = x0 - x1, dy = y0 - y1; double scanArc = afv.getVisibilityArc(); /* WRONG EXPRESSION! double angle = Math.atan2(dx, dy); if (angle < 0.0) angle += Math.PI * 2; */ double angle = Utility.calculateAngle(x0, y0, x1, y1); double fs = Battlefield.getFeatureSize(); double h = afv.getTurretHeading(); double start = Math.toRadians(h - scanArc / 2.0), last = Math.toRadians(h + scanArc / 2.0); //System.err.println("Scanning "+angle+" in a range from "+start+" to "+last); if (angle < start) return false; if (angle > last) return false; double distance = Utility.calculateDistance(afv.getX(), afv.getY(), x1, y1); if (distance > Parameters.getMaximumVisualDistance()) return false; //set the current tank terrain type TerrainType transparentTerrain = map.get(x0, y0); //look for objects in line ObservableObject oo = scanForObstacle(x0, y0, x1, y1, distance, angle, fs, map, transparentTerrain); //if no object in line: we can seen if (oo == null){ return true; }else{ return false; } //if object in line: we cannot see if the object is closer to us /*double pdist = dx * dx + dy * dy; double odx = x0 - oo.getX(); double ody = y0 - oo.getY(); double odist = odx * odx + ody * ody; if (odist > pdist){ //System.err.println(x0+","+y0+" CanSee "+x1+","+y1+": obstacle was at "+odx+","+ody+" ("+odist+">"+pdist+")"); return true; } return false;*/ } public String scanForTerrain() { Map map = Battlefield.getMap(); List observedObjects = new ArrayList(); double x = afv.getX(); double y = afv.getY(); double fs = Battlefield.getFeatureSize(); double h = afv.getTurretHeading(); double scanArc = afv.getVisibilityArc(); double scanIncrementRadians = Math.asin(0.5 * fs / Battlefield.getPhysicalWidth()); double start = Math.toRadians(h - scanArc / 2.0), last = Math.toRadians(h + scanArc / 2.0); ObservableObject previousTerrain = null; TerrainType transparentTerrain = map.get(x, y); if (transparentTerrain != TerrainType.GRASS) observedObjects.add(new ObservableTerrain(transparentTerrain, x, y, fs)); for (double radians = start; radians < last; radians += scanIncrementRadians) { ObservableObject oo = scanForTerrain(x, y, Parameters.getMaximumVisualDistance(), radians, fs, map, transparentTerrain); if (oo == null) continue; if (oo instanceof ObservableTerrain) if (!oo.equals(previousTerrain)) { observedObjects.add(oo); previousTerrain = oo; } } StringBuffer sb = new StringBuffer(""); for (int i = 0, size = observedObjects.size(); i < size; i++) { ObservableObject oo = (ObservableObject) observedObjects.get(i); sb.append(oo.createMessageString()); } return sb.toString(); } private ObservableObject scanForTerrain(double x, double y, double dist, double radians, double fs, Map map, TerrainType transparentTerrain) { double xinc = fs * Math.sin(radians) / 4; double yinc = -fs * Math.cos(radians) / 4; double dist2 = Math.pow(dist, 2.0); for (double x1 = x, y1 = y; Utility.calculateDistance2(x, y, x1, y1)<=dist2; x1 += xinc, y1 += yinc) { TerrainType type = map.get(x1, y1); if (type.isOffMap()) break; //if transparent if (type.isFullyTransparent() //if looking down from a hill ||(transparentTerrain.getHeight()>=type.getHeight())){ continue; // if on low hill, see over all low hills, woods, } // etc. return new ObservableTerrain(type, x1, y1, fs); } return null; } private ObservableObject scanForObstacle(double x, double y, double tx, double ty, double dist, double radians, double fs, Map map, TerrainType transparentTerrain) { double xinc = fs * Math.sin(radians) / 4; double yinc = -fs * Math.cos(radians) / 4; double dist2 = Math.pow(dist, 2.0); TerrainType targetType = map.get(tx,ty); double checkHeight = Math.max(transparentTerrain.getHeight(), targetType.getHeight()); for (double x1 = x, y1 = y; Utility.calculateDistance2(x, y, x1, y1)<=dist2; x1 += xinc, y1 += yinc) { TerrainType type = map.get(x1, y1); if (type.isOffMap()) break; //if on the other side of something, return the obstacle if (type.getHeight()<=checkHeight){ continue; } // etc. return new ObservableTerrain(type, x1, y1, fs); } return null; } public double calculateDeltaX(double seconds) { return seconds * afv.getSpeed() * Math.sin(Math.toRadians(afv.getHeading())) * 1.0; } public double calculateDeltaY(double seconds) { return seconds * afv.getSpeed() * Math.cos(Math.toRadians(afv.getHeading())) * -1.0; } public void paint(Graphics2D g, ServerControlPanel panel, double featureSize) { double scanLineLength = 100.0; Image bodyImage = panel.getBodyImage(afv); Image turretImage = panel.getTurretImage(afv); double heading = Math.toRadians(afv.getHeading()); double turretHeading = Math.toRadians(afv.getTurretHeading()); int fs4 = panel.convertPos(featureSize / 2); // int fs = panel.convertPos(featureSize); int xPixelPos = panel.convertPos(afv.getX()); int yPixelPos = panel.convertPos(afv.getY()); // int xPixelPosOldFS = xPixelPosOld + fs + 4; // int yPixelPosOldFS = yPixelPosOld + fs + 4; AffineTransform xform = new AffineTransform(); { xform.setToIdentity(); xform.translate(xPixelPos, yPixelPos); xform.rotate(heading, fs4, fs4); g.drawImage(bodyImage, xform, null); } { xform.setToIdentity(); xform.translate(xPixelPos, yPixelPos); xform.rotate(turretHeading, fs4, fs4); g.drawImage(turretImage, xform, null); } if (!afv.isDestroyed() && false) { double halfArc = Math.toRadians(afv.getVisibilityArc() / 2.0); int x2Pixels = (int) (xPixelPos + scanLineLength * Math.sin(turretHeading + halfArc)); int y2Pixels = (int) (yPixelPos - scanLineLength * Math.cos(turretHeading + halfArc)); int x3Pixels = (int) (xPixelPos + scanLineLength * Math.sin(turretHeading - halfArc)); int y3Pixels = (int) (yPixelPos - scanLineLength * Math.cos(turretHeading - halfArc)); g.drawLine(xPixelPos + fs4, yPixelPos + fs4, x2Pixels + fs4, y2Pixels + fs4); g.drawLine(xPixelPos + fs4, yPixelPos + fs4, x3Pixels + fs4, y3Pixels + fs4); } } public void unpaint(Graphics2D g, ServerControlPanel panel, double featureSize) { int fs = panel.convertPos(featureSize); int xPixelPos = panel.convertPos(afv.getX()); int yPixelPos = panel.convertPos(afv.getY()); int xPixelPosOldFS = xPixelPosOld + fs + 20; int yPixelPosOldFS = yPixelPosOld + fs + 20; g.drawImage(panel.backgroundImage, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, panel); xPixelPosOld = Math.max(0, xPixelPos - 10); yPixelPosOld = Math.max(0, yPixelPos - 10); } } *************************************************************************************** AFVMoverTest.java *************************************************************************************** package acsl.dTank.mover; import junit.framework.TestCase; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.AFVController; import acsl.dTank.controller.DullAFVController; import acsl.dTank.projectile.Projectile; public class AFVMoverTest extends TestCase { private AFV tank0; AFVController c0, c1; public void setUp() { Parameters.setTesting(true); Battlefield.create("testMaps/TestCenter20x20.map", 1000.0, 1000.0); // map = battlefield.getMap(); c0 = DullAFVController.create(Nationality.BLUE); tank0 = Tank.create(AFVType.SHERMAN, c0); tank0.setLocation(800.0, 500.0); tank0.setHeading(270.0); tank0.setTurretHeading(270.0); { Projectile p = new Projectile(tank0, tank0.getTurretHeading(), tank0.getGunElevation(), 400.0, 500.0); Battlefield.addProjectile(p); } { Projectile p = new Projectile(tank0, tank0.getTurretHeading(), tank0.getGunElevation(), 60.0, 60.0); Battlefield.addProjectile(p); } { Projectile p = new Projectile(tank0, tank0.getTurretHeading(), tank0.getGunElevation(), 200.0, 880.0); Battlefield.addProjectile(p); } { Projectile p = new Projectile(tank0, tank0.getTurretHeading(), tank0.getGunElevation(), 200.0, 700.0); Battlefield.addProjectile(p); } c0.setAFV(tank0); Battlefield.addTank(tank0); // ServerControlPanel.create(Battlefield.getMap()); } public void test1() { AFVMover m = Battlefield.getAFVMover(0); String s = m.scanForProjectiles(); assertEquals(" Projectile:InFlight:400.0:500.0 Projectile:InFlight:200.0:700.0", s); } public static void main(String[] args) { System.out.println("==========AFVMoverTest=========="); AFVMoverTest test = new AFVMoverTest(); test.setUp(); test.test1(); } } *************************************************************************************** CollisionTest.java *************************************************************************************** package acsl.dTank.mover; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.AFVController; import acsl.dTank.controller.DullAFVController; import acsl.dTank.map.Map; public class CollisionTest extends TestCase { private AFV tank0; AFVController c0, c1; private Map map; public void setUp() { Parameters.setTesting(true); Initializer.initializeAll( ); Battlefield.create("testMaps/TestCenter20x20.map", 1000.0, 1000.0); map = Battlefield.getMap(); c0 = DullAFVController.create(Nationality.BLUE); tank0 = Tank.create(AFVType.SHERMAN, c0); tank0.setLocation(949, 500); c0.setAFV(tank0); Battlefield.addTank(tank0); assertEquals("", 0.0, tank0.getSpeed(), 0.01); } public void test1() { Battlefield.update(1.0); assertEquals(0.0, tank0.getSpeedKPH(), 0.01); assertTrue(tank0.atLocation(949.0, 500.0)); tank0.setSpeedKPH(-20.0); tank0.setThrottle(-1.0); Battlefield.update(1.0); assertEquals(-20.0, tank0.getSpeedKPH(), 0.01); assertEquals(949.0, tank0.getX(), 0.1); } public void test2() { tank0.setLocation(49.0, 49.0); assertFalse(Mover.collision(49.0, 49.0, 0.0, 0.0, map)); assertTrue(Mover.collision(49.0, 49.0, 1.0, 2.0, map)); assertTrue(Mover.collision(49.0, 49.0, 1.0, 1.0, map)); tank0.setLocation(150.0, 150.0); assertFalse(Mover.collision(150.0, 150.0, 0.0, 0.0, map)); assertFalse(Mover.collision(150.0, 150.0, 0.0, -1.0, map)); assertTrue(Mover.collision(150.0, 150.0, -1.0, -1.0, map)); tank0.setLocation(199.0, 100.0); assertFalse(Mover.collision(199.0, 100.0, 0.0, 0.0, map)); assertTrue(Mover.collision(199.0, 100.0, -50.0, -1.0, map)); assertFalse(Mover.collision(199.0, 100.0, 1.0, -1.0, map)); tank0.setLocation(100.0, 150.0); assertFalse(Mover.collision(100.0, 150.0, 0.0, 0.0, map)); assertTrue(Mover.collision(100.0, 150.0, -1.0, -1.0, map)); assertFalse(Mover.collision(100.0, 150.0, -1.0, 0.0, map)); assertFalse(Mover.collision(100.0, 150.0, -1.0, 1.0, map)); assertTrue(Mover.collision(100.0, 150.0, 0.0, -1.0, map)); assertFalse(Mover.collision(100.0, 150.0, 0.0, 0.0, map)); assertFalse(Mover.collision(100.0, 150.0, 0.0, 1.0, map)); } // public void test3() { // tank0.setHeading(0.0); // tank0.setLocation(100.0, 0.0); // tank0.setThrottle(-1.0); // tank0.setSpeedKPH(0.0); // battlefield.update(1.0); // assertEquals(-50.0, tank0.getSpeedKPH(), 0.01); // assertEquals(100.0, tank0.getX(), 0.1); // assertEquals(13.8, tank0.getY(), 0.1); // battlefield.update(8.0); // assertEquals(0.0, tank0.getSpeedKPH(), 0.01); // Hits stone // assertEquals(100.0, tank0.getX(), 0.1); // assertEquals(13.88, tank0.getY(), 0.1); // // tank0.setLocation(0.0, 100.0); // tank0.setThrottle(1.0); // tank0.setSpeedKPH(0.0); // battlefield.update(1.0); // assertEquals(50.0, tank0.getSpeedKPH(), 0.1); // assertEquals(0.0, tank0.getX(), 0.1); // assertEquals(86.1, tank0.getY(), 0.1); // } public static void main(String[] args) { System.out.println("==========CollisionTest=========="); CollisionTest test = new CollisionTest(); test.setUp(); test.test1(); test.test2(); // test.test3(); } } *************************************************************************************** DamageController.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.map.TerrainType; import acsl.dTank.projectile.Projectile; public abstract class DamageController { private static final double HIGH_ENERGY = 750 * 750 * 6.0; // kg (m/s)^2 private static final double MEDIUM_ENERGY = 650 * 650 * 6.0; // kg (m/s)^2 private static final double LOW_ENERGY = 500 * 500 * 6.0; // kg (m/s)^2 private static DamageController damageController; public abstract void doDamageTarget(AFV afv, Projectile projectile); public abstract void doDamageTarget(TerrainType type, Projectile projectile); public static void damageTarget(AFV afv, Projectile projectile) { damageController.doDamageTarget(afv, projectile); } public static void damageTarget(TerrainType type, Projectile projectile){ damageController.doDamageTarget(type, projectile); } public static void setDamageController(String dc) { if (dc.equals("SimpleDamageController")) { damageController = new SimpleDamageController(); return; }if (dc.equals("DeterministicDamageController")) { damageController = new DeterministicDamageController(); return; } throw new RuntimeException("No such damage controller: " + dc); } // 0 is head-on static double getImpactAngle(AFV afv, Projectile projectile) { return Utility.normalizeAngle(afv.getHeading() - projectile.getVelocity().getHeading() - 180.0); } static boolean isSideImpact(AFV afv, Projectile projectile) { double angle = getImpactAngle(afv, projectile); if (angle > 45.0 & angle < 135) return true; if (angle > 225.0 & angle < 315.0) return true; return false; } static boolean highEnergy(double projectileEnergy) { return projectileEnergy > HIGH_ENERGY; } static boolean mediumEnergy(double projectileEnergy) { return projectileEnergy > MEDIUM_ENERGY; } static boolean lowEnergy(double projectileEnergy) { return projectileEnergy > LOW_ENERGY; } } *************************************************************************************** DeterministicDamageController.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.controller.RealisticAFVController; import acsl.dTank.map.TerrainType; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.ServerControlPanel; public class DeterministicDamageController extends DamageController { public static final double PENETRATION_RATIO = 0.005; public static void main(String args[]){ TerrainType grass = TerrainType.GRASS.clone(); TerrainType stone = TerrainType.STONE.clone(); TerrainType wood = TerrainType.WOODS.clone(); TerrainType road = TerrainType.ROAD.clone(); AFV afv = AFV.create(AFVType.SHERMAN, new RealisticAFVController("Boh",Nationality.BLUE,null)); Projectile proj = Projectile.create(afv, 0.0); testDamage(grass,proj); testDamage(stone,proj); testDamage(wood,proj); testDamage(road,proj); } private static void testDamage(TerrainType t, Projectile p){ DeterministicDamageController dmg = new DeterministicDamageController(); System.out.println("Hitting "+t.getName()+" with "+p.getEnergy()+" and armor "+t.getArmor()); dmg.doDamageTarget(t,p); double damageInflicted = p.getEnergy()*PENETRATION_RATIO/(t.getArmor()); System.out.println("Damage inflicted: "+damageInflicted); System.out.println("TARGET "+t.getName()+" damage is "+t.getDamage()); } public void doDamageTarget(TerrainType type, Projectile projectile){ double armor = type.getArmor(); double projectileEnergy = projectile.getEnergy(); double damageInflicted = projectileEnergy*PENETRATION_RATIO/(armor); //ServerControlPanel.writeDisplayMessage("Projectile energy "+projectileEnergy+" hit armor "+armor+" rand "+rand); ServerControlPanel.writeDisplayMessage(projectile.getName()+" hit "+type.getName()+" with "+Utility.shorten(damageInflicted)+" damage inflicted"); if(!type.equals(TerrainType.CRATER)){ type.addDamage(damageInflicted); } } public void doDamageTarget(AFV afv, Projectile projectile) { boolean isSideImpact = isSideImpact(afv, projectile); double armorThickness = afv.getArmorThickness(isSideImpact); //double armorDamage = afv.getArmorDamage(); //double effectiveArmorThickness = armorThickness * (1.0 - armorDamage); double projectileEnergy = projectile.getEnergy(); // kg- (m/s)^2 //ServerControlPanel.writeDisplayMessage("Proj mass: "+projectile.getMass()); //ServerControlPanel.writeDisplayMessage("Proj energy: "+projectileEnergy); // an 88 @ close range destroys a Sherman. x3 destroys a Tiger. x6 destroys a King Tiger. //double damageInflicted = (projectileEnergy * projectile.getMass() / armorThickness) * 2.5; double damageInflicted = projectileEnergy*PENETRATION_RATIO/(armorThickness+1); //ServerControlPanel.writeDisplayMessage("Armor Thickness (effective): "+effectiveArmorThickness); //ServerControlPanel.writeDisplayMessage("Damage inflicted: "+damageInflicted); if (damageInflicted > 1.0) { ServerControlPanel.writeDisplayMessage(afv.getName() + " hit and destroyed. "); afv.setDestroyed(); return; } /*if (damageInflicted < 0.5) damageInflicted = damageInflicted / 4;*/ double armorDamage = afv.incArmorDamage(damageInflicted); ServerControlPanel.writeDisplayMessage(afv.getName() + " hit with " + Utility.shorten(damageInflicted) + " damage, leaving " + Utility.shorten(1.0 - armorDamage)); if (armorDamage > 1.0) { ServerControlPanel.writeDisplayMessage(afv.getName() + " finally destroyed. "); afv.setDestroyed(); return; } if (damageInflicted > 0.5) { if (afv.isRadioOperational()) { ServerControlPanel.writeDisplayMessage(afv.getName() + " radio out."); afv.setRadioDestroyed(); } afv.setCrewSpacy(); if (isSideImpact) { afv.setTreadDamaged(); ServerControlPanel.writeDisplayMessage(afv.getName() + " damaged tread."); } return; } if (damageInflicted > 0.2) { afv.setCrewSpacy(); return; } return; } } *************************************************************************************** MagicAFVMover.java *************************************************************************************** /** * This mover is for "video game" behavior. */ package acsl.dTank.mover; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; public class MagicAFVMover extends AFVMover { public MagicAFVMover(AFV afv) { super(afv); } public void move(double seconds) { double newSpeed = 0.0; afv.turn(seconds); Map map = Battlefield.getMap(); TerrainType type = map.get(afv.getX(), afv.getY()); double maxSpeed = afv.getMaxSpeed(); double desiredSpeed = afv.getDesiredSpeedMPS(); double p = type.getPassibility(); maxSpeed = maxSpeed * p; desiredSpeed = desiredSpeed * p; newSpeed = desiredSpeed; afv.setSpeedMPS(newSpeed); if (afv.getFuelRemaining() <= 0.0) {return;} double fuelConsumed = afv.getThrottle() * seconds * afv.getConsumptionRate(); afv.updateFuelRemaining(fuelConsumed); double deltaX = calculateDeltaX(seconds); double deltaY = calculateDeltaY(seconds); double x = afv.getX(); double y = afv.getY(); Location loc = collisionAt(afv, x, y, deltaX, deltaY, map); if (loc != null) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); TerrainType type1 = map.get(loc.getX(), loc.getY()); afv.getController().sendMessage( " Collision:" + type1.getName() + ":" + loc.getX() + ":" + loc.getY()); return; } Location l3 = collidedWithTank(afv, x + deltaX, y + deltaY); if (l3 != null) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); return; } afv.updateLocation(deltaX, deltaY); } } *************************************************************************************** MagicProjectileMover.java *************************************************************************************** /** * This mover is for "video game" behavior. */ package acsl.dTank.mover; import acsl.dTank.Logger; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.afv.Velocity; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.projectile.Projectile; public class MagicProjectileMover extends ProjectileMover { public MagicProjectileMover(Projectile projectile) { this.projectile = projectile; } public void move(double seconds) { if (projectile.isExploded()) { long time = System.currentTimeMillis(); if ((time - projectile.getExplodeTime()) > 2000) Battlefield.removeProjectile(this); return; } Velocity v = projectile.getVelocity(); double deltaX = v.calculateDeltaX(seconds); double deltaY = v.calculateDeltaY(seconds); double x = projectile.getX(); double y = projectile.getY(); Map map = Battlefield.getMap(); Location loc = collisionAt(null, x, y, deltaX, deltaY, map); if (loc != null) { projectile.update(deltaX, deltaY); // System.out.println("Projectile hit at " + (x + deltaX) + " " + (y // + deltaY)); Logger.log("Projectile hit terrain"); projectile.explode(); return; } AFV afv = hitTarget(x, y, deltaX, deltaY); if (afv != null) { projectile.update(deltaX, deltaY); Logger.log("Projectile hit " + afv.getName() + " at " + Utility.shorten(x + deltaX) + " " + Utility.shorten(y + deltaY)); DamageController.damageTarget(afv, projectile); projectile.explode(); return; } projectile.update(deltaX, deltaY); } } *************************************************************************************** Mover.java *************************************************************************************** /** * Base class for movers */ package acsl.dTank.mover; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; public abstract class Mover { public static boolean collision(AFV afv, double x, double y, double deltaX, double deltaY, Map map) { return (collisionAt(afv, x, y, deltaX, deltaY, map) != null); } public static Location collisionAt(AFV afv, double x, double y, double deltaX, double deltaY, Map map) { Location l1 = nonNavigable(x, y, map); if (l1 != null) { TerrainType type = map.get(l1); throw new RuntimeException("IMPOSSIBLE " + "Tank at [" + x + ", " + y + "] ontop of " + type.getName() + " at [" + l1.getX() + ", " + l1.getY() + "]"); } Location l2 = nonNavigable(x + deltaX, y + deltaY, map); if (l2 != null) return l2; return null; } public static Location collidedWithTank(AFV afv, double x, double y) { synchronized (Battlefield.class) { for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { AFVMover m = (AFVMover) Battlefield.getAFVMover(i); AFV afv0 = m.getAFV(); if (afv == afv0) continue; // Don't hit yourself double dx = x - afv0.getX(); double dy = y - afv0.getY(); double distance2 = dx * dx + dy * dy; if (distance2 < Parameters.getCOLLISION_RADIUS2()) { return new Location(afv0.getX(), afv0.getY()); } } return null; } } private static Location nonNavigable(double x, double y, Map map) { double fs = Battlefield.getFeatureSize(); { TerrainType type = map.get(x + fs, y + fs); if (!type.isNavigable()) { return new Location(x + fs, y + fs); } } { TerrainType type = map.get(x + fs, y); if (!type.isNavigable()) { return new Location(x + fs, y); } } { TerrainType type = map.get(x, y + fs); if (!type.isNavigable()) { return new Location(x, y + fs); } } { TerrainType type = map.get(x, y); if (!type.isNavigable()) { return new Location(x, y); } } return null; } protected static boolean isNear(double x1, double y1, double x2, double y2) { if (Math.abs(x1 - x2) > Battlefield.getFeatureSize() / 2) return false; if (Math.abs(y1 - y2) > Battlefield.getFeatureSize() / 2) return false; return true; } public abstract void move(double seconds); public static boolean collision(double d, double e, double f, double g, Map map) { return collision(null, d, e, f, g, map); } } *************************************************************************************** MovingTest.java *************************************************************************************** package acsl.dTank.mover; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.AFVController; import acsl.dTank.controller.DullAFVController; import acsl.dTank.projectile.Projectile; public class MovingTest extends TestCase { private static final String SCAN0 = " AFV:Blue:OK:500.0:500.0:135.0:0.0:Sherman"; private AFV tank0, tank1; AFVController c0, c1; public void setUp() { Parameters.setTesting(true); Parameters.setLoggingToTTY(true); Initializer.initializeAll(); Battlefield.create("testMaps/empty20x20.map", 1000.0, 1000.0); c0 = DullAFVController.create(Nationality.BLUE); tank0 = Tank.create(AFVType.SHERMAN, c0); c0.setAFV(tank0); Battlefield.addTank(tank0); c1 = DullAFVController.create(Nationality.BLUE); tank1 = Tank.create(AFVType.SHERMAN, c1); c1.setAFV(tank1); Battlefield.addTank(tank1); assertEquals("", 0.0, tank0.getSpeed(), 0.1); } public void test1() { tank0.setLocation(949.0, 500.0); tank0.setThrottle(0.0); tank0.setSpeedKPH(0.0); Battlefield.update(1.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.1); tank0.setLocation(949.0, 500.0); tank0.setThrottle(1.0); tank0.setSpeedKPH(50.0); Battlefield.update(1.0); assertEquals("", 20.0, tank0.getSpeedKPH(), 0.1); tank0.setSpeedKPH(0.0); Battlefield.update(1.0); assertEquals("", 20.0, tank0.getSpeedKPH(), 0.1); tank0.setSpeedKPH(50.0); Battlefield.update(9.0); assertEquals("", 20.0, tank0.getSpeedKPH(), 0.1); tank0.setSpeedKPH(50.0); Battlefield.update(2.5); assertEquals("", 20.0, tank0.getSpeedKPH(), 0.1); } public void test2() { tank0.setSpeedKPH(0.0); tank0.setLocation(0.0, 0.0); tank0.setHeading(0.0); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.1); tank0.setLocation(0.0, 0.0); tank0.setHeading(0.0); tank0.setThrottle(-1.0); tank0.setSpeedKPH(-20.0); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getX(), 0.1); assertEquals("", 55.555, tank0.getY(), 0.1); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getX(), 0.1); assertEquals("", 111.11, tank0.getY(), 0.1); } public void test3() { tank0.setThrottle(0.0); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.1); tank0.setLocation(0.0, 0.0); tank0.setThrottle(1.0); tank0.setDesiredHeading(90.01); Battlefield.update(10.0); assertEquals(0.0, tank0.getY(), 0.1); assertEquals(55.55, tank0.getX(), 0.1); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getY(), 0.1); assertEquals("", 111.11, tank0.getX(), 0.1); } public void test4() { tank0.setLocation(0.0, 0.0); tank0.setThrottle(0.0); Battlefield.update(10.0); assertEquals("", 0.0, tank0.getSpeedKPH(), 0.1); tank0.setThrottle(1.0); // tank0.setHeading(135.0); TEST FOR SLOW TURNS tank0.setDesiredHeading(135.0); Battlefield.update(10.0); assertEquals("", 39.28, tank0.getY(), 0.1); assertEquals("", 39.28, tank0.getX(), 0.1); tank1.setThrottle(-1.0); tank1.setLocation(0.0, 0.0); tank1.setDesiredHeading(0.0); Battlefield.update(10.0); assertEquals("", 78.56, tank0.getY(), 0.1); assertEquals("", 78.56, tank0.getX(), 0.1); assertEquals("", 0.0, tank1.getX(), 0.1); assertEquals("", 55.55, tank1.getY(), 0.1); } public void test5() { tank0.setLocation(500.0, 500.0); tank1.setLocation(100.0, 500.0); tank1.setTurretHeading(90.0); Projectile p = new Projectile(tank1, 90.0, 0.3, 500.0, 550.0); Battlefield.addProjectile(p); MagicAFVMover m = new MagicAFVMover(tank1); String s = m.scanForAFVs(); assertEquals(SCAN0, s); } /** * @param args */ public static void main(String[] args) { System.out.println("==========MovingTest=========="); MovingTest test = new MovingTest(); test.setUp(); test.test1(); test.test2(); test.test3(); test.test4(); test.test5(); System.out.println("==========End MovingTest=========="); } } *************************************************************************************** ProjectileMover.java *************************************************************************************** package acsl.dTank.mover; import java.awt.Graphics2D; import java.awt.Image; import java.awt.geom.AffineTransform; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.battle.Battlefield; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.ServerControlPanel; public abstract class ProjectileMover extends Mover { Projectile projectile; private int xPixelPosOld; private int yPixelPosOld; public abstract void move(double seconds); public static ProjectileMover create(Projectile p) { if (Parameters.isMagicMode()) return new MagicProjectileMover(p); if (Parameters.isRealisticMode()) return new RealisticProjectileMover(p); if (Parameters.isDeterministicMode()) return new RealisticProjectileMover(p); throw new RuntimeException("Unknown mode"); } AFV hitTarget(double x, double y, double deltaX, double deltaY) { synchronized (Battlefield.class) { for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { AFVMover m = (AFVMover) Battlefield.getAFVMover(i); AFV afv = m.getAFV(); if (afv.isDestroyed()) continue; if (afv.getNationality() == projectile.getAFV().getNationality()) continue; // Don't hit your own tanks if (hitTank(afv, x, y, deltaX, deltaY)) { projectile.getAFV().incSuccessfulShot(); return afv; } } return null; } } boolean hitTank(AFV afv, double x, double y, double deltaX, double deltaY) { double radius = Parameters.getHitRadius(); double centerX = x + deltaX / 2; double centerY = y + deltaY / 2; double distX = afv.getX() - centerX; double distY = afv.getY() - centerY; double distance = Math.sqrt((distX * distX) + (distY * distY)); if (distance < radius) return true; return false; } public void paint(Graphics2D g, ServerControlPanel panel, double featureSize) { int fs = panel.convertPos(featureSize); int xPixelPos = panel.convertPos(projectile.getX()); int yPixelPos = panel.convertPos(projectile.getY()); int xPixelPosOldFS = xPixelPosOld + fs + 10; int yPixelPosOldFS = yPixelPosOld + fs + 10; g.drawImage(panel.backgroundImage, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, panel); xPixelPosOld = Math.max(0, xPixelPos - 6); yPixelPosOld = Math.max(0, yPixelPos - 6); Image im = projectile.getImage(); AffineTransform xform = new AffineTransform(); xform.setToIdentity(); xform.translate(xPixelPos, yPixelPos); g.drawImage(im, xform, null); } public Projectile getProjectile() { return projectile; } public boolean isExploded() { return projectile.isExploded(); } public void unpaint(Graphics2D g, ServerControlPanel panel, double featureSize) { int fs = panel.convertPos(featureSize); // int xPixelPos = panel.convertPos(projectile.getX()); // int yPixelPos = panel.convertPos(projectile.getY()); int xPixelPosOldFS = xPixelPosOld + fs; int yPixelPosOldFS = yPixelPosOld + fs; g.drawImage(panel.backgroundImage, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, xPixelPosOld, yPixelPosOld, xPixelPosOldFS, yPixelPosOldFS, panel); } } *************************************************************************************** QuantizedAFVMover.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.Parameters; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; public class QuantizedAFVMover extends AFVMover { public QuantizedAFVMover(AFV afv) { super(afv); } public void move(double seconds) { double newSpeed = 0.0; afv.turn(seconds); Map map = Battlefield.getMap(); TerrainType type = map.get(afv.getX(), afv.getY()); double maxSpeed = afv.getMaxSpeed(); double desiredSpeed = afv.getDesiredSpeedMPS(); double p = type.getPassibility(); maxSpeed = maxSpeed * p; desiredSpeed = desiredSpeed * p; newSpeed = desiredSpeed; afv.setSpeedMPS(newSpeed); if (afv.getFuelRemaining() <= 0.0) { return; } double fuelConsumed = afv.getThrottle() * seconds * afv.getConsumptionRate(); afv.updateFuelRemaining(fuelConsumed); double deltaX = calculateDeltaX(seconds); double deltaY = calculateDeltaY(seconds); double x = afv.getX(); double y = afv.getY(); Location loc = collisionAt(afv, x, y, deltaX, deltaY, map); if (loc != null) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); TerrainType type1 = map.get(loc.getX(), loc.getY()); afv.getController().sendMessage(" Collision:" + type1.getName() + ":" + loc.getX() + ":" + loc.getY()); return; } Location l3 = collidedWithTank(afv, x + deltaX, y + deltaY); if (l3 != null) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); return; } afv.updateLocation(deltaX, deltaY); // Always reset to 0 afv.setSpeedMPS(0.0); afv.setThrottle(0.0); } public double calculateDeltaX(double seconds) { if (afv.getSpeed() == 0.0) return 0.0; return Math.sin(Math.toRadians(afv.getHeading())) * Parameters.getFeatureSize(); } public double calculateDeltaY(double seconds) { if (afv.getSpeed() == 0.0) return 0.0; return Math.cos(Math.toRadians(afv.getHeading())) * Parameters.getFeatureSize() * -1; } } *************************************************************************************** RealisticAFVMover.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; public class RealisticAFVMover extends AFVMover { public RealisticAFVMover(AFV afv) { super(afv); } public void move(double seconds) { double newSpeed = 0.0; afv.turn(seconds); Map map = Battlefield.getMap(); TerrainType type = map.get(afv.getX(), afv.getY()); double maxSpeed = afv.getMaxSpeed(); double desiredSpeed = afv.getDesiredSpeedMPS(); double p = type.getPassibility(); maxSpeed = maxSpeed * p; desiredSpeed = desiredSpeed * p; newSpeed = desiredSpeed; afv.setSpeedMPS(newSpeed); double deltaX = calculateDeltaX(seconds); double deltaY = calculateDeltaY(seconds); double x = afv.getX(); double y = afv.getY(); if (!afv.isTreadOperational()) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); return; } Location loc = collisionAt(afv, x, y, deltaX, deltaY, map); if (loc != null) { afv.setSpeedMPS(0.0); afv.setThrottle(0.0); TerrainType type1 = map.get(loc.getX(), loc.getY()); afv.getController().sendMessage( " Collision:" + type1.getName() + ":" + loc.getX() + ":" + loc.getY()); return; } afv.updateLocation(deltaX, deltaY); } } *************************************************************************************** RealisticProjectileMover.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.Logger; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.afv.Velocity; import acsl.dTank.battle.BattleInitializer; import acsl.dTank.battle.Battlefield; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.ServerControlPanel; public class RealisticProjectileMover extends ProjectileMover { private static final double DECELERATION_PER_SECOND = 0.25; // 20% per Sec public RealisticProjectileMover(Projectile projectile) { this.projectile = projectile; } public void move(double seconds) { if (projectile.isExploded()) { long time = System.currentTimeMillis(); if ((time - projectile.getExplodeTime()) > 1000) Battlefield.removeProjectile(this); return; } Velocity v = projectile.getVelocity(); double speed = v.getSpeedMPS(); if (speed < 200.0) { String msg = projectile.getName() + " hit ground at " + Utility.shorten(speed) + " m/s."; Logger.log(msg); ServerControlPanel.writeDisplayMessage(msg); // This doesn't make any sense. You don't destroy dirt. If you want a crator, put one there! -Bil TerrainType tt = Battlefield.getMap().get(projectile.getX(),projectile.getY()); // DamageController.damageTarget(tt,projectile); // if(tt.isDestroyed()){ Battlefield.getMap().set(projectile.getX(),projectile.getY(),tt.lower()); // BattleInitializer.forceRepaintAll(); // } projectile.explode(); return; } v.setSpeedMPS(speed - (DECELERATION_PER_SECOND * seconds * speed)); double deltaX = v.calculateDeltaX(seconds); double deltaY = v.calculateDeltaY(seconds); double x = projectile.getX(); double y = projectile.getY(); Map map = Battlefield.getMap(); Location loc = collisionAt(null, x, y, deltaX, deltaY, map); if (loc != null) { projectile.update(deltaX, deltaY); String msg = projectile.getName() + " hit terrain"; Logger.log(msg); ServerControlPanel.writeDisplayMessage(msg); TerrainType tt = Battlefield.getMap().get(loc); // DamageController.damageTarget(tt,projectile); // if(tt.isDestroyed()){ Battlefield.getMap().set(loc,tt.lower()); BattleInitializer.forceRepaintAll(); // } projectile.explode(); return; } AFV afv = hitTarget(x, y, deltaX, deltaY); if (afv != null) { projectile.update(deltaX, deltaY); double energy = projectile.getEnergy(); String msg = projectile.getName() + " hit " + afv.getName() + " at " + Utility.shorten(speed) + " m/s with " + Utility.shorten(energy/1000) +" mg-m/s^2"; // + "M {" + Utility.shorten(x + deltaX) + ", " + Utility.shorten(y + deltaY) + "}"; Logger.log(msg); ServerControlPanel.writeDisplayMessage(msg); DamageController.damageTarget(afv, projectile); projectile.explode(); return; } if (projectile.hasExceededIntendedRange()) { String msg = projectile.getName() + " exceeded intended range of: " + Utility.shorten(projectile.getIntendedRange()); Logger.log(msg); // ServerControlPanel.writeDisplayMessage(msg); TerrainType tt = Battlefield.getMap().get(projectile.getX(),projectile.getY()); // DamageController.damageTarget(tt,projectile); // if(tt.isDestroyed()){ Battlefield.getMap().set(projectile.getX(),projectile.getY(),tt.lower()); BattleInitializer.forceRepaintAll(); // } projectile.explode(); return; } projectile.update(deltaX, deltaY); } } *************************************************************************************** ScanAFVsTest.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.MagicAFVController; import junit.framework.TestCase; public class ScanAFVsTest extends TestCase { private static final String SCAN1 = " AFV:Blue:OK:100.0:500.0:0.0:0.0:Sherman"; private static final String SCAN2 = " AFV:Blue:OK:100.0:550.0:0.0:0.0:Sherman"; AFV afv0, afv1; AFVMover mover0, mover1; public void setUp() { Battlefield.create("testMaps/empty10x10.map", 1000.0, 1000.0); } public void test1() { afv0 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr2", Nationality.BLUE, null)); afv1 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr3", Nationality.BLUE, null)); // System.out.println(afv0 + " " + afv1); Battlefield.addTank(afv0); Battlefield.addTank(afv1); afv0.setTurretHeading(270.0); afv0.setDesiredTurretHeading(270.0); afv0.setLocation(900.0, 500.0); AFVMover m = Battlefield.getAFVMover(0); { afv1.setLocation(100, 500); String msg = m.scanForAFVs(); assertEquals(SCAN1, msg); } { afv1.setLocation(100, 550); String msg = m.scanForAFVs(); assertEquals(SCAN2, msg); } { afv1.setLocation(100, 900); String msg = m.scanForAFVs(); assertEquals(null, msg); } } public static void main(String[] args) { System.out.println("==========ScanAFVsTest=========="); ScanAFVsTest test = new ScanAFVsTest(); test.setUp(); test.test1(); } } *************************************************************************************** ScanMovingThingsTest.java *************************************************************************************** package acsl.dTank.mover; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.MagicAFVController; import acsl.dTank.projectile.Projectile; import junit.framework.TestCase; public class ScanMovingThingsTest extends TestCase { private static final String SCAN1 = " Projectile:InFlight:850.0:500.0"; private static final String SCAN2 = " Projectile:InFlight:800.0:500.0"; private static final String SCAN4 = null; AFV afv0, afv1; AFVMover mover0, mover1; public void setUp() { Battlefield.create("testMaps/test10x10.map", 1000.0, 1000.0); } public void test1() { afv0 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr2", Nationality.BLUE, null)); afv1 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr3", Nationality.BLUE, null)); // System.out.println(afv0 + " " + afv1); Battlefield.addTank(afv0); afv0.setTurretHeading(270.0); afv0.setDesiredTurretHeading(270.0); afv0.setLocation(900.0, 500.0); Projectile p = Projectile.create(afv0, 270.0); Battlefield.addProjectile(p); AFVMover m = Battlefield.getAFVMover(0); { p.update(-50, 0); String msg = m.scanForProjectiles(); assertEquals(SCAN1, msg); } { p.update(-50, 0); String msg = m.scanForProjectiles(); assertEquals(SCAN2, msg); } { p.update(-50, -500); String msg = m.scanForProjectiles(); assertEquals(SCAN4, msg); } } public static void main(String[] args) { System.out.println("==========ScanMovingThingsTest=========="); ScanMovingThingsTest test = new ScanMovingThingsTest(); test.setUp(); test.test1(); } } *************************************************************************************** ScanTest.java *************************************************************************************** package acsl.dTank.mover; import junit.framework.TestCase; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.MagicAFVController; public class ScanTest extends TestCase { private static final String SCAN0 = ""; private static final String SCAN1 = " LOW_HILL:500.0:450.0"; private static final String SCAN2 = " STONE:350.0:850.0"; private static final String SCAN3 = " STONE:350.0:400.0"; private static final String SCAN4 = " STONE:350.0:850.0 STONE:750.0:900.0"; private static final String SCAN5 = " AFV:Blue:OK:300.0:900.0:0.0:270.0:Sherman"; AFV afv0, afv1; AFVMover mover0, mover1; public void setUp() { // Server.TESTING=true; Battlefield.create("testMaps/test20x20.map", 1000.0, 1000.0); afv0 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr2", Nationality.BLUE, null)); afv0.setLocation(949.0, 500.0); afv1 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr3", Nationality.BLUE, null)); afv1.setLocation(949.0, 500.0); Battlefield.addTank(afv0); mover0 = Battlefield.getAFVMover(0); assertEquals(afv0, mover0.getAFV()); assertEquals(949.0, afv0.getX(), 0.01); assertEquals(500.0, afv0.getY(), 0.01); } public void test1() { afv0.setLocation(949.0, 500.0); afv0.setTurretHeading(0.0); String s = mover0.scanForTerrain(); assertEquals(SCAN0, s); afv0.setLocation(510.0, 510.0); afv0.setTurretHeading(0.0); String s1 = mover0.scanForTerrain(); assertEquals(SCAN1, s1); afv0.setLocation(500.0, 500.0); afv0.setTurretHeading(180.0); String s2 = mover0.scanForTerrain(); assertEquals(SCAN2, s2); afv0.setLocation(500.0, 500.0); afv0.setTurretHeading(270.0); String s3 = mover0.scanForTerrain(); assertEquals(SCAN3, s3); // hide woods behind av1 Battlefield.addTank(afv1); mover1 = Battlefield.getAFVMover(1); afv0.setLocation(0.0, 900.0); afv0.setTurretHeading(110.0); afv1.setLocation(300.0, 900.0); afv1.setTurretHeading(270.0); String s4 = mover0.scanForTerrain(); assertEquals(SCAN4, s4); String s5 = mover0.scanForAFVs(); assertEquals(SCAN5, s5); } public static void main(String[] args) { System.out.println("==========ScanTest=========="); ScanTest test = new ScanTest(); test.setUp(); test.test1(); System.out.println("==========End ScanTest=========="); } } *************************************************************************************** Projectile.java *************************************************************************************** /** * A projectile (shell) needs to know who fired it, where it's headed, etc. It * also is responsible for its images, which change as it explodes (to make pretty * on the display). It's not clear the projectile should know about its images. (What's * better?) */ package acsl.dTank.projectile; import java.awt.Image; import javax.swing.ImageIcon; import acsl.dTank.Utility; import acsl.dTank.afv.AFV; import acsl.dTank.afv.Location; import acsl.dTank.afv.Velocity; import acsl.dTank.battle.Simulation; public class Projectile { private static final String bodyImageFilename = "orangemunit.gif"; // orangemunit private static final String exploded1ImageFilename = "munexp1.gif"; private static final String exploded2ImageFilename = "munexp2.gif"; private static final String exploded3ImageFilename = "munexp3.gif"; private static final String exploded4ImageFilename = "munexp4.gif"; private static final String exploded5ImageFilename = "orangemunit.gif"; private AFV afv; private Location location; private Velocity velocity; private boolean exploded = false; private long createTime, explodeTime; private double mass; private static int count = 0; private String name; private static Image bodyImage, exploded1Image, exploded2Image, exploded3Image, exploded4Image, exploded5Image; private double intendedRange; private Location originalLocation; public Projectile() { } public Projectile(AFV afv, double gunDirection, double gunElevation, double x, double y) { this(afv, gunDirection, gunElevation, x, y, Double.MAX_VALUE); } public Projectile(AFV afv, double gunDirection, double gunElevation, double x, double y, double intendedRange) { this.afv = afv; this.mass = afv.getProjectileMass(); double muzzleVelocity = afv.getAFVType().getMuzzleVelocity(); this.velocity = new Velocity(gunDirection, gunElevation, muzzleVelocity); this.location = new Location(x, y); this.originalLocation = new Location(x, y); this.name = "Projectile_" + afv.getName() + "_" + count++; this.intendedRange = intendedRange; this.createTime = System.currentTimeMillis(); //this.createTime = Simulation.getBattleTime(); } public static Projectile create(AFV afv, double heading, double intendedRange) { Projectile p = new Projectile(afv, heading, afv.getGunElevation(), afv.getX(), afv.getY(), intendedRange); return p; } public static Projectile create(AFV afv, double heading) { return create(afv, heading, Double.MAX_VALUE); } public Velocity getVelocity() { return velocity; } public void update(double deltaX, double deltaY) { location.update(deltaX, deltaY); } public static void initializeImages(int fs) { bodyImage = (new ImageIcon(ClassLoader.getSystemResource("images/" + bodyImageFilename))).getImage() .getScaledInstance(fs, fs, 0); exploded1Image = (new ImageIcon(ClassLoader.getSystemResource("images/" + exploded1ImageFilename))).getImage() .getScaledInstance(fs, fs, 0); exploded2Image = (new ImageIcon(ClassLoader.getSystemResource("images/" + exploded2ImageFilename))).getImage() .getScaledInstance(fs, fs, 0); exploded3Image = (new ImageIcon(ClassLoader.getSystemResource("images/" + exploded3ImageFilename))).getImage() .getScaledInstance(fs, fs, 0); exploded4Image = (new ImageIcon(ClassLoader.getSystemResource("images/" + exploded4ImageFilename))).getImage() .getScaledInstance(fs, fs, 0); exploded5Image = (new ImageIcon(ClassLoader.getSystemResource("images/" + exploded5ImageFilename))).getImage() .getScaledInstance(01, 01, 0); } public double getY() { return location.getY(); } public double getX() { return location.getX(); } public Image getImage() { //long time = Simulation.getBattleTime(); long time = System.currentTimeMillis(); // suppressive fire code. /** * if(suppressive == true){ //the percentage of suppressive fire is assigned in if (exploded) { // * RealisticAFVController.accept(...) method. * * if ((time - explodeTime) > 1900) return impact4Image; if ((time - explodeTime) > 1500) return impact3Image; * if ((time - explodeTime) > 1000) return impact2Image; if ((time - explodeTime) > 500) return impact1Image; * * return impactImage; } * * if((time - createTime) < 150){ //muzzle flash return muzzleImage; } * * return bodyImageSup; * * }else{ */ if (exploded) { if ((time - explodeTime) > 800) return exploded5Image; if ((time - explodeTime) > 600) return exploded4Image; if ((time - explodeTime) > 400) return exploded3Image; if ((time - explodeTime) > 200) return exploded2Image; return exploded1Image; } return bodyImage; } public static Image getImage(String state) { if (state.equals("Exploded5")) return exploded5Image; if (state.equals("Exploded4")) return exploded4Image; if (state.equals("Exploded3")) return exploded3Image; if (state.equals("Exploded2")) return exploded2Image; if (state.equals("Exploded1")) return exploded1Image; return bodyImage; } public String getState() { if (exploded) { long time = System.currentTimeMillis(); //long time = Simulation.getBattleTime(); if ((time - explodeTime) > 800) return "Exploded5"; if ((time - explodeTime) > 600) return "Exploded4"; if ((time - explodeTime) > 400) return "Exploded3"; if ((time - explodeTime) > 200) return "Exploded2"; return "Exploded1"; } return "InFlight"; } public void explode() { exploded = true; velocity.setSpeedKPH(0.0); //explodeTime = Simulation.getBattleTime(); explodeTime = System.currentTimeMillis(); } public boolean isExploded() { return exploded; } public long getExplodeTime() { return explodeTime; } public AFV getAFV() { return afv; } public static Image getBaseImage() { return bodyImage; } public double getMass() { return mass; } public String getName() { return name; } public boolean hasExceededIntendedRange() { if (Utility.distance(originalLocation, location) > intendedRange) return true; return false; } public double getIntendedRange() { return intendedRange; } /** * Applies the kinetic energy formula:
* E = 1/2 * mass * speed^2
* Mass and speed must be in Kg and mps * @return the energy in Jouls */ public double getEnergy() { //this is the old "energy" expression but I'm not sure what it refers to //double energy = velocity.getSpeedMPS() * velocity.getSpeedMPS() * mass/1000000; double energy = 0.5*Math.pow(velocity.getSpeedMPS(),2)*mass; return energy; } } *************************************************************************************** FollowEnemyAtParser.java *************************************************************************************** package acsl.dTank.radioMessage; public class FollowEnemyAtParser extends RadioParser{ FollowEnemyAtParser() { super("FollowEnemyAt", 2); } public void parse(String[] tokens, int i, RadioMessage message) { message.setFollowEnemyAt(tokens[i],tokens[i+1]); } } *************************************************************************************** FromParser.java *************************************************************************************** package acsl.dTank.radioMessage; public class FromParser extends RadioParser { FromParser() { super("From", 1); } public void parse(String[] tokens, int i, RadioMessage message) { message.setFrom(tokens[i]); } } *************************************************************************************** RadioMessage.java *************************************************************************************** package acsl.dTank.radioMessage; import acsl.dTank.Utility; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.commander.BattalionLieutenantCommander; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.InformationMessage; public class RadioMessage { private static final String DELIMITORS = "[|]"; private String input; private double y; private double x; private String from; // public static RadioMessage create(String input) { RadioMessage m = new RadioMessage(); m.input = input; String[] tokens = InformationMessage.dropBlanks(input.split(DELIMITORS)); int len = tokens.length; for (int i = 0; i < len;) { i += m.parse(tokens, i); } return m; } private int parse(String[] tokens, int i) { String typeString = tokens[i]; RadioParser p = RadioParser.lookup(typeString); if (p == null) throw new RuntimeException("Unknown command " + typeString); p.parse(tokens, i + 1, this); return p.getNArgs() + 1; // loc of next cmd } public void setFollowEnemyAt(String xString, String yString) { x = Double.parseDouble(xString); y = Double.parseDouble(yString); } public double getY() { return y; } public double getX() { return x; } public void setFrom(String from) { this.from=from; } public void processMessage(BattalionLieutenantCommander commander) { commander.setCurrentTarget (new DetectedAFV(Nationality.opposite(commander.getAFVModel().getNationality()), false, getX(), getY(), 0.0, 0.0, AFVType.SHERMAN)); commander.writeDisplayMessage("FollowEnemyAt " + Utility.shorten(getX()) + " " + Utility.shorten(getX())); } } *************************************************************************************** RadioParser.java *************************************************************************************** package acsl.dTank.radioMessage; import java.util.HashMap; public abstract class RadioParser { private static HashMap radioTypes = new HashMap(); private String name; private int nArgs; public abstract void parse(String[] tokens, int i, RadioMessage message); public RadioParser(String name, int nArgs) { this.name = name; this.nArgs = nArgs; } public static void initialize() { initialize(new FromParser()); initialize(new FollowEnemyAtParser()); } public static void initialize(RadioParser p) { radioTypes.put(p.getName(), p); } private String getName() { return name; } public static RadioParser lookup(String typeString) { return (RadioParser) radioTypes.get(typeString); } public int getNArgs() { return nArgs; } } *************************************************************************************** Server.java *************************************************************************************** /** * The server opens a listener on the port and creates a new ServerSocketCommunicator (for * socket connections) to communicate with the commander. It also accepts commanders that * want to communicate directely via the DirectCommunicator. */ package acsl.dTank.server; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import javax.net.ServerSocketFactory; import acsl.dTank.Parameters; import acsl.dTank.communicator.CommanderDirectCommunicator; import acsl.dTank.communicator.ServerDebuggerSocketCommunicator; import acsl.dTank.communicator.ServerDirectCommunicator; import acsl.dTank.communicator.ServerSocketCommunicator; public class Server implements Runnable { public static boolean alreadyRunning = false; private static ServerSocket listenSocket; private static ServerSocket controlSocket; public synchronized static void startPortListener() { if (alreadyRunning) return; alreadyRunning = true; try { listenSocket = ServerSocketFactory.getDefault() .createServerSocket(); listenSocket.setReuseAddress(true); InetSocketAddress address = new InetSocketAddress(Parameters .getPort()); listenSocket.bind(address); new Thread(new Server(), "Server").start(); controlSocket = ServerSocketFactory.getDefault() .createServerSocket(); controlSocket.setReuseAddress(true); InetSocketAddress controlAddress = new InetSocketAddress(Parameters .getPort()+1); controlSocket.bind(controlAddress); new Thread(new Server() { public void run() { runController(); } }, "Controller").start(); } catch (Exception e) { System.err.println("Error while starting the server: " + e); e.printStackTrace(); System.exit(1); } } void runController() { try { while (true) { Socket socket = controlSocket.accept(); ServerDebuggerSocketCommunicator.create(socket); } } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public void run() { try { while (true) { Socket socket = listenSocket.accept(); ServerSocketCommunicator.create(socket); } } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public static ServerDirectCommunicator registerCommander( CommanderDirectCommunicator communicator) { return ServerDirectCommunicator.create(communicator); } } *************************************************************************************** AboutPage.java *************************************************************************************** package acsl.dTank.ui; import java.awt.*; import java.awt.event.*; import javax.swing.*; import acsl.dTank.Parameters; public class AboutPage extends JFrame implements ActionListener { private JButton button; private JPanel panel; private JLabel versionLabel, sponsor, contractNo, contact; public AboutPage(){ this.setTitle("dTank Version:" + Parameters.getReleaseDate()); } public static void main(String[] args) { AboutPage frame = new AboutPage(); frame.setSize(300, 280); //width, height frame.setLocation(200, 200); frame.createGUI(); frame.setVisible(true); } private void createGUI() { setDefaultCloseOperation(EXIT_ON_CLOSE); Container window = getContentPane(); //window.setLayout(new BoxLayout(window, BoxLayout.Y_AXIS)); window.setLayout(new BorderLayout()); Dimension minSize = new Dimension(20, 20); Dimension prefSize = new Dimension(20, 20); Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); //window.add(new Box.Filler(minSize, prefSize, maxSize)); versionLabel = new JLabel("For info/updates: http://acs.ist.psu.edu/dTank"); sponsor= new JLabel("Project Sponsored by: Office of Naval Research "); contractNo = new JLabel("Contract #: N00014-02-1-0021 & N00014-06-1-0164"); contact = new JLabel("Contact Person: frank.ritter@psu.edu "); Container window0 = new Container(); window0.setLayout(new BorderLayout()); //window0.add(Box.createRigidArea(new Dimension(100, 0)), BorderLayout.WEST); //window0.add(Box.createRigidArea(new Dimension(100, 0)), BorderLayout.EAST); window0.add(sponsor, BorderLayout.NORTH); window0.add(contractNo, BorderLayout.CENTER); window0.add(Box.createRigidArea(new Dimension(10, 10)), BorderLayout.SOUTH); window.add(window0,BorderLayout.NORTH); ImagePanel panel = new ImagePanel(); window.add(panel,BorderLayout.CENTER); Container window1 = new Container(); window1.setLayout(new BorderLayout()); //window1.add(Box.createRigidArea(new Dimension(100, 0)), BorderLayout.WEST); //window1.add(Box.createRigidArea(new Dimension(100, 0)), BorderLayout.EAST); window1.add(versionLabel, BorderLayout.NORTH); window1.add(contact, BorderLayout.CENTER); button = new JButton("OK"); window1.add(button, BorderLayout.SOUTH); button.addActionListener(this); window.add(window1,BorderLayout.SOUTH); } public void actionPerformed(ActionEvent event) { this.setVisible(false); } public class ImagePanel extends JPanel { Image img; public ImagePanel() { setSize(400,400); setVisible(true); img = Toolkit.getDefaultToolkit().getImage("images/logo.gif"); } public void paint(Graphics g) { g.drawImage(img,0,0,this); } } } *************************************************************************************** CommanderControlPannel.java *************************************************************************************** /* * This is just like the ServerControlPanel, except that it also takes mouse * input and forwards their information to the Commander. */ package acsl.dTank.ui; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.image.BufferedImage; import java.util.HashMap; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.SpringLayout; import acsl.dTank.Parameters; import acsl.dTank.SpringUtilities; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Simulation; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; import acsl.dTank.informationMessage.DetectedAFV; import acsl.dTank.informationMessage.parser.ProjectileParser; import acsl.dTank.map.CommanderMap; import acsl.dTank.map.TerrainType; import acsl.dTank.projectile.Projectile; import acsl.dTank.ui.ServerControlPanel.ServerButtonListener; public class CommanderControlPanel extends JFrame implements ControlPanel { public static int DISPLAY_SIZE = 500; private static int displayFeatureSize; protected static CommanderControlPanel controlPanel; private JPanel contentPane; private JPanel mapPanel = new JPanel(); private JPanel statusPanel = new JPanel(new SpringLayout()); private JLabel headingLabel = new JLabel(); private JLabel speedLabel = new JLabel(); private JLabel destroyedLabel = new JLabel(); private JLabel ammunitionLabel = new JLabel(); private JLabel armorDamageLabel = new JLabel(); private JLabel timeLabel = new JLabel(); private JLabel radioLabel = new JLabel(); private JLabel crewLabel = new JLabel(); private JLabel fuelRemainingLabel = new JLabel(); private JButton clientInfoButton = new JButton(); private JTextArea messagesArea = new JTextArea(); private double physicalFeatureSize; private CommanderMap map; private Image backgroundImage; private int widthInFeatures, heightInFeatures; private double widthPhysical, heightPhysical; private BufferedImage tmpImage; private CommanderDisplayLoop displayLoop; private AFVModel afvModel; private Commander commander; private String cmdrName; private int panelHeight; private int panelWidth; private Image destroyedImage; private HashMap blueBodyImages = new HashMap(), redBodyImages = new HashMap(), whiteBodyImages = new HashMap(); private HashMap blueTurretImages = new HashMap(), redTurretImages = new HashMap(), whiteTurretImages = new HashMap(); private JButton pauseButton, resetButton; JCheckBox realTimeBox; private JButton stepButton; public CommanderControlPanel(CommanderMap map, Commander commander, AFVModel afvModel) { this.map = map; this.commander = commander; if (afvModel == null) return; this.afvModel = afvModel; this.cmdrName = afvModel.getName(); } public static CommanderControlPanel create(CommanderMap map, Commander commander, AFVModel afvModel) { controlPanel = new CommanderControlPanel(map, commander, afvModel); controlPanel.initialize(); // Make textField get the focus whenever frame is activated. controlPanel.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { controlPanel.requestFocusInWindow(); } }); controlPanel.show(); return controlPanel; } void paintFov(Graphics g) { Graphics2D g2d = (Graphics2D) g; double turretAngle = afvModel.getTurretHeading(); int humanX = convertPos(afvModel.getX()); int humanY = convertPos(afvModel.getX()); // translate human tank's x, y by a few so we can see ourselves double transX = Math.cos(turretAngle) * 50; double transY = Math.sin(turretAngle) * 50; humanX -= transX; humanY -= transY; // draw left part of cone GeneralPath cutout = new GeneralPath(); cutout.moveTo(0, 0); cutout.lineTo(1000f * (float) Math.cos(0.5), -1000); // cutout.lineTo(600,-600); cutout.lineTo(-1000, -1000); cutout.lineTo(-1000, 1000); // cutout.lineTo(600,600); cutout.lineTo(1000f * (float) Math.cos(0.5), 1000); cutout.lineTo(0, 0); cutout.closePath(); g2d.setPaint(Color.GRAY); AffineTransform at = g2d.getTransform(); at.translate(humanX, humanY); at.rotate(turretAngle, 0, 0); g2d.setTransform(at); g2d.fill(cutout); } public void paint(Graphics g) { super.paint(g); createBackgroundImage(); Graphics2D tg = tmpImage.createGraphics(); paintBackground(tg); Graphics mg = mapPanel.getGraphics(); paintMovingObjects(tg); // paintFov(mg); boolean z = false; while (!z) z = mg.drawImage(tmpImage, 0, 0, this); tg.dispose(); mg.dispose(); } // public void update(Graphics g) { // if (true||getWidth() != panelWidth || getHeight() != panelHeight) { // panelWidth = getWidth(); // panelHeight = getHeight(); // paint(g); // return; // } // // Graphics g1 = mapPanel.getGraphics(); // // paintMovingObjects((Graphics2D) g1); // // g1.dispose(); // } void initialize() { displayLoop = new CommanderDisplayLoop(this, afvModel, commander, timeLabel, destroyedLabel, ammunitionLabel, armorDamageLabel, radioLabel, crewLabel, fuelRemainingLabel, headingLabel, speedLabel, messagesArea); widthInFeatures = map.getWidthInFeatures(); heightInFeatures = map.getWidthInFeatures(); widthPhysical = map.getWidthPhysical(); heightPhysical = map.getWidthPhysical(); physicalFeatureSize = map.getFeatureSize(); displayFeatureSize = DISPLAY_SIZE / widthInFeatures; DISPLAY_SIZE = displayFeatureSize * widthInFeatures; if (widthInFeatures > DISPLAY_SIZE) throw new RuntimeException( "Not enough pixels to display all features. " + widthInFeatures + " > " + DISPLAY_SIZE); // if ((DISPLAY_SIZE % widthInFeatures) != 0) // throw new RuntimeException("Gonna be an ugly display: " + // widthInFeatures + " > " + DISPLAY_SIZE); backgroundImage = getGraphicsConfiguration().createCompatibleImage( DISPLAY_SIZE, DISPLAY_SIZE); Projectile.initializeImages(displayFeatureSize); TerrainType.initializeImages(displayFeatureSize); createBackgroundImage(); createOffscreenImages(); destroyedImage = (new ImageIcon(ClassLoader .getSystemResource("images/wreck.gif"))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); initializeWindow(); mapPanel.addMouseListener(new CommanderMouseListener(commander)); this.getKeyListeners(); this.addKeyListener(new CommanderKeyListener(commander)); } void createBackgroundImage() { Graphics g1 = backgroundImage.getGraphics(); for (int y = 0; y <= widthInFeatures; y++) { for (int x = 0; x <= widthInFeatures; x++) { Image image = map.get(x * physicalFeatureSize, y * physicalFeatureSize).getImage(); boolean z = false; while (!z) z = g1.drawImage(image, x * displayFeatureSize, y * displayFeatureSize, this); } } g1.dispose(); } void paintBackground(Graphics g) { boolean z = false; while (!z) z = g.drawImage(backgroundImage, 0, 0, null); } private void paintMovingObjects(Graphics2D g) { synchronized (map) { // for (int i = 0, size = map.getNPreviousAFVs(); i < size; i++) { // DetectedAFV a = map.getPreviousAFV(i); // a.unpaint(g, this, map.getFeatureSize()); // } // System.out.println("n"); for (int i = 0, size = map.getNAFVs(); i < size; i++) { DetectedAFV a = map.getAFV(i); a.paint(g, this, map.getFeatureSize()); } for (int i = 0, size = map.getNProjectiles(); i < size; i++) { ProjectileParser m = map.getProjectile(i); m.paint(g, this); } } } private void createOffscreenImages() { tmpImage = getGraphicsConfiguration().createCompatibleImage( DISPLAY_SIZE + 50, DISPLAY_SIZE + 50); BufferedImage oldOffscreen = getGraphicsConfiguration() .createCompatibleImage(30, 30); } private void initializeWindow() { this.setVisible(false); this.setSize(425 + DISPLAY_SIZE, 57 + DISPLAY_SIZE); this.setTitle("dTank " + Parameters.getVersion() + " - " + Parameters.getReleaseDate()); this.setResizable(true); // Center the frame on the desktop. Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); this.setLocation( (int) (0.4 * screenSize.width - 0.5 * this.getWidth()), (int) (0.4 * screenSize.height - 0.5 * this.getHeight())); contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS)); contentPane.setBackground(Color.gray); contentPane.setBorder(BorderFactory.createRaisedBevelBorder()); mapPanel.setBackground(Color.white); mapPanel.setBorder(BorderFactory.createRaisedBevelBorder()); mapPanel.setSize(DISPLAY_SIZE + 50, DISPLAY_SIZE); mapPanel.setMinimumSize(new Dimension(DISPLAY_SIZE + 50, DISPLAY_SIZE)); contentPane.add(mapPanel); JPanel controlPanel = new JPanel(new SpringLayout()); contentPane.add(controlPanel); JLabel titleLabel = new JLabel(); titleLabel.setFont(new java.awt.Font("Serif", 1, 16)); titleLabel.setText(" Commander Information"); controlPanel.add(titleLabel); statusPanel.setBorder(BorderFactory.createRaisedBevelBorder()); statusPanel.setMaximumSize(new Dimension(300, DISPLAY_SIZE)); headingLabel.setText("Heading"); speedLabel.setText("Speed"); destroyedLabel.setText("Operative"); ammunitionLabel.setText("Ammunition: 90"); armorDamageLabel.setText("ArmorDamage: 0.0"); crewLabel.setText("crew"); radioLabel.setText("radio"); fuelRemainingLabel.setText("fuel"); timeLabel.setFont(new java.awt.Font("Serif", 1, 16)); timeLabel.setText("Time: 0"); statusPanel.add(headingLabel); statusPanel.add(speedLabel); statusPanel.add(destroyedLabel); statusPanel.add(ammunitionLabel); statusPanel.add(armorDamageLabel); statusPanel.add(crewLabel); statusPanel.add(radioLabel); statusPanel.add(fuelRemainingLabel); statusPanel.add(new JLabel(" ")); statusPanel.add(timeLabel); controlPanel.add(statusPanel); statusPanel.add(new JLabel(" ")); JLabel messagesLabel = new JLabel(); messagesLabel.setFont(new java.awt.Font("Serif", 1, 16)); messagesLabel.setText("Messages:"); statusPanel.add(messagesLabel); messagesArea.setBorder(BorderFactory.createLoweredBevelBorder()); messagesArea.setEditable(false); messagesArea.setText(" dTank 4"); messagesArea.setRows(5); messagesArea.setColumns(20); statusPanel.add(messagesArea); SpringUtilities.makeCompactGrid(statusPanel, 13, 1, 6, 6, 6, 6); JPanel stepPanel = new JPanel(new SpringLayout()); ActionListener listener = new CommanderButtonListener(); pauseButton = new JButton("Pause/Resume"); stepPanel.add(pauseButton); pauseButton.addActionListener(listener); resetButton = new JButton("Reset"); stepPanel.add(resetButton); resetButton.addActionListener(listener); stepButton = new JButton("Step"); stepPanel.add(stepButton); stepButton.addActionListener(listener); realTimeBox = new JCheckBox("Real time"); stepPanel.add(realTimeBox); realTimeBox.addActionListener(listener); SpringUtilities.makeCompactGrid(stepPanel, 1, 4, 6, 6, 6, 6); controlPanel.add(stepPanel); SpringUtilities.makeCompactGrid(controlPanel, 3, 1, 6, 6, 6, 6); } public int convertPos(double y) { // From meters to pixels return (int) ((y / heightPhysical) * DISPLAY_SIZE); } public static int getDisplayFeatureSize() { return displayFeatureSize; } public void redisplay() { displayLoop.redisplay(); } public Image getBackgroundImage() { return backgroundImage; } public Image getBodyImage(DetectedAFV afv) { if (afv.isDestroyed()) return destroyedImage; Nationality n = afv.getNationality(); return getBodyImage(n, afv); } public Image getTurretImage(DetectedAFV afv) { if (afv.isDestroyed()) return destroyedImage; Nationality n = afv.getNationality(); return getTurretImage(n, afv); } private Image getImage(Nationality n, DetectedAFV type, boolean returnBody) { HashMap bodyImages, turretImages; String c; if (n == Nationality.BLUE) { bodyImages = blueBodyImages; turretImages = blueTurretImages; c = "blue"; } else if (n == Nationality.WHITE) { bodyImages = whiteBodyImages; turretImages = whiteTurretImages; c = "white"; } else { bodyImages = redBodyImages; turretImages = redTurretImages; c = "red"; } Image bodyImage = (Image) bodyImages.get(type); Image turretImage = (Image) turretImages.get(type); if (bodyImage == null) { bodyImage = (new ImageIcon(ClassLoader.getSystemResource("images/" + c + type.getBodyImageFilename()))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); bodyImages.put(type, bodyImage); if (type.getBodyImageFilename().equals("tank.gif")) { turretImage = (new ImageIcon(ClassLoader .getSystemResource("images/" + c + type.getTurretImageFilename()))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); turretImages.put(type, turretImage); } } if (returnBody) return bodyImage; return turretImage; } private Image getTurretImage(Nationality n, DetectedAFV type) { return getImage(n, type, false); } private Image getBodyImage(Nationality n, DetectedAFV type) { return getImage(n, type, true); } class CommanderButtonListener implements ActionListener { private boolean paused; public void actionPerformed(ActionEvent e) { JComponent s = (JComponent) e.getSource(); if (s == pauseButton) { paused = !paused; commander.setPause(paused); } else if (s == stepButton) { commander.setStep(1); } else if (s == resetButton) { commander.setResetBattle(); } else if (s == realTimeBox) { commander.setRealTimeMode(realTimeBox.isSelected()); } } } } *************************************************************************************** COmmanderControlPanelTest.java *************************************************************************************** package acsl.dTank.ui; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintStream; import junit.framework.TestCase; import acsl.dTank.Initializer; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; import acsl.dTank.commander.SmartCommander; import acsl.dTank.communicator.CommanderSocketCommunicator; import acsl.dTank.map.CommanderMap; public class CommanderControlPanelTest extends TestCase { private String expectedInitialization = ""; private String initReply = ""; private String expectedRadioMessage = ""; private CommanderMap map; private Commander commander; private AFVModel afvModel; private CommanderSocketCommunicator commanderCommunicator; public void setUp() { startListener(); String[] args = new String[] { "Blue", "Sherman", "Display", "1", "arg0" }; Initializer.initializeAll(); map = CommanderMap.create(1000.0, 1000.0, 50.0); //commanderCommunicator = new CommanderSocketCommunicator(); //String cmdrName = "SmartCommander0"; //InformationMessage m = commanderCommunicator.initialize(Nationality.BLUE, AFVType.SHERMAN, cmdrName); commander = SmartCommander.create(args); afvModel = AFVModel.create(AFVType.SHERMAN, Nationality.BLUE); //CommanderControlPanel.create(map, commander, afvModel); } public void test1() { } public static void main(String[] args) { System.out.println("==========CommanderControlPanelTest=========="); CommanderControlPanelTest test = new CommanderControlPanelTest(); test.setUp(); test.test1(); } private void startListener() { TestListener sct = new TestListener() { void runTests(BufferedReader inStream, PrintStream outStream) throws IOException { String input = inStream.readLine(); TestCase.assertEquals(expectedInitialization, input); outStream.println(initReply); while (true) { input = inStream.readLine(); if (input.indexOf("Radio") != -1) break; } TestCase.assertEquals(expectedRadioMessage, input); } }; new Thread(sct).start(); sct.waitForReady(); } } *************************************************************************************** CommanderDisplayLoop.java *************************************************************************************** package acsl.dTank.ui; import javax.swing.JLabel; import javax.swing.JTextArea; import acsl.dTank.Parameters; import acsl.dTank.Utility; import acsl.dTank.battle.Battlefield; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; public class CommanderDisplayLoop { private JLabel timeLabel, destroyedLabel, ammunitionLabel, armorDamageLabel, crewLabel, radioLabel, fuelDamageLabel; private ControlPanel controlPanel; private AFVModel afvModel; private JTextArea messageTextArea; private Commander commander; private JLabel speedLabel; private JLabel headingLabel; public CommanderDisplayLoop(ControlPanel controlPanel, AFVModel afvModel, Commander commander, JLabel timeLabel, JLabel destroyedLabel, JLabel ammunitionLabel, JLabel armorDamageLabel, JLabel radioLabel, JLabel crewLabel, JLabel fuelDamageLabel, JLabel headingLabel, JLabel speedLabel, JTextArea connectionsArea) { this.afvModel = afvModel; this.controlPanel = controlPanel; this.timeLabel = timeLabel; this.destroyedLabel = destroyedLabel; this.ammunitionLabel = ammunitionLabel; this.armorDamageLabel = armorDamageLabel; this.radioLabel = radioLabel; this.crewLabel = crewLabel; this.headingLabel = headingLabel; this.speedLabel = speedLabel; this.fuelDamageLabel = fuelDamageLabel; this.messageTextArea = connectionsArea; this.commander = commander; } // public void run() { // // long startTime = System.currentTimeMillis(); // // long seconds = 0; // for (int i = 0; i < 100000; i++) { // try { // Thread.sleep(Parameters.getCommanderDisplayFrequency()); // } catch (InterruptedException e) { // e.printStackTrace(); // } // redisplay(); // } // // } void redisplay() { int seconds = commander.getGameTime() / 1000; timeLabel.setText("Time: " + seconds + "." + Battlefield.getGameTime() % 1000); armorDamageLabel.setText("Armor damage: " + Utility.shorten(afvModel.getArmorDamage())); fuelDamageLabel.setText("Fuel: " + Utility.shorten(afvModel.getFuel())); destroyedLabel.setText((afvModel.isDestroyed() ? "Destroyed" : "Operative")); radioLabel.setText("Radio:" + (afvModel.isRadioDestroyed() ? "destroyed" : "operating")); crewLabel.setText("Crew:" + (afvModel.isCrewHealthy() ? "healthy" : "dingy")); ammunitionLabel.setText("Ammunition:" + afvModel.getAmmunitionRemaining()); headingLabel.setText("Heading:" + afvModel.getHeading()); speedLabel.setText("Speed:" + afvModel.getSpeedKPH()); messageTextArea.setText(commander.getMessageString()); controlPanel.repaint(); } } *************************************************************************************** CommanderKeyListener.java *************************************************************************************** /** * All key strokes to a Commander's display are handled here. */ package acsl.dTank.ui; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import acsl.dTank.commander.Commander; public class CommanderKeyListener implements KeyListener { private Commander commander; public CommanderKeyListener(Commander commander) { this.commander = commander; } public void keyPressed(KeyEvent e) { // System.out.println(e); try { switch (e.getKeyCode()) { case KeyEvent.VK_UP: commander.incThrottle(); break; case KeyEvent.VK_DOWN: commander.decThrottle(); break; case KeyEvent.VK_RIGHT: commander.incDesiredHeading(); break; case KeyEvent.VK_LEFT: commander.decDesiredHeading(); break; case KeyEvent.VK_SPACE: commander.fireKeyStroke(); default: break; } } catch (Exception Ex) { } } public void keyTyped(KeyEvent arg0) { // TODO Auto-generated method stub } public void keyReleased(KeyEvent arg0) { // TODO Auto-generated method stub } } *************************************************************************************** CommanderKeyTest.java *************************************************************************************** package acsl.dTank.ui; import acsl.dTank.Initializer; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; import acsl.dTank.commander.SmartCommander; import acsl.dTank.map.CommanderMap; import junit.framework.TestCase; public class CommanderKeyTest extends TestCase { CommanderControlPanel ccp; public void setUp() { Initializer.initializeAll(); CommanderMap m = CommanderMap.create(1000.0, 1000.0, 50.0); Commander c = new SmartCommander(); AFVModel a = AFVModel.create(AFVType.KING_TIGER, Nationality.BLUE); ccp = CommanderControlPanel.create(m, c, a); } public void test1() { } public static void main(String[] args) { System.out.println("==========CommanderKeyTest=========="); CommanderKeyTest test = new CommanderKeyTest(); test.setUp(); test.test1(); } } *************************************************************************************** CommanderMouseListener.java *************************************************************************************** /** * All mouse clicks on the commander's display are handled here. */ package acsl.dTank.ui; import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; public class CommanderMouseListener implements MouseListener { private Commander commander; public CommanderMouseListener(Commander commander) { this.commander = commander; } /** * Sets the desired turret rotation of the human-controlled tank to the angle indicated by the current mouse * position. */ public void mousePressed(MouseEvent e) { Point mouse = e.getPoint(); AFVModel afvm = commander.getAFVModel(); double displayFeatureSize = CommanderControlPanel.getDisplayFeatureSize(); double fs = commander.getFeatureSize(); double humX = afvm.getX() + displayFeatureSize/2;// Tank position is NOT center of image double humY = afvm.getY() + displayFeatureSize/2; double mouseX = mouse.getX() / displayFeatureSize * fs; double mouseY = mouse.getY() / displayFeatureSize * fs; // System.out.println("x: " + humX + " y: " + humY); // System.out.println("mx: " + mouseX + " my: " + mouseY); double heading = calculateHeading(humX, humY, mouseX, mouseY); commander.setDesiredTurretHeadingEvent(heading); } public static double calculateHeading(double afvX, double afvY, double mouseX, double mouseY) { // Determine the x, y components of the angle. double dx = ((mouseX - afvX)); double dy = ((mouseY - afvY)); double heading; if (((dx >= 0) && (dy >= 0)) || ((dx < 0) && (dy < 0))) { heading = Math.atan(Math.abs(dy / dx)); } else { heading = Math.atan(Math.abs(dx / dy)); } // Adjust the angle to absolute positioning with 0 at north. if ((dx >= 0) && (dy >= 0)) { heading += Math.PI / 2; } if ((dx < 0) && (dy >= 0)) { heading += Math.PI; } if ((dx < 0) && (dy < 0)) { heading += 3 * Math.PI / 2; } return Math.toDegrees(heading); } public void mouseClicked(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseReleased(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } } *************************************************************************************** CommanderMouseListenerTest.java *************************************************************************************** package acsl.dTank.ui; import junit.framework.TestCase; public class CommanderMouseListenerTest extends TestCase { //private CommanderMouseListener listener; public void setUp() { // listener = new CommanderMouseListener(null); } public void test1() { { double h = CommanderMouseListener.calculateHeading(500.0, 500.0, 100.0, 500.0); assertEquals(270.0, h, 0.1); } { double h = CommanderMouseListener.calculateHeading(500.0, 500.0, 800.0, 500.0); assertEquals(90.0, h, 0.1); } { double h = CommanderMouseListener.calculateHeading(500.0, 500.0, 500.0, 100.0); assertEquals(0.0, h, 0.1); } { double h = CommanderMouseListener.calculateHeading(500.0, 500.0, 500.0, 800.0); assertEquals(180.0, h, 0.1); } { double h = CommanderMouseListener.calculateHeading(500.0, 500.0, 100.0, 100.0); assertEquals(315.0, h, 0.1); } } public static void main(String[] args) { System.out.println("==========CommanderMouseListenerTest=========="); CommanderMouseListenerTest test = new CommanderMouseListenerTest(); test.setUp(); test.test1(); } } *************************************************************************************** ControlPanel.java *************************************************************************************** package acsl.dTank.ui; public interface ControlPanel { int convertPos(double x); void repaint(); // A hack to allow controlPanel.repaint() WHAT'S THE RIGHT WAY?? } *************************************************************************************** DebuggerControlPanel.java *************************************************************************************** package acsl.dTank.ui; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import acsl.dTank.commander.AFVModel; import acsl.dTank.commander.Commander; import acsl.dTank.map.CommanderMap; // Nice idea, doesn't work. I won't spend the time to mess with the GUI. :-( public class DebuggerControlPanel extends CommanderControlPanel { public DebuggerControlPanel(CommanderMap map, Commander commander, AFVModel afvModel) { super(map, commander, afvModel); // TODO Auto-generated constructor stub } void initialize() { } public static DebuggerControlPanel create(CommanderMap map, Commander commander, AFVModel afvModel) { final DebuggerControlPanel controlPanel = new DebuggerControlPanel(map, commander, afvModel); controlPanel.initialize(); // Make textField get the focus whenever frame is activated. controlPanel.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { controlPanel.requestFocusInWindow(); } }); controlPanel.show(); return controlPanel; } private static final long serialVersionUID = 1L; } *************************************************************************************** ServerControlPanel.java *************************************************************************************** /* * This does the display for the server. It starts a separate thread to do the updates. * All the display images for AFVs are here, not in the AFVs themselves. */ package acsl.dTank.ui; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.SystemColor; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.SpringLayout; import acsl.dTank.Parameters; import acsl.dTank.SpringUtilities; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Battlefield; import acsl.dTank.battle.Simulation; import acsl.dTank.map.Map; import acsl.dTank.map.TerrainType; import acsl.dTank.mover.AFVMover; import acsl.dTank.mover.ProjectileMover; import acsl.dTank.projectile.Projectile; public class ServerControlPanel extends JFrame implements ControlPanel, WindowListener { private static final int CONTROL_PANEL_WIDTH_PX = 300; private static int DISPLAY_SIZE = 800; private static final int MESSAGE_WIDTH = 70; private static final int MAX_MESSAGES = 25; private static int displayFeatureSize; private static ServerControlPanel controlPanel; private static List displayMessages = new ArrayList(); private JSplitPane contentPane; private JPanel mapPanel = new JMapPanel(); private JButton quitButton = new JButton(); private JPanel statusPanel = new JPanel(new SpringLayout()); private JLabel gameSpeedLabel = new JLabel(); private JLabel secondsPerCycleLabel = new JLabel(); private JLabel mapDimensionsLabel = new JLabel(); private JLabel blueLabel = new JLabel(); private JLabel redLabel = new JLabel(); private JLabel whiteLabel = new JLabel(); private JLabel timeLabel = new JLabel(); // private JButton clientInfoButton = new JButton(); private JTextArea messageTextArea = new JTextArea(); private double physicalFeatureSize; private Map map; public Image backgroundImage; private int widthInFeatures, heightInFeatures; private double widthPhysical, heightPhysical; private BufferedImage tmpImage; private int panelWidth; private int panelHeight; private boolean repaintAll; private Image destroyedImage; private HashMap blueBodyImages = new HashMap(), redBodyImages = new HashMap(), whiteBodyImages = new HashMap(); private HashMap blueTurretImages = new HashMap(), redTurretImages = new HashMap(), whiteTurretImages = new HashMap(); private JButton pauseButton, resetButton; private JButton stepButton; private Thread displayLoop; private JCheckBox realTimeBox; public ServerControlPanel(Map map) { this.map = map; addWindowListener(this); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static ServerControlPanel create(Map map) { controlPanel = new ServerControlPanel(map); controlPanel.initialize(); // controlPanel.show(); controlPanel.setVisible(true); return controlPanel; } public void startDisplayLoop() { displayLoop = new Thread(new ServerDisplayLoop(controlPanel), "ServerDisplayLoop"); displayLoop.start(); } public void stopDisplayLoop() { displayLoop.interrupt(); } public void paint(Graphics g) { super.paint(g); createBackgroundImage(); Graphics2D tg = tmpImage.createGraphics(); paintBackground(tg); Graphics mg = mapPanel.getGraphics(); paintMovingObjects(tg); boolean z = false; while (!z) z = mg.drawImage(tmpImage, 0, 0, this); tg.dispose(); mg.dispose(); } public void update(Graphics g) { if (repaintAll || getWidth() != panelWidth || getHeight() != panelHeight) { panelWidth = getWidth(); panelHeight = getHeight(); paint(g); repaintAll = false; return; } Graphics g1 = mapPanel.getGraphics(); paintMovingObjects((Graphics2D) g1); g1.dispose(); } public void setRepaintAll(boolean repaintAll) { this.repaintAll = repaintAll; } void initialize() { widthInFeatures = map.getWidthInFeatures(); heightInFeatures = map.getWidthInFeatures(); widthPhysical = map.getWidthPhysical(); heightPhysical = map.getWidthPhysical(); physicalFeatureSize = map.getFeatureSize(); { displayFeatureSize = DISPLAY_SIZE / widthInFeatures; // DISPLAY_SIZE = displayFeatureSize * widthInFeatures; if (widthInFeatures > DISPLAY_SIZE) throw new RuntimeException( "Not enough pixels to display all features. " + widthInFeatures + " > " + DISPLAY_SIZE); // if ((DISPLAY_SIZE % widthInFeatures) != 0) // throw new RuntimeException("Gonna be an ugly display: " // + widthInFeatures + " > " + DISPLAY_SIZE); backgroundImage = getGraphicsConfiguration().createCompatibleImage( DISPLAY_SIZE + 50, DISPLAY_SIZE + 50); } Projectile.initializeImages(displayFeatureSize); TerrainType.initializeImages(displayFeatureSize); createBackgroundImage(); createOffscreenImages(); destroyedImage = (new ImageIcon(ClassLoader .getSystemResource("images/wreck.gif"))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); initializeWindow(); } void createBackgroundImage() { Graphics g1 = backgroundImage.getGraphics(); for (int y = 0; y < widthInFeatures; y++) { for (int x = 0; x < widthInFeatures; x++) { Image image = map.get(x * physicalFeatureSize, y * physicalFeatureSize).getImage(); // image.getClass(); boolean z = false; while (!z) z = g1.drawImage(image, x * displayFeatureSize, y * displayFeatureSize, this); } } g1.dispose(); } void paintBackground(Graphics g) { boolean z = false; while (!z) z = g.drawImage(backgroundImage, 0, 0, null); } private void paintMovingObjects(Graphics2D g) { synchronized (Battlefield.class) { double featureSize = map.getFeatureSize(); for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { AFVMover m = (AFVMover) Battlefield.getAFVMover(i); m.unpaint(g, this, featureSize); } for (int i = 0, size = Battlefield.getNProjectiles(); i < size; i++) { ProjectileMover m = (ProjectileMover) Battlefield .getProjectile(i); m.unpaint(g, this, featureSize); } for (int i = 0, size = Battlefield.getNAFVs(); i < size; i++) { AFVMover m = (AFVMover) Battlefield.getAFVMover(i); m.paint(g, this, featureSize); } for (int i = 0, size = Battlefield.getNProjectiles(); i < size; i++) { ProjectileMover m = (ProjectileMover) Battlefield .getProjectile(i); m.paint(g, this, featureSize); } } } private void createOffscreenImages() { tmpImage = getGraphicsConfiguration().createCompatibleImage( DISPLAY_SIZE + 50, DISPLAY_SIZE + 50); } private void initializeWindow() { this.setVisible(false); int width = 605 + DISPLAY_SIZE; int height = 57 + DISPLAY_SIZE; Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); if ((screen.width - 10) < width) { width = screen.width - 10; } if ((screen.height - 20) < height) { height = screen.height - 20; } this.setSize(width, height); // ** to maximize the window ** // this.setExtendedState(JFrame.MAXIMIZED_BOTH); this.setTitle("BattleField - dTank " + Parameters.getVersion() + " " + Parameters.getReleaseDate()); this.setResizable(true); // Center the frame on the desktop. (useless since we use setLocationRelativeTo(null) below /*Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); this.setLocation( (int) (0.5 * screenSize.width - 0.5 * this.getWidth()), (int) (0.5 * screenSize.height - 0.5 * this.getHeight())); */ //contentPane = (JPanel) this.getContentPane(); // contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.X_AXIS)); //contentPane.setLayout(new BorderLayout()); contentPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); this.setContentPane(contentPane); contentPane.setBackground(Color.gray); contentPane.setBorder(BorderFactory.createRaisedBevelBorder()); mapPanel.setBackground(Color.white); mapPanel.setBorder(BorderFactory.createRaisedBevelBorder()); mapPanel.setSize(DISPLAY_SIZE + 50, DISPLAY_SIZE); mapPanel.setMinimumSize(new Dimension(DISPLAY_SIZE + 50, DISPLAY_SIZE)); mapPanel .setPreferredSize(new Dimension(DISPLAY_SIZE + 50, DISPLAY_SIZE)); contentPane.setLeftComponent(new JScrollPane(mapPanel)); //contentPane.add(, BorderLayout.CENTER); // contentPane.add(mapPanel); JPanel controlPanel = new JPanel(new SpringLayout()); // controlPanel.setMaximumSize(new Dimension(250, DISPLAY_SIZE)); contentPane.setRightComponent(new JScrollPane(controlPanel)); //contentPane.add(new JScrollPane(controlPanel), BorderLayout.EAST); JLabel titleLabel = new JLabel(); titleLabel.setFont(new java.awt.Font("Serif", 1, 16)); titleLabel.setText(" Server Display"); controlPanel.add(titleLabel); statusPanel.setBorder(BorderFactory.createRaisedBevelBorder()); statusPanel.setMaximumSize(new Dimension(600, DISPLAY_SIZE)); quitButton.setText("Quit dTank"); // quitButton.addActionListener(this); quitButton.setBackground(SystemColor.inactiveCaption); blueLabel.setText("Blue:"); redLabel.setText("Red:"); whiteLabel.setText("White:"); secondsPerCycleLabel.setText("Seconds per cycle: " + Simulation.getBattleSecondsPerCycle()); gameSpeedLabel.setText("Simulation period (ms): " + Simulation.getSimulationPeriod()); mapDimensionsLabel.setText("Dimensions: " + map.getHeightPhysical() + " x " + map.getHeightPhysical() + " m"); timeLabel.setFont(new java.awt.Font("Serif", 1, 16)); timeLabel.setText("Time: 0"); statusPanel.add(new JLabel(" Total / Damaged / Destroyed")); statusPanel.add(blueLabel); statusPanel.add(redLabel); statusPanel.add(whiteLabel); statusPanel.add(new JLabel(" ")); statusPanel.add(mapDimensionsLabel); statusPanel.add(gameSpeedLabel); statusPanel.add(new JLabel(" ")); statusPanel.add(timeLabel); // clientInfoButton.addActionListener(this); statusPanel.add(new JLabel(" ")); JLabel messagesLabel = new JLabel("Messages:"); messagesLabel.setFont(new java.awt.Font("Serif", 1, 16)); statusPanel.add(messagesLabel); messageTextArea.setBorder(BorderFactory.createLoweredBevelBorder()); messageTextArea.setEditable(false); messageTextArea.setText("T dTank 4"); messageTextArea.setRows(15); messageTextArea.setColumns(40); statusPanel.add(messageTextArea); SpringUtilities.makeCompactGrid(statusPanel, 12, 1, 6, 6, 6, 6); controlPanel.add(statusPanel); // clientInfoButton.setBackground(SystemColor.inactiveCaption); JPanel stepPanel = new JPanel(new SpringLayout()); ActionListener listener = new ServerButtonListener(); pauseButton = new JButton("Pause/Resume"); stepPanel.add(pauseButton); pauseButton.addActionListener(listener); resetButton = new JButton("Reset"); stepPanel.add(resetButton); resetButton.addActionListener(listener); stepButton = new JButton("Step"); stepPanel.add(stepButton); stepButton.addActionListener(listener); realTimeBox = new JCheckBox("Real time"); stepPanel.add(realTimeBox); realTimeBox.addActionListener(listener); SpringUtilities.makeCompactGrid(stepPanel, 1, 4, 6, 6, 6, 6); // clientInfoButton.setText("Detailed Client Info"); // clientInfoButton.addActionListener(this); controlPanel.add(stepPanel); SpringUtilities.makeCompactGrid(controlPanel, 3, 1, 6, 6, 6, 6); this.setLocationRelativeTo(null); contentPane.setDividerLocation(this.getWidth()-CONTROL_PANEL_WIDTH_PX); } public int convertPos(double y) { // From meters to pixels return (int) ((y / heightPhysical) * DISPLAY_SIZE); } public static int getDisplayFeatureSize() { return displayFeatureSize; } static String buildStatusString() { String s = "Sec/Cycle: " + Simulation.getBattleSecondsPerCycle() + " ms/Cycle: " + Simulation.getSimulationPeriod(); return s; } class JMapPanel extends JPanel { public void paint(Graphics g) { super.paint(g); createBackgroundImage(); Graphics2D tg = tmpImage.createGraphics(); paintBackground(tg); Graphics mg = mapPanel.getGraphics(); paintMovingObjects(tg); boolean z = false; while (!z) z = mg.drawImage(tmpImage, 0, 0, this); tg.dispose(); mg.dispose(); } public void update(Graphics g) { Graphics g1 = mapPanel.getGraphics(); paintMovingObjects((Graphics2D) g1); g1.dispose(); } } public void setBlueText(String string) { blueLabel.setText(string); } public void setRedText(String string) { redLabel.setText(string); } public void setWhiteText(String string) { whiteLabel.setText(string); } public void setTimeText(String string) { timeLabel.setText(string); } public void setMessageText(String messages) { messageTextArea.setText(messages); } public static void writeDisplayMessage(String msg) { if (msg.length() > MESSAGE_WIDTH) { writeDisplayMessageHelper(msg.substring(0, MESSAGE_WIDTH)); writeDisplayMessageHelper(" " + msg.substring(MESSAGE_WIDTH)); } else writeDisplayMessageHelper(msg); } public static void writeDisplayMessageHelper(String msg) { int size = displayMessages.size(); if (size > 0 && msg.equals(displayMessages.get(size - 1))) return; while (displayMessages.size() > MAX_MESSAGES) { displayMessages.remove(0); } displayMessages.add(msg + "\n"); } public static void clearDisplayMessage() { displayMessages.clear(); } public static String getMessageString() { StringBuffer sb = new StringBuffer(); for (int i = 0, size = displayMessages.size(); i < size; i++) { sb.append(wrapLine((String) displayMessages.get(i))); } return sb.toString(); } private static String wrapLine(String string) { // StringBuffer sb = new StringBuffer(string); // for (int i = 90; i < sb.length(); i += 80) { // sb.insert(i, "\n "); // } // return sb.toString(); return string; } public void reset() { repaintAll = true; } public Image getBodyImage(AFV afv) { if (afv.isDestroyed()) return destroyedImage; Nationality n = afv.getNationality(); return getBodyImage(n, afv.getAFVType()); } public Image getTurretImage(AFV afv) { if (afv.isDestroyed()) return destroyedImage; Nationality n = afv.getNationality(); return getTurretImage(n, afv.getAFVType()); } private Image getImage(Nationality n, AFVType type, boolean returnBody) { HashMap bodyImages, turretImages; String c; if (n == Nationality.BLUE) { bodyImages = blueBodyImages; turretImages = blueTurretImages; c = "blue"; } else if (n == Nationality.WHITE) { bodyImages = whiteBodyImages; turretImages = whiteTurretImages; c = "white";// White might be nice, but yellow will do. } else { bodyImages = redBodyImages; turretImages = redTurretImages; c = "red"; } Image bodyImage = (Image) bodyImages.get(type); Image turretImage = (Image) turretImages.get(type); if (bodyImage == null) { bodyImage = (new ImageIcon(ClassLoader.getSystemResource("images/" + c + type.getBodyImageFilename()))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); bodyImages.put(type, bodyImage); // if (type.getBodyImageFilename().equals("tank.gif")) { turretImage = (new ImageIcon(ClassLoader .getSystemResource("images/" + c + type.getTurretImageFilename()))).getImage() .getScaledInstance(displayFeatureSize, displayFeatureSize, 0); turretImages.put(type, turretImage); // } } if (returnBody) return bodyImage; return turretImage; } private Image getTurretImage(Nationality n, AFVType type) { return getImage(n, type, false); } private Image getBodyImage(Nationality n, AFVType type) { return getImage(n, type, true); } class ServerButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { JComponent s = (JComponent) e.getSource(); if (s == pauseButton) { Simulation.togglePause(); } else if (s == stepButton) { Simulation.step(); } else if (s == resetButton) { Simulation.endBattle(); } else if (s == realTimeBox) { Simulation.setRealTime(realTimeBox.isSelected()); } } } public void windowActivated(WindowEvent e) { } public void windowClosed(WindowEvent e) { Simulation.stopSimulation(); stopDisplayLoop(); displayMessages.clear(); reset(); } public void windowClosing(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowOpened(WindowEvent e) { } } *************************************************************************************** ServerControlPanelCreationTest.java *************************************************************************************** package acsl.dTank.ui; import acsl.dTank.map.Map; import junit.framework.TestCase; public class ServerControlPanelCreationTest extends TestCase { private static final String MAP_FILENAME = "testMaps/test50x50.map"; public void setUp() { Map map = Map.create(MAP_FILENAME, 1000.0, 1000.0); ServerControlPanel.create(map); } public void test1() throws InterruptedException { Thread.sleep(100000); } public static void main(String[] args) throws InterruptedException { System.out.println("==========ServerControlPanelCreationTest=========="); ServerControlPanelCreationTest test = new ServerControlPanelCreationTest(); test.setUp(); test.test1(); } } *************************************************************************************** ServerDisplayLoop.java *************************************************************************************** /** * The display loop updates and repaints the display independently of the * simulation. */ package acsl.dTank.ui; import acsl.dTank.Parameters; import acsl.dTank.battle.Battlefield; public class ServerDisplayLoop implements Runnable { private ServerControlPanel controlPanel; public ServerDisplayLoop(ServerControlPanel controlPanel) { this.controlPanel = controlPanel; } public void run() { while (true) { try { Thread.sleep(Parameters.getServerDisplayPeriod()); } catch (InterruptedException e) { return; } redisplay(); } } void redisplay() { long seconds = Battlefield.getGameTime() / 1000; controlPanel.setTimeText("Time: " + seconds + "." + Battlefield.getGameTime() % 1000); int nBlueAFVs = Battlefield.getNBlueAFVs(); int nBlueDamaged = Battlefield.getNBlueDamaged(); int nBlueDestroyed = Battlefield.getNBlueDestroyed(); int nRedAFVs = Battlefield.getNRedAFVs(); int nRedDamaged = Battlefield.getNRedDamaged(); int nRedDestroyed = Battlefield.getNRedDestroyed(); int nWhiteAFVs = Battlefield.getNWhiteAFVs(); int nWhiteDamaged = Battlefield.getNWhiteDamaged(); int nWhiteDestroyed = Battlefield.getNWhiteDestroyed(); controlPanel.setBlueText("Blue: " + nBlueAFVs + " / " + nBlueDamaged + " / " + nBlueDestroyed); controlPanel.setRedText("Red: " + nRedAFVs + " / " + nRedDamaged + " / " + nRedDestroyed); controlPanel.setWhiteText("White: " + nWhiteAFVs + " / " + nWhiteDamaged + " / " + nWhiteDestroyed); controlPanel.setMessageText(ServerControlPanel.getMessageString()); controlPanel.repaint(); } } *************************************************************************************** StartupMenu.java *************************************************************************************** package acsl.dTank.ui; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SpringLayout; import acsl.dTank.Parameters; import acsl.dTank.SpringUtilities; import acsl.dTank.battle.AFVConfiguration; import acsl.dTank.battle.Battalion; import acsl.dTank.battle.Battle; import acsl.dTank.battle.BattleInitializer; public class StartupMenu extends JFrame { public static final String MAP_DIR = System.getProperty("DTANK_MAP_DIR","maps"); private static final String DURATION500 = "500", DURATION1000 = "1000", DURATION2000 = "2000", DURATION5000 = "5000", DURATION10000 = "10000"; String MOD_MEM_FILE = "modelFile.txt"; String LINE_SEPERATOR = ";"; JLabel mapLabel, dimLabel, simLabel, displayLabel; JPanel mainPanel; JFrame frame; private JComboBox cmdrCombo; private JComboBox afvCombo; private JComboBox withDisplayCombo; private JComboBox nCombo; private JButton startButton, aboutButton; private JList blueList; private JButton addBlueAFV; private JButton removeBlueAFV; private DefaultListModel blueListModel; private JList redList; private JButton addRedAFV; private JButton removeRedAFV; private DefaultListModel redListModel; private JList whiteList; private JButton addWhiteAFV; private JButton removeWhiteAFV; private DefaultListModel whiteListModel; private JComboBox durationCombo; private JLabel durationLabel; JComboBox mapCombo; private JComboBox dimCombo; private JComboBox simCombo; private JComboBox dispFreqCombo; private JCheckBox chkLoggingON, changeLocation, magicMode; private JTextField fldLogDir; private JButton btnBrowseLog; private JComboBox fldModelFile; private JButton btnBrowseModel; private JTextField fldMapFile; private JButton btnBrowseMap; private File fileIterator; ArrayList models = new ArrayList(); private static JFileChooser chooser = new JFileChooser(); public static String DIM500 = "500m x 500m", DIM1KM = "1km x 1km", DIM2KM = "2km x 2km", DIM5KM = "5km x 5km", DIM10KM = "10km x 10km", DIM20KM = "20km x 20km"; public static String SIM10 = "10", SIM20 = "20", SIM50 = "50", SIM100 = "100"; public static String DISP40 = "40", DISP100 = "100", DISP500 = "500", DISP1000 = "1000"; public static String N1 = "1", N2 = "2", N3 = "3", N4 = "4"; public static String WITH_DISPLAY = "Display", WITHOUT_DISPLAY = "NoDisplay"; private void fightBattles() { String mapFilename = (String) mapCombo.getSelectedItem(); // mapFfilename = mapFilename.replace('\\', '/'); String durString = (String) durationCombo.getSelectedItem(); int dur; try{ dur = Integer.parseInt(durString); }catch(NumberFormatException nfe){ JOptionPane.showMessageDialog(frame, "Duration is supposed to be an integer amount of seconds, not "+durString,"Preparing battle...",JOptionPane.ERROR_MESSAGE); return; } String dimString = (String) dimCombo.getSelectedItem(); double dim = 500; if (dimString.equals(DIM500)) dim = 500; else if (dimString.equals(DIM1KM)) dim = 1000; else if (dimString.equals(DIM2KM)) dim = 2000; else if (dimString.equals(DIM5KM)) dim = 5000; else if (dimString.equals(DIM10KM)) dim = 10000; else if (dimString.equals(DIM20KM)) dim = 20000; String simString = (String) simCombo.getSelectedItem(); int sim; try{ sim = Integer.parseInt(simString); }catch(NumberFormatException nfe){ JOptionPane.showMessageDialog(frame, "Simulation period is supposed to be an integer amount of milliseconds, not "+simString,"Preparing battle...",JOptionPane.ERROR_MESSAGE); return; } int dis = 10; String disString = (String) dispFreqCombo.getSelectedItem(); try{ dis = Integer.parseInt(disString); }catch(NumberFormatException nfe){ JOptionPane.showMessageDialog(frame, "Display period is supposed to be an integer amount of milliseconds, not "+disString,"Preparing battle...",JOptionPane.ERROR_MESSAGE); return; } List battles = new ArrayList(); Battalion battalionA = new Battalion("BlueCommander"); for (int i = 0, size = blueListModel.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) blueListModel.get(i); battalionA.addAFVConfigurations(c); } Battalion battalionB = new Battalion("RedCommander"); for (int i = 0, size = redListModel.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) redListModel.get(i); battalionB.addAFVConfigurations(c); } Battalion battalionC = new Battalion("WhiteCommander"); for (int i = 0, size = whiteListModel.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) whiteListModel.get(i); battalionC.addAFVConfigurations(c); } Battle b = new Battle(battalionA, battalionB, battalionC); battles.add(b); Parameters.setLoggingToTTY(chkLoggingON.isSelected()); Parameters.setRecordResults(chkLoggingON.isSelected()); Parameters.setChangeLoc(changeLocation.isSelected()); // String dir = fldLogDir.getText(); dir = dir.replace("\\", "/"); // if a path is specified, make sure it contains // a trailing path sep... if (dir.trim().length() > 0) { if (!dir.trim().endsWith("/")) dir = dir + "/"; } // otherwise assume current dir... Parameters.setLogFilename(dir + "dTankLog.log"); Parameters.setResultsFilename(dir + "dTankResults.log"); Parameters.setValues(mapFilename, dim, sim, dis, dur, battles); if (magicMode.isSelected()) { // Parameters.setMode("Magic"); Parameters.setServerDisplayPeriod(1000); } startBattles(); } private void startBattles() { Thread t = new Thread("BattleInitializer") { public void run() { try { BattleInitializer.fightBattles(); } catch (Exception e) { e.printStackTrace(); } } }; t.start(); } /** * Create the GUI and show it. For thread safety, this method should be invoked from the event-dispatching thread. */ private void createAndShowGUI() { mainPanel = new JPanel(new SpringLayout()); JPanel topPanel = new JPanel(new SpringLayout()); ActionListener buttonListener = new ButtonListener(this); { mapLabel = new JLabel("Map: ", JLabel.TRAILING); topPanel.add(mapLabel); mapCombo=createMapComboBox(); topPanel.add(mapCombo); mapLabel.setLabelFor(mapCombo); dimLabel = new JLabel("Dimensions: ", JLabel.TRAILING); topPanel.add(dimLabel); dimCombo = new JComboBox(new String[] { DIM500, DIM1KM, DIM2KM, DIM5KM, DIM10KM, DIM20KM }); topPanel.add(dimCombo); dimLabel.setLabelFor(dimCombo); simLabel = new JLabel("Simulation Period (ms): ", JLabel.TRAILING); topPanel.add(simLabel); simCombo = new JComboBox(new String[] { SIM10, SIM20, SIM50, SIM100 }); simCombo.setEditable(true); topPanel.add(simCombo); simLabel.setLabelFor(simCombo); displayLabel = new JLabel("Redisplay Period (ms): ", JLabel.TRAILING); topPanel.add(displayLabel); dispFreqCombo = new JComboBox(new String[] { DISP40, DISP100, DISP500, DISP1000 }); dispFreqCombo.setEditable(true); topPanel.add(dispFreqCombo); topPanel.setBorder(BorderFactory.createLineBorder(Color.black)); displayLabel.setLabelFor(dispFreqCombo); durationLabel = new JLabel("Battle Duraton (s): ", JLabel.TRAILING); topPanel.add(durationLabel); durationCombo = new JComboBox(new String[] { DURATION500, DURATION1000, DURATION2000, DURATION5000, DURATION10000 }); durationCombo.setEditable(true); topPanel.add(durationCombo); topPanel.setBorder(BorderFactory.createLineBorder(Color.black)); durationLabel.setLabelFor(durationCombo); } SpringUtilities.makeCompactGrid(topPanel, 5, 2, 6, 6, 6, 6); mainPanel.add(topPanel); { JPanel afvPanel = new JPanel(new FlowLayout()); cmdrCombo = createCommanderComboBox(); afvPanel.add(cmdrCombo); afvCombo = createAFVComboBox(); afvPanel.add(afvCombo); nCombo = new JComboBox(new String[] { N1, N2, N3, N4 }); afvPanel.add(nCombo); withDisplayCombo = new JComboBox(new String[] { WITHOUT_DISPLAY, WITH_DISPLAY }); afvPanel.add(withDisplayCombo); mainPanel.add(afvPanel); } { JPanel pathPanel = new JPanel(new FlowLayout()); pathPanel.add(new JLabel("Model path:")); models .add(" "); getTextfromModelFile(); // fldModelFile = new JComboBox(new String[] {" " }); String m[] = new String[models.size()]; for (int i = 0; i < models.size(); i++) { m[i] = models.get(i).toString(); } fldModelFile = new JComboBox(m); fldModelFile.setMinimumSize(new Dimension(40, 20)); fldModelFile.setSize(40, 20); pathPanel.add(fldModelFile); btnBrowseModel = new JButton("..."); pathPanel.add(btnBrowseModel); btnBrowseModel.addActionListener(buttonListener); pathPanel.setBorder(BorderFactory.createLineBorder(Color.black)); mainPanel.add(pathPanel); } { JPanel loggingPanel = new JPanel(new FlowLayout()); chkLoggingON = new JCheckBox("Turn Logging On", false); loggingPanel.add(chkLoggingON); loggingPanel.add(new JLabel("Logging path:")); fldLogDir = new JTextField("", 20); loggingPanel.add(fldLogDir); btnBrowseLog = new JButton("..."); loggingPanel.add(btnBrowseLog); btnBrowseLog.addActionListener(buttonListener); loggingPanel.setBorder(BorderFactory.createLineBorder(Color.black)); changeLocation = new JCheckBox("", false); loggingPanel.add(new JLabel(" Switch Starting Location:")); loggingPanel.add(changeLocation); magicMode = new JCheckBox("", false); // loggingPanel.add(new JLabel(" Discrete Mode:")); // loggingPanel.add(magicMode); mainPanel.add(loggingPanel); } JPanel battalionPanel = new JPanel(new SpringLayout()); { JPanel bluePanel = new JPanel(new SpringLayout()); battalionPanel.add(bluePanel); JLabel BlueLabel = new JLabel("Blue: ", JLabel.TRAILING); bluePanel.add(BlueLabel); blueListModel = new DefaultListModel(); blueList = new JList(blueListModel); JScrollPane listScroller = new JScrollPane(blueList); listScroller.setPreferredSize(new Dimension(250, 80)); battalionPanel.add(listScroller); addBlueAFV = new JButton("Add"); addBlueAFV.addActionListener(buttonListener); bluePanel.add(addBlueAFV); removeBlueAFV = new JButton("Remove"); removeBlueAFV.addActionListener(buttonListener); bluePanel.add(removeBlueAFV); SpringUtilities.makeCompactGrid(bluePanel, 3, 1, 6, 6, 6, 6); } { JPanel redPanel = new JPanel(new SpringLayout()); battalionPanel.add(redPanel); JLabel RedLabel = new JLabel("Red: ", JLabel.TRAILING); redPanel.add(RedLabel); redListModel = new DefaultListModel(); redList = new JList(redListModel); JScrollPane listScroller = new JScrollPane(redList); listScroller.setPreferredSize(new Dimension(250, 80)); battalionPanel.add(listScroller); addRedAFV = new JButton("Add"); addRedAFV.addActionListener(buttonListener); redPanel.add(addRedAFV); removeRedAFV = new JButton("Remove"); removeRedAFV.addActionListener(buttonListener); redPanel.add(removeRedAFV); SpringUtilities.makeCompactGrid(redPanel, 3, 1, 6, 6, 6, 6); } { JPanel whitePanel = new JPanel(new SpringLayout()); battalionPanel.add(whitePanel); JLabel whiteLabel = new JLabel("White: ", JLabel.TRAILING); whitePanel.add(whiteLabel); whiteListModel = new DefaultListModel(); whiteList = new JList(whiteListModel); JScrollPane listScroller = new JScrollPane(whiteList); listScroller.setPreferredSize(new Dimension(250, 80)); battalionPanel.add(listScroller); addWhiteAFV = new JButton("Add"); addWhiteAFV.addActionListener(buttonListener); whitePanel.add(addWhiteAFV); removeWhiteAFV = new JButton("Remove"); removeWhiteAFV.addActionListener(buttonListener); whitePanel.add(removeWhiteAFV); SpringUtilities.makeCompactGrid(whitePanel, 3, 1, 6, 6, 6, 6); } SpringUtilities.makeCompactGrid(battalionPanel, 3, 2, 6, 6, 6, 6); mainPanel.add(battalionPanel); { JPanel startPanel = new JPanel(); startPanel.setLayout(new BoxLayout(startPanel, BoxLayout.X_AXIS)); Dimension minSize = new Dimension(50, 50); Dimension prefSize = new Dimension(50, 50); Dimension maxSize = new Dimension(Short.MAX_VALUE, 100); startPanel.add(new Box.Filler(minSize, prefSize, maxSize)); startPanel.setBorder(BorderFactory.createLineBorder(Color.black)); startButton = new JButton("Start"); startButton.addActionListener(buttonListener); startPanel.add(startButton); mainPanel.add(startPanel); startPanel.add(new Box.Filler(minSize, prefSize, maxSize)); aboutButton = new JButton("About"); aboutButton.addActionListener(buttonListener); startPanel.add(aboutButton); startPanel.add(Box.createRigidArea(new Dimension(10, 0))); mainPanel.add(startPanel); } SpringUtilities.makeCompactGrid(mainPanel, 6, 1, 6, 6, 6, 6); frame = new JFrame("dTank" + Parameters.getVersion() + " " + Parameters.getReleaseDate()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainPanel.setOpaque(true); frame.setContentPane(mainPanel); // Display the window. frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static final String AFV_SHERMAN = "Sherman"; public static final String AFV_TIGER = "Tiger"; public static final String AFV_PKW_IV = "PKW_IV"; public static final String AFV_KING_TIGER = "King_Tiger"; public static final String AFV_SOLDIER = "SOLDIER"; public static final String AFV_OFFICER = "OFFICER"; public static final String AFV_CIVILIAN = "CIVILIAN"; private JComboBox createAFVComboBox() { return new JComboBox(new String[] { AFV_SHERMAN, AFV_TIGER, AFV_KING_TIGER, AFV_PKW_IV, AFV_SOLDIER, AFV_OFFICER, AFV_CIVILIAN }); } public static final String CMDR_SmartCommander = "SmartCommander"; public static final String CMDR_DullCommander = "DullCommander"; public static final String CMDR_HumanCommander = "HumanCommander"; public static final String CMDR_HillCommander = "HillCommander"; public static final String CMDR_SoarCommander = "SoarCommander"; public static final String CMDR_JessCommander = "JessCommander"; public static final String CMDR_JackCommander = "JackCommander"; private JComboBox createCommanderComboBox() { return (new JComboBox(new String[] { CMDR_DullCommander, CMDR_SmartCommander, CMDR_HillCommander, CMDR_HumanCommander, CMDR_JessCommander, CMDR_SoarCommander, CMDR_JackCommander })); } public static final String MAP1 = "maps/Empty_10x10.map"; public static final String MAP5 = "maps/Empty_20x20.map"; public static final String MAP6 = "maps/Empty_50x50.map"; public static final String MAP2 = "maps/Hilly_20x20.map"; public static final String MAP3 = "maps/Strat_20x20.map"; public static final String MAP4 = "maps/El_Alamein_50x50.map"; private JComboBox createMapComboBox() { try { fileIterator = new File(this.getClass().getClassLoader().getResource(MAP_DIR).toURI().getPath()); } catch (Exception ex) { fileIterator = new File(MAP_DIR); } //fileIterator = new File(MAP_DIR); JComboBox combo = new JComboBox(); if (fileIterator.isDirectory() == false) { if (fileIterator.exists() == false) { combo = new JComboBox(new String[] { MAP1, MAP2, MAP3, MAP4, MAP5, MAP6 }); } } else { String[] files = fileIterator.list(); //add a prefix to the file int i=0; for(String f :files){ files[i++]=MAP_DIR+File.separator+f; } combo = new JComboBox(files); } return combo; //return new JComboBox(new String[] { MAP1, MAP2, MAP3, MAP4, MAP5, MAP6 }); } public static void main(String[] args) { // Schedule a job for the event-dispatching thread: // creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { StartupMenu s = new StartupMenu(); s.createAndShowGUI(); } }); } public void updateFileMemory(String text) { // MOD_MEM_FILE = "modelFile.txt"; // LINE_SEPERATOR = ';'; try { FileWriter f = new FileWriter(MOD_MEM_FILE, true); f.write(text); f.write(LINE_SEPERATOR); f.close(); } catch (Exception ex) { System.out.println(ex.toString()); } } public void getTextfromModelFile() { try { BufferedReader in = new BufferedReader(new FileReader(MOD_MEM_FILE)); String str; while ((str = in.readLine()) != null) { processString(str); } in.close(); } catch (IOException e) { } } public void processString(String str) { StringBuffer tempSt = new StringBuffer(); for (int i = 0; i < str.length(); i++) { String c = "" + str.charAt(i); if (!c.equals(LINE_SEPERATOR)) { tempSt = tempSt.append(c); } else { models.add(tempSt.toString()); int l = tempSt.length(); tempSt = tempSt.delete(0, l); } } } public void showAboutBox() { AboutPage.main(new String[] {}); } private class ButtonListener implements ActionListener { private JFrame parentComponent; ButtonListener(JFrame parentComponent) { this.parentComponent = parentComponent; } public void actionPerformed(ActionEvent e) { JButton button = (JButton) e.getSource(); String cmdr = (String) cmdrCombo.getSelectedItem(); String num = (String) nCombo.getSelectedItem(); String wd = (String) withDisplayCombo.getSelectedItem(); String afv = (String) afvCombo.getSelectedItem(); String modelFile = (String) fldModelFile.getSelectedItem(); String[] args = new String[] {}; if (modelFile.trim().length() > 0) args = new String[] { modelFile.trim() }; if (cmdr.equals(CMDR_HumanCommander)) wd = WITH_DISPLAY; if (button == addBlueAFV) { AFVConfiguration c = new AFVConfiguration("Blue", cmdr, afv, num, wd, args); blueListModel.addElement(c); return; } if (button == addRedAFV) { AFVConfiguration c = new AFVConfiguration("Red", cmdr, afv, num, wd, args); redListModel.addElement(c); return; } if (button == addWhiteAFV) { AFVConfiguration c = new AFVConfiguration("WHITE", cmdr, afv, num, wd, args); whiteListModel.addElement(c); return; } if (button == removeBlueAFV) { int i = blueList.getSelectedIndex(); if (i == -1) return; blueListModel.remove(i); return; } if (button == removeRedAFV) { int i = redList.getSelectedIndex(); if (i == -1) return; redListModel.remove(i); return; } if (button == removeWhiteAFV) { int i = whiteList.getSelectedIndex(); if (i == -1) return; whiteListModel.remove(i); return; } if (button == startButton) { // parentComponent.hide(); fightBattles(); return; } if (button == aboutButton) { showAboutBox(); return; } if (button == btnBrowseLog) { chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int returnVal = chooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { fldLogDir.setText(chooser.getSelectedFile().toString()); } } if (button == btnBrowseModel) { int returnVal = chooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { String text = chooser.getSelectedFile().toString(); fldModelFile.addItem(text); fldModelFile.setSelectedItem((String) text); updateFileMemory(text); } } } } } *************************************************************************************** TestListener.java *************************************************************************************** /* * This is used exclusively by a number of JUnit tests. */ package acsl.dTank.ui; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import acsl.dTank.Parameters; public abstract class TestListener implements Runnable { private boolean ready = false; public void run() { try { ServerSocket listenSocket = new ServerSocket(Parameters.getPort()); synchronized (this) { ready = true; notifyAll(); } Socket socket = listenSocket.accept(); BufferedReader inStream = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintStream outStream = new PrintStream(socket.getOutputStream()); runTests(inStream, outStream); listenSocket.close(); } catch (Exception e) { e.printStackTrace(); } } abstract void runTests(BufferedReader inStream, PrintStream outStream) throws IOException; public synchronized void waitForReady() { try { while (!ready) { wait(); } Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } *************************************************************************************** AllTests.java *************************************************************************************** /** * This runs the complete set of unit tests. * * The unit tests are not strictly proper unit tests as some start * threads and don't shut them down. Others change global state (eg, battleTime). * Thus the order of running the tests is important and some can't be run from here. */ package acsl.dTank; import java.io.IOException; import java.net.UnknownHostException; import acsl.dTank.commandMessage.CommandMessageTest; import acsl.dTank.commander.CommanderMapTest; import acsl.dTank.commander.CommanderMessageTest; import acsl.dTank.commander.CommanderTest; import acsl.dTank.commander.CommanderTestTwo; import acsl.dTank.commander.RadioMessageTest; import acsl.dTank.communicator.ServerCommunicatorTest; import acsl.dTank.controller.DullAFVControllerTest; import acsl.dTank.controller.ExactControllerTest; import acsl.dTank.informationMessage.InformationMessageCreateTest; import acsl.dTank.informationMessage.InformationMessageTest; import acsl.dTank.map.MapTest; import acsl.dTank.mover.AFVMoverTest; import acsl.dTank.mover.CollisionTest; import acsl.dTank.mover.MovingTest; import acsl.dTank.mover.ScanAFVsTest; import acsl.dTank.mover.ScanMovingThingsTest; import acsl.dTank.mover.ScanTest; import acsl.dTank.ui.CommanderControlPanelTest; import acsl.dTank.ui.CommanderKeyTest; import acsl.dTank.ui.CommanderMouseListenerTest; public class AllTests { public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { Parameters.setTesting(true); Parameters.setLoggingToTTY(true); ServerCommunicatorTest.main(args); MapTest.main(args); CommanderTest.main(args); InformationMessageTest.main(args); InformationMessageCreateTest.main(args); ExactControllerTest.main(args); // advances time DullAFVControllerTest.main(args); CollisionTest.main(args); CommandMessageTest.main(args); CommanderMapTest.main(args); ScanTest.main(args); ScanTwoTest.main(args); ScanAFVsTest.main(args); ScanMovingThingsTest.main(args); AFVMoverTest.main(args); MovingTest.main(args); CommanderMouseListenerTest.main(args); if (false) {// These tests start threads and don't clean up. RadioMessageTest.main(args); CommanderTestTwo.main(args); CommanderKeyTest.main(args); CommanderControlPanelTest.main(args); CommanderMessageTest.main(args); } System.out.println("All tests run"); } } *************************************************************************************** Logger.java *************************************************************************************** /** * This takes care of logging events to a file. * (Should it be replaced with Log4J?) */ package acsl.dTank; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; import acsl.dTank.battle.AFVConfiguration; import acsl.dTank.battle.Battalion; public class Logger { private static boolean isLoggingToTTY; private static boolean logToFile; private static FileWriter logFile; private static FileWriter resultsFile; private static boolean resultsToFile; public static void logBoth(String msg) { System.out.println(msg); log(msg); } public static void log(String msg) { if (isLoggingToTTY) System.out.println(msg); if (logToFile) try { logFile.write(msg + "\n"); } catch (IOException e) { System.out.println("Log file closed."); } } public static void initialize() { String logFilename = Parameters.getLogfilename(); String resultsFilename = Parameters.getResultsFilename(); Logger.isLoggingToTTY = Parameters.isLoggingToTTY(); try { if (logFilename != null) { logToFile = true; File f = new File(logFilename); logFile = new FileWriter(f); } if (resultsFilename != null) { resultsToFile = true; File f = new File(resultsFilename); resultsFile = new FileWriter(f); } } catch (Exception e) { throw new RuntimeException(e); } } public static void close() { if (logFile == null) return; try { logFile.close(); } catch (IOException e) { throw new RuntimeException(e); } } public static void logAll(String msg) { logBoth(msg); if (resultsToFile) try { resultsFile.write(msg + "\n"); } catch (IOException e) { System.out.println("Results file closed."); } } public static void logAll(Battalion b) { List configurations = b.getAFVConfigurations(); for (int i = 0, size = configurations.size(); i < size; i++) { AFVConfiguration c = (AFVConfiguration) configurations.get(i); logAll(c.toString()); } } public static void flushAll() { try { if (resultsToFile) resultsFile.flush(); if (logFile != null) logFile.flush(); } catch (IOException e) { System.out.println("Results or Log file closed unexpectantly."); } } } *************************************************************************************** Parameters.java *************************************************************************************** /** * All parameters for the system are here. Many are initialized via Configuration. * Some are just constants that PERHAPS you'd like to change. */ package acsl.dTank; import java.util.List; import acsl.dTank.afv.Nationality; import acsl.dTank.battle.Battle; import acsl.dTank.battle.Configuration; import acsl.dTank.afv.Location; public class Parameters { private static String version = "4.3"; private static String releaseDate = "(16 Jan 2008)"; private static boolean isLoggingToTTY = false; private static final int PORT = 3500; private static boolean TESTING = false; private static String mode = "Realistic"; // "Magic", Realistic ; private static int messagePeriod = 1000; // send messages every X ms. // (1000 by def) private static int simulationPeriod = 40; // ms (SHOULD NOT BE 0!) private static int serverDisplayPeriod = 40; // ms (SHOULD NOT BE 0!) private static int commanderDisplayPeriod = 40; // ms (SHOULD NOT BE 0!) private static double secondsPerCycle = .4; private static double collisionRadius = 10; // colliding with other tanks private static double collisionRadius2 = collisionRadius * collisionRadius; private static double hitRadius = 20; // meters private static String logFilename = null; private static int battleDuration = 5000;// seconds private static int heightInFeatures; private static int widthInFeatures; private static double physicalHeight, physicalWidth; // meters private static double blueInjectionPointX; private static double blueInjectionPointY; private static double featureSize; // meters private static double redInjectionPointX; private static double redInjectionPointY; private static double whiteInjectionPointX; private static double whiteInjectionPointY; private static boolean useDirectCommunicator = false; private static String resultsFilename; private static boolean recordResults; private static List battles; private static int repeat = 1; // private static String damageController = "SimpleDamageController"; private static String damageController = "DeterministicDamageController"; private static String mapFilename; private static String battleName; private static boolean changeLoc = false; private static List blueSpawnPoints; private static int noBlueSpawnAssigned = 0; private static List redSpawnPoints; private static int noRedSpawnAssigned = 0; private static List whiteSpawnPoints; private static int noWhiteSpawnAssigned = 0; private static double maximumVisualDistance = 10000.0; private static boolean emptyBoardersRequired = false; private static int startUpPause; private static boolean allowControlMessages; public static boolean isMagicMode() { return mode.equals("Magic"); } public static boolean isRealisticMode() { return mode.equals("Realistic"); } public static boolean isDeterministicMode() { return mode.equals("Deterministic"); } public static void setMode(String mode2) { mode = mode2; if (isMagicMode()) { double fs = physicalHeight / heightInFeatures; collisionRadius2 = fs * fs; } } public static void setDimensions(int widthInFeatures2, int heightInFeatures2) { widthInFeatures = widthInFeatures2; heightInFeatures = heightInFeatures2; featureSize = physicalHeight / heightInFeatures; if (changeLoc == true) { redInjectionPointX = physicalWidth - (featureSize + 1.0); blueInjectionPointX = +1.0; } else { // default blueInjectionPointX = physicalWidth - (featureSize + 1.0); redInjectionPointX = +1.0; } reset(); } public static void reset() {// These get changed when injecting AFVs, so // have to reset for each battle blueInjectionPointY = physicalWidth / 8.0; redInjectionPointY = physicalWidth / 8.0; } public static int getWidthInFeatures() { return widthInFeatures; } public static int getHeightInFeatures() { return heightInFeatures; } public static void setSize(int i, int j) { widthInFeatures = i; heightInFeatures = j; } public static boolean isTesting() { return TESTING; } public static int getBattleDuration() { return battleDuration; } public static void setLoggingToTTY(boolean b) { isLoggingToTTY = b; } public static void setLogFilename(String logFilename2) { logFilename = logFilename2; } public static void setChangeLoc(boolean x) { changeLoc = x; } public static void setServerDisplayPeriod(int period) { Parameters.serverDisplayPeriod = period; } public static String getLogfilename() { return logFilename; } public static boolean isLoggingToTTY() { return isLoggingToTTY; } public static void setBattleDuration(int i) { battleDuration = i; } public static void setTesting(boolean b) { TESTING = b; } public static int getPort() { return PORT; } public static int getSimulationPeriod() { return simulationPeriod; } public static void setSimulationPeriod(int i) { simulationPeriod = i; } public static double getSecondsPerCycle() { return secondsPerCycle; } public static void setSecondsPerCycle(double d) { secondsPerCycle = d; } public static int getMessagePeriod() { return messagePeriod; } public static double getCOLLISION_RADIUS2() { return collisionRadius2; } public static double getFeatureSize() { return featureSize; } public static int getCommanderDisplayPeriod() { return commanderDisplayPeriod; } public static int getServerDisplayPeriod() { return serverDisplayPeriod; } public static double getMaximumVisualDistance() { return maximumVisualDistance; } public static double getHitRadius() { return hitRadius; } public static boolean useDirectCommunicator() { return useDirectCommunicator; } public static void setMaximumVisualDistance(double d) { maximumVisualDistance = d; } public static void setHitRadius(double hr) { hitRadius = hr; } public static String getReleaseDate() { return releaseDate; } public static double getPhysicalWidth() { return physicalWidth; } public static double getPhysicalHeight() { return physicalHeight; } public static void setResultsFilename(String resultsFilename) { Parameters.resultsFilename = resultsFilename; Parameters.recordResults = true; } public static String getResultsFilename() { return resultsFilename; } public static void setRecordResults(boolean recordResults) { Parameters.recordResults = recordResults; } public static boolean isRecordResults() { return recordResults; } public static void setBattles(List battles) { Parameters.battles = battles; } public static List getBattles() { return battles; } public static void setRepeat(int repeat) { Parameters.repeat = repeat; } public static int getRepeat() { return repeat; } public static void setValues(Configuration config) { Parameters.setLoggingToTTY(config.isLoggingToTTY()); Parameters.setLogFilename(config.getLogFilename()); Parameters.setMode(config.getMode()); Parameters.setHitRadius(config.getHitRadius()); Parameters.setMaximumVisualDistance(config.getMaximumVisualDistance()); Parameters.setBattleDuration(config.getBattleDuration() * 1000); Parameters.setSimulationPeriod(config.getSimulationPeriod()); Parameters.setSecondsPerCycle(config.getSecondsPerCycle()); Parameters.setResultsFilename(config.getResultsFilename()); Parameters.setRecordResults(config.isRecordResults()); Parameters.setBattles(config.getBattles()); Parameters.setRepeat(config.getRepeat()); Parameters.setDamageController(config.getDamageController()); Parameters.setMapFilename(config.getMapFilename()); Parameters.physicalWidth = config.getPhysicalWidth(); Parameters.physicalHeight = config.getPhysicalHeight(); Parameters.battleName = config.getBattleName(); Parameters.messagePeriod = config.getMessagePeriod(); Parameters.emptyBoardersRequired = config.emptyBoardersRequired(); Parameters.startUpPause = config.getStartUpPause(); Parameters.allowControlMessages = config.getAllowControlMessages(); } private static void setMapFilename(String mapFilename) { Parameters.mapFilename = mapFilename; } private static void setDamageController(String damageController) { Parameters.damageController = damageController; } public static String getDamageController() { return damageController; } public static String getMapFilename() { return mapFilename; } public static void setValues(String map, double dim, int sim, int dis, int dur, List battles) { Parameters.mapFilename = map; Parameters.physicalHeight = dim; Parameters.physicalWidth = dim; Parameters.simulationPeriod = sim; Parameters.serverDisplayPeriod = dis; Parameters.battles = battles; Parameters.battleDuration = dur * 1000; } public static String getBattleName() { return battleName; } public static void setPhysicalDimensions(double physicalWidth, double physicalHeight) { Parameters.physicalHeight = physicalHeight; Parameters.physicalWidth = physicalWidth; } public static double getInjectionPointY(Nationality nationality) { if (nationality == Nationality.BLUE) { blueInjectionPointY += featureSize; return blueInjectionPointY; } if (nationality == Nationality.RED) { redInjectionPointY += featureSize; return redInjectionPointY; } if (nationality == Nationality.WHITE) { whiteInjectionPointY += featureSize; return whiteInjectionPointY; } throw new RuntimeException("No such nationality " + nationality); } public static double getInjectionPointX(Nationality nationality) { if (nationality == Nationality.BLUE) { return blueInjectionPointX; } if (nationality == Nationality.RED) { return redInjectionPointX; } if (nationality == Nationality.WHITE) { whiteInjectionPointX += featureSize; return whiteInjectionPointX; } throw new RuntimeException("No such nationality " + nationality); } // public static void setBlueSpawnPoints(List l) { blueSpawnPoints = l; } public static void setRedSpawnPoints(List l) { redSpawnPoints = l; } public static void setWhiteSpawnPoints(List l) { whiteSpawnPoints = l; } // assigns location based on round robin public static Location getNextBlueSpawn() { Location l = new Location(0, 0); int nextSpawn = noBlueSpawnAssigned % blueSpawnPoints.size(); int quotient = noBlueSpawnAssigned / blueSpawnPoints.size(); l = (Location) blueSpawnPoints.get(nextSpawn); l = new Location(l.getX(), l.getY() + featureSize * quotient); noBlueSpawnAssigned++; return l; } // public static int getNoBlueSpawnPoints() { return blueSpawnPoints.size(); } public static Location getNextRedSpawn() { Location l = new Location(0, 0); int nextSpawn = noRedSpawnAssigned % redSpawnPoints.size(); int quotient = noRedSpawnAssigned / redSpawnPoints.size(); l = (Location) redSpawnPoints.get(nextSpawn); l = new Location(l.getX(), l.getY() + featureSize * quotient); noRedSpawnAssigned++; return l; } public static int getNoRedSpawnPoints() { return redSpawnPoints.size(); } public static Location getNextWhiteSpawn() { Location l = new Location(0, 0); int nextSpawn = noWhiteSpawnAssigned % whiteSpawnPoints.size(); int quotient = noWhiteSpawnAssigned / whiteSpawnPoints.size(); l = (Location) whiteSpawnPoints.get(nextSpawn); l = new Location(l.getX(), l.getY() + featureSize * quotient); noWhiteSpawnAssigned++; return l; } public static int getNoWhiteSpawnPoints() { return whiteSpawnPoints.size(); } public static String getVersion() { return version; } public static boolean emptyBoardersRequired() { return emptyBoardersRequired; } public static int getStartUpPause() { return startUpPause; } public static boolean getAllowControlMessages() { return allowControlMessages; } } *************************************************************************************** ScanTwoTest.java *************************************************************************************** package acsl.dTank; import junit.framework.TestCase; import acsl.dTank.afv.AFV; import acsl.dTank.afv.AFVType; import acsl.dTank.afv.Nationality; import acsl.dTank.afv.Tank; import acsl.dTank.battle.Battlefield; import acsl.dTank.controller.MagicAFVController; import acsl.dTank.mover.AFVMover; public class ScanTwoTest extends TestCase { private static final String SCAN0 = ""; AFV afv0, afv1; AFVMover mover0, mover1; public void setUp() { Battlefield.create("testMaps/test10x10.map", 1000.0, 1000.0); afv0 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr2", Nationality.BLUE, null)); afv1 = Tank.create(AFVType.SHERMAN, new MagicAFVController("Cmdr3", Nationality.BLUE, null)); // System.out.println(afv0 + " " + afv1); Battlefield.addTank(afv0); Battlefield.addTank(afv1); mover0 = Battlefield.getAFVMover(0); assertEquals(afv0, mover0.getAFV()); } public void test1() { afv0.setLocation(300.0, 400.0); afv0.setTurretHeading(42); afv1.setLocation(517, 161); String s = mover0.scanForTerrain(); assertEquals(SCAN0, s); } public static void main(String[] args) { System.out.println("==========ScanTwoTest=========="); ScanTwoTest test = new ScanTwoTest(); test.setUp(); test.test1(); } } *************************************************************************************** SpringUtilities.java *************************************************************************************** package acsl.dTank; import javax.swing.*; import javax.swing.SpringLayout; import java.awt.*; /** * A 1.4 file that provides utility methods for * creating form- or grid-style layouts with SpringLayout. * These utilities are used by several programs, such as * SpringBox and SpringCompactGrid. */ public class SpringUtilities { /** * A debugging utility that prints to stdout the component's * minimum, preferred, and maximum sizes. */ public static void printSizes(Component c) { System.out.println("minimumSize = " + c.getMinimumSize()); System.out.println("preferredSize = " + c.getPreferredSize()); System.out.println("maximumSize = " + c.getMaximumSize()); } /** * Aligns the first rows * cols * components of parent in * a grid. Each component is as big as the maximum * preferred width and height of the components. * The parent is made just big enough to fit them all. * * @param rows number of rows * @param cols number of columns * @param initialX x location to start the grid at * @param initialY y location to start the grid at * @param xPad x padding between cells * @param yPad y padding between cells */ public static void makeGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout)parent.getLayout(); } catch (ClassCastException exc) { System.err.println("The first argument to makeGrid must use SpringLayout."); return; } Spring xPadSpring = Spring.constant(xPad); Spring yPadSpring = Spring.constant(yPad); Spring initialXSpring = Spring.constant(initialX); Spring initialYSpring = Spring.constant(initialY); int max = rows * cols; //Calculate Springs that are the max of the width/height so that all //cells have the same size. Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)). getWidth(); Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)). getWidth(); for (int i = 1; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); } //Apply the new width/height Spring. This forces all the //components to have the same size. for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); cons.setWidth(maxWidthSpring); cons.setHeight(maxHeightSpring); } //Then adjust the x/y constraints of all the cells so that they //are aligned in a grid. SpringLayout.Constraints lastCons = null; SpringLayout.Constraints lastRowCons = null; for (int i = 0; i < max; i++) { SpringLayout.Constraints cons = layout.getConstraints( parent.getComponent(i)); if (i % cols == 0) { //start of new row lastRowCons = lastCons; cons.setX(initialXSpring); } else { //x position depends on previous component cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST), xPadSpring)); } if (i / cols == 0) { //first row cons.setY(initialYSpring); } else { //y position depends on previous row cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH), yPadSpring)); } lastCons = cons; } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, Spring.sum( Spring.constant(yPad), lastCons.getConstraint(SpringLayout.SOUTH))); pCons.setConstraint(SpringLayout.EAST, Spring.sum( Spring.constant(xPad), lastCons.getConstraint(SpringLayout.EAST))); } /* Used by makeCompactGrid. */ private static SpringLayout.Constraints getConstraintsForCell( int row, int col, Container parent, int cols) { SpringLayout layout = (SpringLayout) parent.getLayout(); Component c = parent.getComponent(row * cols + col); return layout.getConstraints(c); } /** * Aligns the first rows * cols * components of parent in * a grid. Each component in a column is as wide as the maximum * preferred width of the components in that column; * height is similarly determined for each row. * The parent is made just big enough to fit them all. * * @param rows number of rows * @param cols number of columns * @param initialX x location to start the grid at * @param initialY y location to start the grid at * @param xPad x padding between cells * @param yPad y padding between cells */ public static void makeCompactGrid(Container parent, int rows, int cols, int initialX, int initialY, int xPad, int yPad) { SpringLayout layout; try { layout = (SpringLayout)parent.getLayout(); } catch (ClassCastException exc) { System.err.println("The first argument to makeCompactGrid must use SpringLayout."); return; } //Align all cells in each column and make them the same width. Spring x = Spring.constant(initialX); for (int c = 0; c < cols; c++) { Spring width = Spring.constant(0); for (int r = 0; r < rows; r++) { width = Spring.max(width, getConstraintsForCell(r, c, parent, cols). getWidth()); } for (int r = 0; r < rows; r++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setX(x); constraints.setWidth(width); } x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); } //Align all cells in each row and make them the same height. Spring y = Spring.constant(initialY); for (int r = 0; r < rows; r++) { Spring height = Spring.constant(0); for (int c = 0; c < cols; c++) { height = Spring.max(height, getConstraintsForCell(r, c, parent, cols). getHeight()); } for (int c = 0; c < cols; c++) { SpringLayout.Constraints constraints = getConstraintsForCell(r, c, parent, cols); constraints.setY(y); constraints.setHeight(height); } y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); } //Set the parent's size. SpringLayout.Constraints pCons = layout.getConstraints(parent); pCons.setConstraint(SpringLayout.SOUTH, y); pCons.setConstraint(SpringLayout.EAST, x); } } *************************************************************************************** Utility.java *************************************************************************************** package acsl.dTank; import acsl.dTank.afv.Location; public class Utility { /** * Testing methods * @param args */ public static void main(String args[]){ System.out.println(shorten(10.343213131321123)); System.out.println("Angle: "+calculateTargetHeading(0.0,0.0,10.0,-10.0)); System.out.println("Angle: "+Math.toDegrees(calculateAngle(0.0,0.0,10.0,-10.0))); } // 2.3451 => "2.3" // mp: a little faster public static String shorten(double d) { d = (double)((int)(d*1000))/1000.0; return String.valueOf(d); /* String s = "" + d; int dot = s.indexOf("."); if (dot == -1) return s; if (s.length() > dot + 3) return s.substring(0, dot + 3); return s; */ } public static double parseHeading(String heading) { double d = Double.parseDouble(heading); return normalizeAngle(d); } public static double normalizeAngle(double d) { return d % 360.0; /*while (d > 360.0) d -= 360.0; while (d < 0.0) d += 360.0; return d;*/ } /** * Calculate angle to point from x0,y0 to x1,y1 in radians * @param x0 * @param y0 * @param x1 * @param y1 * @return radians */ public static double calculateAngle(double x0, double y0, double x1, double y1) { double deltaX = (x1 - x0); double deltaY = (y1 - y0); if (deltaX == deltaY && deltaY == 0.0) return 0.0; double theta; // if (deltaY == 0.0) theta = (deltaX > 0.0) ? Math.PI / 2 : 3 * Math.PI // / 2; else theta = Math.atan(deltaY / deltaX); if (deltaX < 0) theta += Math.PI; /*if (theta < 0) theta += Math.PI * 2; if (theta > Math.PI * 2) theta -= Math.PI * 2;*/ //theta %= (Math.PI*2); theta = (theta+Math.PI/2) % (Math.PI*2); return theta; } // x0,y0 is ME, x1,y1 is the target public static double calculateTargetHeading(double x0, double y0, double x1, double y1) { double deltaX = (x1 - x0); double deltaY = (y1 - y0); if (deltaX == deltaY && deltaY == 0.0) return 0.0; double theta; // if (deltaY == 0.0) theta = (deltaX > 0.0) ? Math.PI / 2 : 3 * Math.PI // / 2; else theta = Math.atan(deltaY / deltaX); if (deltaX < 0) theta += Math.PI; /*if (theta < 0) theta += Math.PI * 2; if (theta > Math.PI * 2) theta -= Math.PI * 2;*/ theta = (theta+Math.PI/2) % (Math.PI*2); return Math.toDegrees(theta); } /** * Calculate the linear distance * @param x0 * @param y0 * @param x1 * @param y1 * @return */ public static double calculateDistance(double x0, double y0, double x1, double y1) { return Math.sqrt(calculateDistance2(x0,y0,x1,y1)); } /** * Calculate the distance squared * @param x0 * @param y0 * @param x1 * @param y1 * @return */ public static double calculateDistance2(double x0, double y0, double x1, double y1){ double dx = x0 - x1; double dy = y0 - y1; return (dx * dx) + (dy * dy); } public static double distance(Location l0, Location l1) { return calculateDistance(l0.getX(), l0.getY(), l1.getX(), l1.getY()); } } *************************************************************************************** END OF FILE EOF ***************************************************************************************