From 71d7008a0cf072e28bb312e4b3b7bf7c6ecbe4c4 Mon Sep 17 00:00:00 2001 From: tbavl <tbavl@MSI.ern.nps.edu> Date: Wed, 4 Sep 2024 10:32:04 -0700 Subject: [PATCH] Bavlsik Assignment 3 --- .../Bavlsik/BavlsikSimulationProgram.java | 583 ++++++++++-------- .../homework3/Bavlsik/README.md | 42 +- 2 files changed, 339 insertions(+), 286 deletions(-) diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/BavlsikSimulationProgram.java b/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/BavlsikSimulationProgram.java index 21463b4b64..639f00e31e 100644 --- a/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/BavlsikSimulationProgram.java +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/BavlsikSimulationProgram.java @@ -1,7 +1,9 @@ /** * Copyright (c) 2008-2023, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved. * This work is provided under a BSD open-source license, see project license.html or license.txt + * * @author brutzman@nps.edu + * @author timothy.bavlsik@nps.edu */ package MV3500Cohort2024JulySeptember.homework3.Bavlsik; @@ -12,156 +14,194 @@ import edu.nps.moves.dis7.pdus.*; import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.PduFactory; import java.time.LocalDateTime; +import java.util.Random; import java.util.logging.Level; import java.util.logging.Logger; -/** The purpose of this inheritable class is to provide an easily modifiable - * example simulation program that includes DIS-capable entities performing - * tasks of interest, and then reporting activity via PDUs to the network. - * Default program initialization includes PDU recording turned on by default. - * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramLog.txt" target="_blank">ExampleSimulationProgramLog.txt</a> - * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramPduCaptureLog.dislog" target="_blank">ExampleSimulationProgramPduCaptureLog.dislog</a> - * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramFlowDiagram.pdf" target="_blank">ExampleSimulationProgramFlowDiagram.pdf</a> - * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramWireshark.png" target="_blank">ExampleSimulationProgramWireshark.png</a> - * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramSequenceDiagram.png" target="_blank">ExampleSimulationProgramSequenceDiagram.png</a> +/** + * This program runs a simulation that initializes two entities, of which one will + * attempt to find and destroy the other, and one which will flee the other entity. + * Default program initialization includes PDU recording turned on by default. + * + * @see + * <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramLog.txt" target="_blank">ExampleSimulationProgramLog.txt</a> + * @see + * <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramPduCaptureLog.dislog" target="_blank">ExampleSimulationProgramPduCaptureLog.dislog</a> + * @see + * <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramFlowDiagram.pdf" target="_blank">ExampleSimulationProgramFlowDiagram.pdf</a> + * @see + * <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramWireshark.png" target="_blank">ExampleSimulationProgramWireshark.png</a> + * @see + * <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramSequenceDiagram.png" target="_blank">ExampleSimulationProgramSequenceDiagram.png</a> */ -public class BavlsikSimulationProgram -{ +public class BavlsikSimulationProgram { + /* **************************** infrastructure code, modification is seldom needed ************************* */ - - private String descriptor = this.getClass().getSimpleName(); - /** DIS channel defined by network address/port combination includes multiple utility capabilities */ + + private String descriptor = this.getClass().getSimpleName(); + /** + * DIS channel defined by network address/port combination includes multiple + * utility capabilities + */ protected DisChannel disChannel; - /** Factory object used to create new PDU instances */ + /** + * Factory object used to create new PDU instances + */ protected PduFactory pduFactory; - - /** seconds per loop for real-time or simulation execution */ - private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate - /** initial simulation time in seconds */ - double simulationTimeInitial = 0.0; - /** current simulation time in seconds */ - double simulationTimeSeconds = simulationTimeInitial; - /** Maximum number of simulation loops */ + + /** + * seconds per loop for real-time or simulation execution + */ + private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate + /** + * initial simulation time in seconds + */ + double simulationTimeInitial = 0.0; + /** + * current simulation time in seconds + */ + double simulationTimeSeconds = simulationTimeInitial; + /** + * Maximum number of simulation loops + */ int MAX_LOOP_COUNT = 4; - + String narrativeMessage1 = new String(); String narrativeMessage2 = new String(); String narrativeMessage3 = new String(); - - /** EntityID settings for entity 1 */ - protected EntityID entityID_1 = new EntityID(); - /** EntityID settings for entity 2 */ - protected EntityID entityID_2 = new EntityID(); - /** ESPDU for entity 1 */ - protected EntityStatePdu entityStatePdu_1; - /** ESPDU for entity 2 */ - protected EntityStatePdu entityStatePdu_2; - /** FirePdu for entity 1 first weapon (if any) */ - protected FirePdu firePdu_1a; - /** FirePdu for entity 1 second weapon (if any) */ - protected FirePdu firePdu_1b; - /** MunitionDescriptor for these weapons */ + + /** + * EntityID settings for entity 1 + */ + protected EntityID entityID_1 = new EntityID(); + /** + * EntityID settings for entity 2 + */ + protected EntityID entityID_2 = new EntityID(); + /** + * ESPDU for entity 1 + */ + protected EntityStatePdu entityStatePdu_1; + /** + * ESPDU for entity 2 + */ + protected EntityStatePdu entityStatePdu_2; + /** + * FirePdu for entity 1 first weapon (if any) + */ + protected FirePdu firePdu_1a; + /** + * FirePdu for entity 1 second weapon (if any) + */ + protected FirePdu firePdu_1b; + /** + * MunitionDescriptor for these weapons + */ protected MunitionDescriptor munitionDescriptor1; - + // hey programmer, what other state do you want? this is a good place to declare it... - /** - * Constructor to create an instance of this class. - * Design goal: additional built-in initialization conveniences can go here - * to keep your efforts focused on the runSimulation() method. + * Constructor to create an instance of this class. Design goal: additional + * built-in initialization conveniences can go here to keep your efforts + * focused on the runSimulation() method. */ // base constructor is not invoked automatically by other constructors // https://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java - public BavlsikSimulationProgram() - { + public BavlsikSimulationProgram() { initialize(); } + /** * Constructor to create an instance of this class. - * @param newDescriptor describes this program, useful for logging and debugging + * + * @param newDescriptor describes this program, useful for logging and + * debugging */ - public BavlsikSimulationProgram(String newDescriptor) - { + public BavlsikSimulationProgram(String newDescriptor) { descriptor = newDescriptor; initialize(); } + /** - * Utility Constructor that allows your example simulation program to override default network address and port + * Utility Constructor that allows your example simulation program to + * override default network address and port + * * @param address network address to use * @param port corresponding network port to use */ - public BavlsikSimulationProgram(String address, int port) - { - disChannel.setNetworkAddress (address); - disChannel.setNetworkPort (port); - disChannel.setVerboseComments (true); // TODO rename library method to disambiguate CommentPDU - // TODO still seems really chatty... add silent mode? + public BavlsikSimulationProgram(String address, int port) { + disChannel.setNetworkAddress(address); + disChannel.setNetworkPort(port); + disChannel.setVerboseComments(true); // TODO rename library method to disambiguate CommentPDU + // TODO still seems really chatty... add silent mode? disChannel.setVerboseDisNetworkInterface(true); // Default false - disChannel.setVerbosePduRecorder (true); // default false + disChannel.setVerbosePduRecorder(true); // default false initialize(); } - - /** Initialize channel setup for OpenDis7 and report a test PDU + + /** + * Initialize channel setup for OpenDis7 and report a test PDU + * * @see initializeDisChannel - * @see initializeSimulationEntities */ - private void initialize() - { + * @see initializeSimulationEntities + */ + private void initialize() { initializeDisChannel(); // must come first, uses PduFactory - + initializeSimulationEntities(); // set unchanging parameters - + disChannel.join(); // TODO further functionality expected - + String timeStepMessage = "Simulation timestep duration " + getSimulationTimeStepDuration() + " seconds"; disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_SIMULATION_TIMESTEP, timeStepMessage); // additional constructor initialization can go here } - - /** Initialize channel setup for OpenDis7 and report a test PDU */ - private void initializeDisChannel() - { - if (disChannel == null) + + /** + * Initialize channel setup for OpenDis7 and report a test PDU + */ + private void initializeDisChannel() { + if (disChannel == null) { disChannel = new DisChannel(); - else - { - disChannel.printlnTRACE ("*** warning, duplicate invocation of initializeDisChannel() ignored"); + } else { + disChannel.printlnTRACE("*** warning, duplicate invocation of initializeDisChannel() ignored"); return; } - pduFactory = disChannel.getPduFactory(); + pduFactory = disChannel.getPduFactory(); disChannel.setDescriptor(this.getClass().getSimpleName()); // ExampleSimulationProgram might be a superclass disChannel.setUpNetworkInterface(); - disChannel.printlnTRACE ("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress() + - ", getNetworkPort()=" + disChannel.getNetworkPort()); - disChannel.getDisNetworkInterface().setVerbose(true); // sending and receipt - disChannel.printlnTRACE ("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending() + - ", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt()); - disChannel.getPduRecorder().setVerbose(true); + disChannel.printlnTRACE("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress() + + ", getNetworkPort()=" + disChannel.getNetworkPort()); + disChannel.getDisNetworkInterface().setVerbose(false); // sending and receipt + disChannel.printlnTRACE("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending() + + ", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt()); + disChannel.getPduRecorder().setVerbose(false); // TODO confirm whether recorder is explicitly started by programmer (or not) - // disChannel.sendCommentPdu(VariableRecordType.OTHER, "DisThreadedNetworkInterface.initializeDisChannel() complete"); // hello channel, debug } - - /** Get ready, get set... initialize simulation entities. Who's who in the zoo? + + /** + * Get ready, get set... initialize simulation entities. Who's who in the + * zoo? */ - public void initializeSimulationEntities() - { - if (pduFactory == null) - pduFactory = disChannel.getPduFactory(); - entityStatePdu_1 = pduFactory.makeEntityStatePdu(); - entityStatePdu_2 = pduFactory.makeEntityStatePdu(); - firePdu_1a = pduFactory.makeFirePdu(); - firePdu_1b = pduFactory.makeFirePdu(); + public void initializeSimulationEntities() { + if (pduFactory == null) { + pduFactory = disChannel.getPduFactory(); + } + entityStatePdu_1 = pduFactory.makeEntityStatePdu(); + entityStatePdu_2 = pduFactory.makeEntityStatePdu(); + firePdu_1a = pduFactory.makeFirePdu(); + firePdu_1b = pduFactory.makeFirePdu(); munitionDescriptor1 = new MunitionDescriptor(); - + // Your model setup: define participants. who's who in this zoo? // Assuming you keep track of entity objects... here is some support for for Entity 1. - // PDU objects are already declared and instances created, so now set their values. // who is who in our big zoo, sufficient for global participation if we need it entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID; disChannel.addEntity(entityID_1); - + entityID_2.setSiteID(1).setApplicationID(2).setEntityID(4); // made-up example ID; disChannel.addEntity(entityID_2); // TODO someday, use enumerations for sites as part of a SimulationManager object; e.g. is there a unique site triplet for MOVES Institute? @@ -178,181 +218,215 @@ public class BavlsikSimulationProgram entityStatePdu_2.setForceId(ForceID.OPPOSING); entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above entityStatePdu_2.setMarking("Entity #2"); + //Initialize entity2's location to a random spot from (0,0,0) to (10,10,0) + Random random = new Random(); + int randX = random.nextInt(10); + int randY = random.nextInt(10); + entityStatePdu_2.getEntityLocation().setX(randX); + entityStatePdu_2.getEntityLocation().setY(randY); // TODO how should we customize this munition? what are key parameters for your simulation? // more is needed here by scenario authors... munitionDescriptor1.setQuantity(1); - firePdu_1a.setDescriptor(munitionDescriptor1).setRange(1000.0f); + firePdu_1a.setDescriptor(munitionDescriptor1).setRange(3.0f); } - + /** - * This runSimulationLoops() method is for you, a customizable programmer-modifiable - * code block for defining and running a new simulation of interest. - * - * Welcome! Other parts of this program handle bookkeeping and plumbing tasks so that - * you can focus on your model entities and activities. - * Expandable support includes DIS EntityStatePdu, FirePdu and CommentPdu all available for - * modification and sending in a simulation loop. - * Continuous improvement efforts seek to make this program as easy and straightforward - * as possible for DIS simulationists to use and adapt. - * All of the other methods are setup, teardown and configuration that you may find - * interesting, even helpful, but don't really have to worry about. + * This runSimulationLoops() method is for you, a customizable + * programmer-modifiable code block for defining and running a new + * simulation of interest. + * + * Welcome! Other parts of this program handle bookkeeping and plumbing + * tasks so that you can focus on your model entities and activities. + * Expandable support includes DIS EntityStatePdu, FirePdu and CommentPdu + * all available for modification and sending in a simulation loop. + * Continuous improvement efforts seek to make this program as easy and + * straightforward as possible for DIS simulationists to use and adapt. All + * of the other methods are setup, teardown and configuration that you may + * find interesting, even helpful, but don't really have to worry about. */ @SuppressWarnings("SleepWhileInLoop") // yes we might do that - public void runSimulationLoops () - { - try - { - final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops. - int simulationLoopCount = 0; // variable, initialized at 0 - boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet? - - // TODO reset Clock Time for today's date and timestamp to zero, providing consistent outputs for each simulation run - String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now(); - disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage); - // TODO replace enumeration with disChannel.COMMENTPDU_TIME - // TODO fix VariableRecordType.TIME_AMP_DATE_VALID - - // =================================================================================================== - // loop the simulation while allowed, programmer can set additional conditions to break out and finish - while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet? - { - simulationLoopCount++; // good practice: increment loop counter as first action in that loop - - // ============================================================================================= - // * your own simulation code starts here! ***************************************************** - // ============================================================================================= - - // are there any other variables to modify at the beginning of your loop? - - // are your reading any DIS PDUs from the network? check for them here - - // compute a track, update an ESPDU, whatever it is that your model is doing... - - // Where is my entity? Insert changes in position; this sample only changes X position. - entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + 1.0); // 1m per timestep - - // decide whether to fire, and then update the firePdu. Hmmm, you might want a target to shoot at! - - // etc. etc. your code goes here for your simulation of interest - - // something happens between my simulation entities, la de da de da... - System.out.println ("... My simulation just did something, no really..."); - System.out.flush(); // make sure this arrives to user even if other threads somehow become deadlocked - - - // make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending) - narrativeMessage1 = "MV3500 ExampleSimulationProgram"; - narrativeMessage2 = "runSimulation() loop " + simulationLoopCount; - narrativeMessage3 = ""; // intentionally blank for testing - - // your loop termination condition goes here - if (simulationLoopCount > MAX_LOOP_COUNT) // for example - { - simulationComplete = true; - } - // ============================================================================================= - // * your own simulation code is finished here! ************************************************ - // ============================================================================================= - - // staying synchronized with timestep: wait duration for elapsed time in this loop - // Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes - Thread.sleep((long)(getSimulationTimeStepDuration() * 1000)); // units of seconds * (1000 msec/sec) = milliseconds - System.out.println ("... [Pausing for " + getSimulationTimeStepDuration() + " seconds]"); - - // OK now send the status PDUs for this loop, and then continue - System.out.println ("... sending PDUs of interest for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent"); - System.out.flush(); - - // TODO set timesteps in PDUs - - sendAllPdusForLoopTimestep(simulationTimeSeconds, - entityStatePdu_1, - firePdu_1a, - DisChannel.COMMENTPDU_APPLICATION_STATUS, - narrativeMessage1, narrativeMessage2, narrativeMessage3); - disChannel.sendSinglePdu(simulationTimeSeconds, entityStatePdu_2); // me too i.e. 2! - - System.out.println ("... [PDUs of interest successfully sent for this loop]"); - System.out.flush(); - - // =============================== - // current loop now finished, check whether to terminate if simulation complete, otherwise continue - if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good + public void runSimulationLoops() { + Random random = new Random(); + boolean killFlag = false;//updates if the hunter kills its prey. + try { + final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops. + int simulationLoopCount = 0; // variable, initialized at 0 + boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet? + + // TODO reset Clock Time for today's date and timestamp to zero, providing consistent outputs for each simulation run + String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now(); + disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage); + // TODO replace enumeration with disChannel.COMMENTPDU_TIME + // TODO fix VariableRecordType.TIME_AMP_DATE_VALID + + // =================================================================================================== + // loop the simulation while allowed, programmer can set additional conditions to break out and finish + while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet? { - System.out.println ("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount + + simulationLoopCount++; // good practice: increment loop counter as first action in that loop + + // ============================================================================================= + // * your own simulation code starts here! ***************************************************** + // ============================================================================================= + Vector3Double entity2Location = entityStatePdu_2.getEntityLocation(); + Vector3Double entity1Location = entityStatePdu_1.getEntityLocation(); + System.out.println(entity1Location); + System.out.println(entity2Location); + Double deltaX = entity2Location.getX() - entity1Location.getX(); + Double deltaY = entity2Location.getY() - entity1Location.getY(); + System.out.println("1x: " + entity1Location.getX() + " 1y: " + entity1Location.getY() + " deltaX " + deltaX + " deltaY " + deltaY); + System.out.println("2x: " + entity2Location.getX() + " 2y: " + entity2Location.getY()); + Double magnitude = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY)); + System.out.println(magnitude); + // are there any other variables to modify at the beginning of your loop? + + // are your reading any DIS PDUs from the network? check for them here + // compute a track, update an ESPDU, whatever it is that your model is doing... + // Where is my entity? Insert changes in position; this sample only changes X position.& +// entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + 1.0); // 1m per timestep + if (magnitude <= firePdu_1a.getRange()) { + System.out.println(entityStatePdu_1.getEntityID() + " FIRING AT " + entityStatePdu_2.getEntityID() + "...."); + double pKill = 0.5; //probability of a hit + double shot = random.nextDouble(); + System.out.println(shot); + if (shot <= pKill) { + System.out.println("...HIT!"); + killFlag = true; + } else { + System.out.println("...MISS!"); + } + } else { + entityStatePdu_1.getEntityLocation().setX(entityStatePdu_1.getEntityLocation().getX() + (2 * deltaX / magnitude)); + entityStatePdu_1.getEntityLocation().setY(entityStatePdu_1.getEntityLocation().getY() + (2 * deltaY / magnitude)); + } + //Entity2 moves away from entity 1 + entityStatePdu_2.getEntityLocation().setX(entityStatePdu_2.getEntityLocation().getX() + (deltaX / magnitude)); + entityStatePdu_2.getEntityLocation().setY(entityStatePdu_2.getEntityLocation().getY() + (deltaY / magnitude)); + System.out.flush(); // make sure this arrives to user even if other threads somehow become deadlocked + + // make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending) + narrativeMessage1 = "MV3500 ExampleSimulationProgram"; + narrativeMessage2 = "runSimulation() loop " + simulationLoopCount; + narrativeMessage3 = ""; // intentionally blank for testing + + // your loop termination condition goes here + if (killFlag) { + simulationComplete = true; + } + // ============================================================================================= + // * your own simulation code is finished here! ************************************************ + // ============================================================================================= + + // staying synchronized with timestep: wait duration for elapsed time in this loop + // Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes + Thread.sleep((long) (getSimulationTimeStepDuration() * 1000)); // units of seconds * (1000 msec/sec) = milliseconds + System.out.println("... [Pausing for " + getSimulationTimeStepDuration() + " seconds]"); + + // OK now send the status PDUs for this loop, and then continue + System.out.println("... sending PDUs of interest for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent"); System.out.flush(); - break; + + // TODO set timesteps in PDUs + sendAllPdusForLoopTimestep(simulationTimeSeconds, + entityStatePdu_1, + firePdu_1a, + DisChannel.COMMENTPDU_APPLICATION_STATUS, + narrativeMessage1, narrativeMessage2, narrativeMessage3); + disChannel.sendSinglePdu(simulationTimeSeconds, entityStatePdu_2); // me too i.e. 2! + + System.out.println("... [PDUs of interest successfully sent for this loop]"); + System.out.flush(); + + // =============================== + // current loop now finished, check whether to terminate if simulation complete, otherwise continue + if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good + { + System.out.println("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount + + System.out.flush(); + break; + } + simulationTimeSeconds += getSimulationTimeStepDuration(); // good practice: increment simulationTime as lastst action in that loop + + } // end of simulation loop, continue until done + // ===================================================================================================// ===================================================================================================// ===================================================================================================// =================================================================================================== + if(simulationComplete){ + System.out.println("Good guys sank the bads guys!"); + } + else{ + System.out.println("Bad guys got away... we'll get em' next time boys."); } - simulationTimeSeconds += getSimulationTimeStepDuration(); // good practice: increment simulationTime as lastst action in that loop - - } // end of simulation loop, continue until done - // ===================================================================================================// ===================================================================================================// ===================================================================================================// =================================================================================================== - - narrativeMessage2 = "runSimulation() completed successfully"; // all done, so tell everyone else on the channel - // TODO better javadoc needs to be autogenerated for VariableRecordType enumerations - disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); - System.out.println ("... [final=completion CommentPdu successfully sent for simulation]"); - + narrativeMessage2 = "runSimulation() completed successfully"; // all done, so tell everyone else on the channel + // TODO better javadoc needs to be autogenerated for VariableRecordType enumerations + disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); + System.out.println("... [final=completion CommentPdu successfully sent for simulation]"); + // disChannel.getPduRecorder(). TODO record XML as well - disChannel.leave(); // embedded SimulationManager is expected to send appropriate PDUs for entity, application shutdown - } - catch (InterruptedException iex) // handle any exception that your code might choose to provoke! - { - Logger.getLogger(BavlsikSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex); - } + disChannel.leave(); // embedded SimulationManager is expected to send appropriate PDUs for entity, application shutdown + } catch (InterruptedException iex) // handle any exception that your code might choose to provoke! + { + Logger.getLogger(BavlsikSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex); + } } /** - * Send EntityState, Fire, Comment PDUs that got updated for this loop, reflecting state of current simulation timestep. - * @param simTimeSeconds simulation time in second, applied to PDU as timestamp + * Send EntityState, Fire, Comment PDUs that got updated for this loop, + * reflecting state of current simulation timestep. + * + * @param simTimeSeconds simulation time in second, applied to PDU as + * timestamp * @param entityStatePdu the ESPDU to send, if any - * @param firePdu the FirePDU to send, if any - * @param commentType enumeration value describing purpose of the narrative comment PDU - * @param comments String array of narrative comments - * @see DisChannel -// * @see DisTime // TODO find renamed version - * @see <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html" target="_blank">Passing Information to a Method or a Constructor</a> Arbitrary Number of Arguments + * @param firePdu the FirePDU to send, if any + * @param commentType enumeration value describing purpose of the narrative + * comment PDU + * @param comments String array of narrative comments + * @see DisChannel // * @see DisTime // TODO find renamed version + * @see + * <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html" target="_blank">Passing + * Information to a Method or a Constructor</a> Arbitrary Number of + * Arguments */ public void sendAllPdusForLoopTimestep(double simTimeSeconds, - EntityStatePdu entityStatePdu, - FirePdu firePdu, - VariableRecordType commentType, - // vararg... variable-length set of String comments can optionally follow - String... comments) - { - if (entityStatePdu != null) + EntityStatePdu entityStatePdu, + FirePdu firePdu, + VariableRecordType commentType, + // vararg... variable-length set of String comments can optionally follow + String... comments) { + if (entityStatePdu != null) { disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu); - - if (firePdu != null) + } + + if (firePdu != null) { disChannel.sendSinglePdu(simTimeSeconds, firePdu); // bang - + } disChannel.sendCommentPdu(simTimeSeconds, commentType, comments); // empty comments are filtered } - + /** - * Initial execution via main() method: handle args array of command-line initialization (CLI) arguments here + * Initial execution via main() method: handle args array of command-line + * initialization (CLI) arguments here + * * @param args command-line parameters: network address and port */ - protected void handleArguments (String[] args) - { + protected void handleArguments(String[] args) { // initial execution: handle args array of initialization arguments here - if (args.length == 2) - { - if ((args[0] != null) && !args[0].isEmpty()) + if (args.length == 2) { + if ((args[0] != null) && !args[0].isEmpty()) { thisProgram.disChannel.setNetworkAddress(args[0]); - if ((args[1] != null) && !args[1].isEmpty()) + } + if ((args[1] != null) && !args[1].isEmpty()) { thisProgram.disChannel.setNetworkPort(Integer.parseInt(args[1])); - } - else if (args.length != 0) - { + } + } else if (args.length != 0) { System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]"); System.exit(-1); } } /** - * Get simple descriptor (such as parent class name) for this network interface, used in trace statements + * Get simple descriptor (such as parent class name) for this network + * interface, used in trace statements + * * @return simple descriptor name */ public String getDescriptor() { @@ -360,17 +434,21 @@ public class BavlsikSimulationProgram } /** - * Set new simple descriptor (such as parent class name) for this network interface, used in trace statements + * Set new simple descriptor (such as parent class name) for this network + * interface, used in trace statements + * * @param newDescriptor simple descriptor name for this interface */ public void setDescriptor(String newDescriptor) { - if (newDescriptor == null) + if (newDescriptor == null) { newDescriptor = ""; + } this.descriptor = newDescriptor; } /** * parameter accessor method + * * @return the simulationTimeStepDuration in seconds */ public double getSimulationTimeStepDuration() { @@ -379,35 +457,42 @@ public class BavlsikSimulationProgram /** * parameter accessor method - * @param timeStepDurationSeconds the simulationTimeStepDuration in seconds to set + * + * @param timeStepDurationSeconds the simulationTimeStepDuration in seconds + * to set */ public void setSimulationTimeStepDuration(double timeStepDurationSeconds) { this.simulationTimeStepDuration = timeStepDurationSeconds; } - - /** Locally instantiable copy of program, can be subclassed. */ + + /** + * Locally instantiable copy of program, can be subclassed. + */ protected static BavlsikSimulationProgram thisProgram; - + /** * Main method is first executed when a program instance is loaded. - * @see <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html" target="_blank">Java Tutorials: A Closer Look at the "Hello World!" Application</a> + * + * @see + * <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html" target="_blank">Java + * Tutorials: A Closer Look at the "Hello World!" Application</a> * @param args command-line parameters: network address and port. - * Command-line arguments are an array of optional String parameters that are passed from execution environment during invocation + * Command-line arguments are an array of optional String parameters that + * are passed from execution environment during invocation */ - public static void main(String[] args) - { + public static void main(String[] args) { thisProgram = new BavlsikSimulationProgram("test constructor"); // create instance of self within static main() method - + thisProgram.disChannel.printlnTRACE("main() started..."); - + thisProgram.handleArguments(args); // process any command-line invocation arguments thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ... - + thisProgram.disChannel.tearDownNetworkInterface(); // make sure no processes are left lingering - + thisProgram.disChannel.printlnTRACE("complete."); // report successful completion - + System.exit(0); // ensure all threads and sockets released } } diff --git a/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/README.md b/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/README.md index c5aadebfdc..4827a529dc 100644 --- a/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/README.md +++ b/assignments/src/MV3500Cohort2024JulySeptember/homework3/Bavlsik/README.md @@ -1,38 +1,6 @@ ## Homework 3: Example Simulation Recording using OpenDIS Network Streams - -<!-- Viewable at https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/assignments/src/MV3500Cohort2024JulySeptember/homework3/README.md --> - -### Assignment - -1. Adapt the functionality for [OpenDIS ExampleSimulationProgram](../../../../examples/src/OpenDis7Examples/ExampleSimulationProgram.java), modifying provided code -2. Experiment with the enumeration values that set up each entity and PDU. What works for you? What makes sense for your future work? -3. Adapt or replace the UML diagrams to describe what you have going on. -4. Record, save and replay your result stream using [PduRecorder](https://savage.nps.edu/opendis7-java/javadoc/edu/nps/moves/dis7/utilities/stream/PduRecorder.html) or [Wireshark](https://www.wireshark.org) - * see local [assignments/src/pduLog](../../../pduLog) subdirectory for latest opendis log files - * Coming soon, we will also (again have) [X3D-Edit](https://savage.nps.edu/X3D-Edit) for DIS stream recording/replay -5. Observe good-practice conventions in the [assignments README](../../../README.md) and [current-course README](../README.md) instructions. - -This assignment presents a Problem Prototyping opportunity. -While some minimal functionality is expected, the general outline of -a networking problem and proposed solution holds great interest. -Think of it as warmup preparation for your future work. - -This is also a freeplay opportunity. -You have the option to pick one or more of the provided course example programs -and adapt the source to demonstrate a new client-server handshake protocol of interest. - -Be sure to provide a rationale that justifies why the networking choices you made -(TCP/UDP, unicast/multicast, etc.) are the best for the problem you are addressing. - -You may find that the prior [homework2 README](../homework2/README.md) still provides -helpful details on what specific deliverables are expected in each homework assignment. - -Team efforts are encouraged, though if you choose a team approach be sure to justify why. -This is a good warmup prior to final projects. Have fun with Java networking! - -### Prior Assignment, August 2019 - -In 2019, students worked together on a single project to check wireless multicast connectivity recently deployed on NPS campus. - -See their experimental results in the [NPS Multicast Connectivity Report](../../MV3500Cohort2019JulySeptember/homework3). - +This program runs a simulation between two entites. One entity is initialized at +(0,0,0) and the other is randomly placed. The hunter entity moves towards the prey +entity until it is in range. When in range the hunter attempts to shoot the prey. +If successful, the simulation ends. The prey entity constantly attemps to move away +from the hunter. \ No newline at end of file -- GitLab