Skip to content
Snippets Groups Projects
Commit 86812928 authored by tjsus's avatar tjsus
Browse files

Assignment 3 code added.

parent 7c243eb5
No related branches found
No related tags found
No related merge requests found
/**
* 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 tjsus
*/
package MV3500Cohort2024JulySeptember.homework3.Smith; package MV3500Cohort2024JulySeptember.homework3.Smith;
import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon;
import edu.nps.moves.dis7.entities.swe.platform.surface._002Triton;
import edu.nps.moves.dis7.enumerations.*;
import edu.nps.moves.dis7.pdus.*; import edu.nps.moves.dis7.pdus.*;
import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.DisChannel;
import edu.nps.moves.dis7.utilities.PduFactory; import edu.nps.moves.dis7.utilities.PduFactory;
import java.time.LocalDateTime;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
...@@ -19,395 +10,232 @@ import java.util.logging.Logger; ...@@ -19,395 +10,232 @@ import java.util.logging.Logger;
* example simulation program that includes DIS-capable entities performing * example simulation program that includes DIS-capable entities performing
* tasks of interest, and then reporting activity via PDUs to the network. * tasks of interest, and then reporting activity via PDUs to the network.
* Default program initialization includes PDU recording turned on by default. * 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 ExampleSimulationProgram public class ExampleSimulationProgram {
{
/* **************************** infrastructure code, modification is seldom needed ************************* */ // Constants for the Battleship game
private static final int GRID_SIZE = 10; // 10x10 grid for Battleship
private String descriptor = this.getClass().getSimpleName(); private static final int MAX_TURNS = 100; // Limit turns to avoid infinite games
/** DIS channel defined by network address/port combination includes multiple utility capabilities */
// Grids for each player
private char[][] player1Grid = new char[GRID_SIZE][GRID_SIZE];
private char[][] player2Grid = new char[GRID_SIZE][GRID_SIZE];
// To track whose turn it is
private boolean isPlayer1Turn = true;
// Ship positions (simple example positions for each player's ships)
private final int[][] player1Ships = {{0, 0}, {0, 1}, {0, 2}}; // Positions for player 1's ships
private final int[][] player2Ships = {{5, 5}, {5, 6}, {5, 7}}; // Positions for player 2's ships
// DIS utilities
private String descriptor = this.getClass().getSimpleName();
protected DisChannel disChannel; protected DisChannel disChannel;
/** Factory object used to create new PDU instances */
protected PduFactory pduFactory; protected PduFactory pduFactory;
protected FirePdu firePduPlayer1;
/** seconds per loop for real-time or simulation execution */ protected FirePdu firePduPlayer2;
private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate protected MunitionDescriptor munitionDescriptor1 = new MunitionDescriptor();
/** initial simulation time in seconds */
double simulationTimeInitial = 0.0; // Simulation time settings
/** current simulation time in seconds */ private double simulationTimeStepDuration = 1.0; // seconds
double simulationTimeSeconds = simulationTimeInitial; private double simulationTimeSeconds = 0.0;
/** Maximum number of simulation loops */
int MAX_LOOP_COUNT = 4; // Tracking indices for Player 1's systematic search
private int player1SearchRow = 0;
String narrativeMessage1 = new String(); private int player1SearchCol = 0;
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 */
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. * Constructor to create an instance of this class.
* Design goal: additional built-in initialization conveniences can go here * Design goal: additional built-in initialization conveniences can go here
* to keep your efforts focused on the runSimulation() method. * to keep your efforts focused on the runSimulation() method.
*/ */
// base constructor is not invoked automatically by other constructors public ExampleSimulationProgram() {
// https://stackoverflow.com/questions/581873/best-way-to-handle-multiple-constructors-in-java
public ExampleSimulationProgram()
{
initialize(); initialize();
} }
/**
* Constructor to create an instance of this class. /**
* @param newDescriptor describes this program, useful for logging and debugging * Initialize the simulation program, setting up the DIS channel,
* PDUs, and the Battleship game grids.
*/ */
public ExampleSimulationProgram(String newDescriptor) private void initialize() {
{ initializeDisChannel();
descriptor = newDescriptor; initializeSimulationEntities();
initialize(); setupGrids();
disChannel.join();
} }
/**
* Utility Constructor that allows your example simulation program to override default network address and port /**
* @param address network address to use * Initialize the DIS channel for communication, setting verbose output
* @param port corresponding network port to use * for debugging and creating the PduFactory.
*/ */
public ExampleSimulationProgram(String address, int port) private void initializeDisChannel() {
{ disChannel = new DisChannel();
disChannel.setNetworkAddress (address); pduFactory = disChannel.getPduFactory();
disChannel.setNetworkPort (port); disChannel.setDescriptor(this.getClass().getSimpleName());
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
initialize();
}
/** Initialize channel setup for OpenDis7 and report a test PDU
* @see initializeDisChannel
* @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)
disChannel = new DisChannel();
else
{
disChannel.printlnTRACE ("*** warning, duplicate invocation of initializeDisChannel() ignored");
return;
}
pduFactory = disChannel.getPduFactory();
disChannel.setDescriptor(this.getClass().getSimpleName()); // ExampleSimulationProgram might be a superclass
disChannel.setUpNetworkInterface(); disChannel.setUpNetworkInterface();
disChannel.printlnTRACE ("just checking: disChannel.getNetworkAddress()=" + disChannel.getNetworkAddress() +
", getNetworkPort()=" + disChannel.getNetworkPort());
disChannel.getDisNetworkInterface().setVerbose(true); // sending and receipt disChannel.getDisNetworkInterface().setVerbose(true); // sending and receipt
disChannel.printlnTRACE ("just checking: hasVerboseSending()=" + disChannel.getDisNetworkInterface().hasVerboseSending() +
", hasVerboseReceipt()=" + disChannel.getDisNetworkInterface().hasVerboseReceipt());
disChannel.getPduRecorder().setVerbose(true); disChannel.getPduRecorder().setVerbose(true);
// 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?
*/
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?
entityStatePdu_1.setEntityID(entityID_1); /**
entityStatePdu_1.setForceId(ForceID.FRIENDLY); * Initialize simulation entities by creating PDUs for firing events.
entityStatePdu_1.setEntityType(new _001Poseidon()); // note import statement above */
// entityStatePdu_1.setMarking("Entity #1"); private void initializeSimulationEntities() {
entityStatePdu_1.setEntityType(new edu.nps.moves.dis7.entities.usa.platform.air.MV22B()); // note import statement at top firePduPlayer1 = pduFactory.makeFirePdu();
entityStatePdu_1.setMarking("Entity #53"); firePduPlayer2 = pduFactory.makeFirePdu();
entityStatePdu_1.getMarkingString(); // use Netbeans Debug breakpoint here to check left justified... }
entityStatePdu_2.setEntityID(entityID_2); /**
entityStatePdu_2.setForceId(ForceID.OPPOSING); * Set up the game grids for each player, marking empty water and ship positions.
entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above */
entityStatePdu_2.setMarking("Entity #2"); private void setupGrids() {
// Initialize grids with empty water '~'
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
player1Grid[i][j] = '~';
player2Grid[i][j] = '~';
}
}
// TODO how should we customize this munition? what are key parameters for your simulation? // Place ships on the grids ('P' denotes a ship)
// more is needed here by scenario authors... for (int[] ship : player1Ships) {
munitionDescriptor1.setQuantity(1); player1Grid[ship[0]][ship[1]] = 'P';
firePdu_1a.setDescriptor(munitionDescriptor1).setRange(1000.0f); }
for (int[] ship : player2Ships) {
player2Grid[ship[0]][ship[1]] = 'P';
}
} }
/** /**
* This runSimulationLoops() method is for you, a customizable programmer-modifiable * This runSimulationLoops() method is for you, a customizable programmer-modifiable
* code block for defining and running a new simulation of interest. * 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() {
public void runSimulationLoops () int turnCount = 0;
{ while (turnCount < MAX_TURNS) {
try if (isPlayer1Turn) {
{ // Player 1 systematically searches Player 2's grid
final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops. int[] target = selectNextTargetForPlayer1();
int simulationLoopCount = 0; // variable, initialized at 0 handleFire(firePduPlayer1, player2Grid, target, "Player 1");
boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet? } else {
// Player 2 fires at Player 1 randomly
// TODO reset Clock Time for today's date and timestamp to zero, providing consistent outputs for each simulation run int[] target = selectRandomTarget();
String timeMessage = "Simulation time " + simulationTimeSeconds + " at LocalDateTime " + LocalDateTime.now(); handleFire(firePduPlayer2, player1Grid, target, "Player 2");
disChannel.sendCommentPdu(simulationTimeSeconds, DisChannel.COMMENTPDU_TIME, timeMessage); }
// TODO replace enumeration with disChannel.COMMENTPDU_TIME
// TODO fix VariableRecordType.TIME_AMP_DATE_VALID // Switch turns and increment turn counter
isPlayer1Turn = !isPlayer1Turn;
// =================================================================================================== turnCount++;
// 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 // Check for win conditions
if (simulationLoopCount > MAX_LOOP_COUNT) // for example if (checkWinCondition(player1Grid)) {
{ System.out.println("Player 2 wins!");
simulationComplete = true; break;
} } else if (checkWinCondition(player2Grid)) {
// ============================================================================================= System.out.println("Player 1 wins!");
// * 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
{
System.out.println ("... [loop termination condition met, simulationComplete=" + simulationComplete + "]"); // ", final loopCount=" + loopCount +
System.out.flush();
break; break;
} }
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 // Wait for the next simulation step
// TODO better javadoc needs to be autogenerated for VariableRecordType enumerations try {
disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); Thread.sleep((long) (simulationTimeStepDuration * 1000)); // units of seconds * (1000 msec/sec) = milliseconds
System.out.println ("... [final=completion CommentPdu successfully sent for simulation]"); } catch (InterruptedException iex) {
Logger.getLogger(ExampleSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex);
// 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(ExampleSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex);
}
}
/** // Increment simulation time
* Send EntityState, Fire, Comment PDUs that got updated for this loop, reflecting state of current simulation timestep. simulationTimeSeconds += simulationTimeStepDuration;
* @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
*/
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)
disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu);
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 * Systematically select the next target for Player 1 in a row-by-row manner.
* @param args command-line parameters: network address and port * @return the coordinates of the next target cell.
*/ */
protected void handleArguments (String[] args) private int[] selectNextTargetForPlayer1() {
{ // Systematically select the next target in a row-by-row manner
// initial execution: handle args array of initialization arguments here int[] target = {player1SearchRow, player1SearchCol};
if (args.length == 2)
{ // Move to the next column
if ((args[0] != null) && !args[0].isEmpty()) player1SearchCol++;
thisProgram.disChannel.setNetworkAddress(args[0]); // If end of row is reached, move to the next row and reset column
if ((args[1] != null) && !args[1].isEmpty()) if (player1SearchCol >= GRID_SIZE) {
thisProgram.disChannel.setNetworkPort(Integer.parseInt(args[1])); player1SearchCol = 0;
player1SearchRow++;
} }
else if (args.length != 0)
{ // Ensure search stays within grid bounds
System.err.println("Usage: " + thisProgram.getClass().getSimpleName() + " [address port]"); if (player1SearchRow >= GRID_SIZE) {
System.exit(-1); player1SearchRow = 0; // Reset search if bounds are exceeded
} }
}
/** return target;
* Get simple descriptor (such as parent class name) for this network interface, used in trace statements
* @return simple descriptor name
*/
public String getDescriptor() {
return descriptor;
} }
/** /**
* Set new simple descriptor (such as parent class name) for this network interface, used in trace statements * Randomly select a target on the grid for Player 2's turn.
* @param newDescriptor simple descriptor name for this interface * @return the coordinates of the randomly selected target cell.
*/ */
public void setDescriptor(String newDescriptor) { private int[] selectRandomTarget() {
if (newDescriptor == null) int x = (int) (Math.random() * GRID_SIZE);
newDescriptor = ""; int y = (int) (Math.random() * GRID_SIZE);
this.descriptor = newDescriptor; return new int[]{x, y};
} }
/** /**
* parameter accessor method * Handles the firing action, checking if the target is a hit or miss,
* @return the simulationTimeStepDuration in seconds * updating the grid, and sending the appropriate PDU.
* @param firePdu the FirePdu object to use for the shot.
* @param grid the grid of the player being fired at.
* @param target the coordinates of the target cell.
* @param player the name of the player firing the shot.
*/ */
public double getSimulationTimeStepDuration() { private void handleFire(FirePdu firePdu, char[][] grid, int[] target, String player) {
return simulationTimeStepDuration; int x = target[0];
int y = target[1];
// Fire at the target position
firePdu.setDescriptor(munitionDescriptor1).setRange(100.0f); // Example fire properties
if (grid[x][y] == 'P') {
grid[x][y] = 'H'; // Hit
System.out.println(player + " hits a ship at (" + x + ", " + y + ")!");
} else if (grid[x][y] == '~') {
grid[x][y] = 'M'; // Miss
System.out.println(player + " misses at (" + x + ", " + y + ").");
} else {
System.out.println(player + " fires at (" + x + ", " + y + ") but it's already hit/missed.");
}
// Send the fire PDU to reflect the shot
disChannel.sendSinglePdu(simulationTimeSeconds, firePdu);
} }
/** /**
* parameter accessor method * Checks the win condition by verifying if all ships on the grid have been hit.
* @param timeStepDurationSeconds the simulationTimeStepDuration in seconds to set * @param grid the grid to check.
* @return true if all ships are hit; false otherwise.
*/ */
public void setSimulationTimeStepDuration(double timeStepDurationSeconds) { private boolean checkWinCondition(char[][] grid) {
this.simulationTimeStepDuration = timeStepDurationSeconds; // Check if all ships have been hit
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (grid[i][j] == 'P') {
return false; // There are still ships left
}
}
}
return true; // All ships have been hit
} }
/** Locally instantiable copy of program, can be subclassed. */
protected static ExampleSimulationProgram thisProgram;
/** /**
* Main method is first executed when a program instance is loaded. * 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>
* @param args command-line parameters: network address and port. * @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) {
{ ExampleSimulationProgram game = new ExampleSimulationProgram();
thisProgram = new ExampleSimulationProgram("test constructor"); // create instance of self within static main() method game.runSimulationLoops();
System.out.println("Game Over");
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
} }
} }
package MV3500Cohort2024JulySeptember.homework3.Smith;
import edu.nps.moves.dis7.pdus.*;
import edu.nps.moves.dis7.utilities.DisChannel;
import edu.nps.moves.dis7.utilities.PduFactory;
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.
*/
public class ExampleSimulationProgramBattleShip {
// Constants for the Battleship game
private static final int GRID_SIZE = 10; // 10x10 grid for Battleship
private static final int MAX_TURNS = 100; // Limit turns to avoid infinite games
// Grids for each player
private char[][] player1Grid = new char[GRID_SIZE][GRID_SIZE];
private char[][] player2Grid = new char[GRID_SIZE][GRID_SIZE];
// To track whose turn it is
private boolean isPlayer1Turn = true;
// Ship positions (simple example positions for each player's ships)
private final int[][] player1Ships = {{0, 0}, {0, 1}, {0, 2}}; // Positions for player 1's ships
private final int[][] player2Ships = {{5, 5}, {5, 6}, {5, 7}}; // Positions for player 2's ships
// DIS utilities
private String descriptor = this.getClass().getSimpleName();
protected DisChannel disChannel;
protected PduFactory pduFactory;
protected FirePdu firePduPlayer1;
protected FirePdu firePduPlayer2;
protected MunitionDescriptor munitionDescriptor1 = new MunitionDescriptor();
// Simulation time settings
private double simulationTimeStepDuration = 1.0; // seconds
private double simulationTimeSeconds = 0.0;
// Tracking indices for Player 1's systematic search
private int player1SearchRow = 0;
private int player1SearchCol = 0;
/**
* 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.
*/
public ExampleSimulationProgramBattleShip() {
initialize();
}
/**
* Initialize the simulation program, setting up the DIS channel,
* PDUs, and the Battleship game grids.
*/
private void initialize() {
initializeDisChannel();
initializeSimulationEntities();
setupGrids();
disChannel.join();
}
/**
* Initialize the DIS channel for communication, setting verbose output
* for debugging and creating the PduFactory.
*/
private void initializeDisChannel() {
disChannel = new DisChannel();
pduFactory = disChannel.getPduFactory();
disChannel.setDescriptor(this.getClass().getSimpleName());
disChannel.setUpNetworkInterface();
disChannel.getDisNetworkInterface().setVerbose(true); // sending and receipt
disChannel.getPduRecorder().setVerbose(true);
}
/**
* Initialize simulation entities by creating PDUs for firing events.
*/
private void initializeSimulationEntities() {
firePduPlayer1 = pduFactory.makeFirePdu();
firePduPlayer2 = pduFactory.makeFirePdu();
}
/**
* Set up the game grids for each player, marking empty water and ship positions.
*/
private void setupGrids() {
// Initialize grids with empty water '~'
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
player1Grid[i][j] = '~';
player2Grid[i][j] = '~';
}
}
// Place ships on the grids ('P' denotes a ship)
for (int[] ship : player1Ships) {
player1Grid[ship[0]][ship[1]] = 'P';
}
for (int[] ship : player2Ships) {
player2Grid[ship[0]][ship[1]] = 'P';
}
}
/**
* This runSimulationLoops() method is for you, a customizable programmer-modifiable
* code block for defining and running a new simulation of interest.
*/
public void runSimulationLoops() {
int turnCount = 0;
while (turnCount < MAX_TURNS) {
if (isPlayer1Turn) {
// Player 1 systematically searches Player 2's grid
int[] target = selectNextTargetForPlayer1();
handleFire(firePduPlayer1, player2Grid, target, "Player 1");
} else {
// Player 2 fires at Player 1 randomly
int[] target = selectRandomTarget();
handleFire(firePduPlayer2, player1Grid, target, "Player 2");
}
// Switch turns and increment turn counter
isPlayer1Turn = !isPlayer1Turn;
turnCount++;
// Check for win conditions
if (checkWinCondition(player1Grid)) {
System.out.println("Player 2 wins!");
break;
} else if (checkWinCondition(player2Grid)) {
System.out.println("Player 1 wins!");
break;
}
// Wait for the next simulation step
try {
Thread.sleep((long) (simulationTimeStepDuration * 1000)); // units of seconds * (1000 msec/sec) = milliseconds
} catch (InterruptedException iex) {
Logger.getLogger(ExampleSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex);
}
// Increment simulation time
simulationTimeSeconds += simulationTimeStepDuration;
}
}
/**
* Systematically select the next target for Player 1 in a row-by-row manner.
* @return the coordinates of the next target cell.
*/
private int[] selectNextTargetForPlayer1() {
// Systematically select the next target in a row-by-row manner
int[] target = {player1SearchRow, player1SearchCol};
// Move to the next column
player1SearchCol++;
// If end of row is reached, move to the next row and reset column
if (player1SearchCol >= GRID_SIZE) {
player1SearchCol = 0;
player1SearchRow++;
}
// Ensure search stays within grid bounds
if (player1SearchRow >= GRID_SIZE) {
player1SearchRow = 0; // Reset search if bounds are exceeded
}
return target;
}
/**
* Randomly select a target on the grid for Player 2's turn.
* @return the coordinates of the randomly selected target cell.
*/
private int[] selectRandomTarget() {
int x = (int) (Math.random() * GRID_SIZE);
int y = (int) (Math.random() * GRID_SIZE);
return new int[]{x, y};
}
/**
* Handles the firing action, checking if the target is a hit or miss,
* updating the grid, and sending the appropriate PDU.
* @param firePdu the FirePdu object to use for the shot.
* @param grid the grid of the player being fired at.
* @param target the coordinates of the target cell.
* @param player the name of the player firing the shot.
*/
private void handleFire(FirePdu firePdu, char[][] grid, int[] target, String player) {
int x = target[0];
int y = target[1];
// Fire at the target position
firePdu.setDescriptor(munitionDescriptor1).setRange(100.0f); // Example fire properties
if (grid[x][y] == 'P') {
grid[x][y] = 'H'; // Hit
System.out.println(player + " hits a ship at (" + x + ", " + y + ")!");
} else if (grid[x][y] == '~') {
grid[x][y] = 'M'; // Miss
System.out.println(player + " misses at (" + x + ", " + y + ").");
} else {
System.out.println(player + " fires at (" + x + ", " + y + ") but it's already hit/missed.");
}
// Send the fire PDU to reflect the shot
disChannel.sendSinglePdu(simulationTimeSeconds, firePdu);
}
/**
* Checks the win condition by verifying if all ships on the grid have been hit.
* @param grid the grid to check.
* @return true if all ships are hit; false otherwise.
*/
private boolean checkWinCondition(char[][] grid) {
// Check if all ships have been hit
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (grid[i][j] == 'P') {
return false; // There are still ships left
}
}
}
return true; // All ships have been hit
}
/**
* Main method is first executed when a program instance is loaded.
* @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
*/
public static void main(String[] args) {
ExampleSimulationProgramBattleShip game = new ExampleSimulationProgramBattleShip();
game.runSimulationLoops();
System.out.println("Game Over");
}
}
...@@ -27,13 +27,13 @@ public class UnicastUdpSender ...@@ -27,13 +27,13 @@ public class UnicastUdpSender
private static final String MY_NAME = System.getProperty("user.name"); // guru incantation 8) private static final String MY_NAME = System.getProperty("user.name"); // guru incantation 8)
// public static final int SENDING_PORT = 1414; // not needed, can let system choose an open local port // public static final int SENDING_PORT = 1414; // not needed, can let system choose an open local port
/** socket value of shared interest */ /** socket value of shared interest */
public static final int UDP_PORT = UnicastUdpReceiver.UDP_PORT; // 1415; ensure consistent public static final int UDP_PORT = 1415;// ensure consistent
private static final int TOTAL_PACKETS_TO_SEND = 100; private static final int TOTAL_PACKETS_TO_SEND = 100;
/** socket value of shared interest */ /** socket value of shared interest */
public static final String DESTINATION_HOST = "localhost"; //public static final String DESTINATION_HOST = "localhost";
// here is what we need for lab comms // here is what we need for lab comms
// public static final String DESTINATION_HOST = "10.1.105.16"; // localhost 127.0.0.1 or argon 10.1.105.1 or 10.1.105.1 or whatever public static final String DESTINATION_HOST = "127.0.0.1"; // localhost 127.0.0.1 or argon 10.1.105.1 or 10.1.105.1 or whatever
/** /**
* Program invocation, execution starts here * Program invocation, execution starts here
...@@ -46,7 +46,7 @@ public class UnicastUdpSender ...@@ -46,7 +46,7 @@ public class UnicastUdpSender
DataOutputStream dos = null; DataOutputStream dos = null;
int packetID = 0; // counter variable to send in packet int packetID = 0; // counter variable to send in packet
float countdown = -1.0f; // unreachable value is good sentinel to ensure expected changes occur float countdown = -1.0f; // unreachable value is good sentinel to ensure expected changes occur
String message = MY_NAME + " says Hello MV3500"; // no really String message = MY_NAME + " says Hello Professor!"; // no really
String padding = new String(); String padding = new String();
try try
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment