Skip to content
Snippets Groups Projects
Commit f12cd243 authored by owner's avatar owner
Browse files

Merge origin/master

parents a782f82b 446b91a2
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.enumerations.VariableRecordType;
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;
/** The purpose of this inheritable class is to provide an easily modifiable /**
* example simulation program that includes DIS-capable entities performing * The purpose of this inheritable class is to provide an easily modifiable
* tasks of interest, and then reporting activity via PDUs to the network. * example simulation program that includes DIS-capable entities performing
* Default program initialization includes PDU recording turned on by default. * tasks of interest, and then reporting activity via PDUs to the network.
* @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleSimulationProgramLog.txt" target="_blank">ExampleSimulationProgramLog.txt</a> * Default program initialization includes PDU recording turned on by default.
* @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 CommentPdu gridStatusPdu;
/** seconds per loop for real-time or simulation execution */ protected FirePdu firePduPlayer1;
private double simulationTimeStepDuration = 1.0; // seconds TODO encapsulate protected FirePdu firePduPlayer2;
/** initial simulation time in seconds */ protected MunitionDescriptor munitionDescriptor1 = new MunitionDescriptor();
double simulationTimeInitial = 0.0;
/** current simulation time in seconds */ // Simulation time settings
double simulationTimeSeconds = simulationTimeInitial; private double simulationTimeStepDuration = 1.0; // seconds
/** Maximum number of simulation loops */ private double simulationTimeSeconds = 0.0;
int MAX_LOOP_COUNT = 4;
// Tracking indices for Player 1's systematic search
String narrativeMessage1 = new String(); private int player1SearchRow = 0;
String narrativeMessage2 = new String(); private int player1SearchCol = 0;
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
* Design goal: additional built-in initialization conveniences can go here * built-in initialization conveniences can go here to keep your efforts
* to keep your efforts focused on the runSimulation() method. * 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. * Initialize the simulation program, setting up the DIS channel, PDUs, and
* @param newDescriptor describes this program, useful for logging and debugging * 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 * Initialize the DIS channel for communication, setting verbose output for
* @param address network address to use * debugging and creating the PduFactory.
* @param port corresponding network port to use
*/ */
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? /**
* Initialize simulation entities by creating PDUs for firing events.
*/ */
public void initializeSimulationEntities() private void initializeSimulationEntities() {
{ firePduPlayer1 = pduFactory.makeFirePdu();
if (pduFactory == null) firePduPlayer2 = pduFactory.makeFirePdu();
pduFactory = disChannel.getPduFactory(); gridStatusPdu = pduFactory.makeCommentPdu();
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);
entityStatePdu_1.setEntityType(new _001Poseidon()); // note import statement above
// entityStatePdu_1.setMarking("Entity #1");
entityStatePdu_1.setEntityType(new edu.nps.moves.dis7.entities.usa.platform.air.MV22B()); // note import statement at top
entityStatePdu_1.setMarking("Entity #53");
entityStatePdu_1.getMarkingString(); // use Netbeans Debug breakpoint here to check left justified...
entityStatePdu_2.setEntityID(entityID_2);
entityStatePdu_2.setForceId(ForceID.OPPOSING);
entityStatePdu_2.setEntityType(new _002Triton()); // note import statement above
entityStatePdu_2.setMarking("Entity #2");
// 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);
} }
/** /**
* This runSimulationLoops() method is for you, a customizable programmer-modifiable * Set up the game grids for each player, marking empty water and ship
* code block for defining and running a new simulation of interest. * positions.
*
* 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 private void setupGrids() {
public void runSimulationLoops () // Initialize grids with empty water '~'
{ for (int i = 0; i < GRID_SIZE; i++) {
try for (int j = 0; j < GRID_SIZE; j++) {
{ player1Grid[i][j] = '~';
final int SIMULATION_MAX_LOOP_COUNT = 10; // be deliberate out there! also avoid infinite loops. player2Grid[i][j] = '~';
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
{
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 // Place ships on the grids ('P' denotes a ship)
// ===================================================================================================// ===================================================================================================// ===================================================================================================// =================================================================================================== for (int[] ship : player1Ships) {
player1Grid[ship[0]][ship[1]] = 'P';
narrativeMessage2 = "runSimulation() completed successfully"; // all done, so tell everyone else on the channel }
// TODO better javadoc needs to be autogenerated for VariableRecordType enumerations for (int[] ship : player2Ships) {
disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); player2Grid[ship[0]][ship[1]] = 'P';
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(ExampleSimulationProgram.class.getSimpleName()).log(Level.SEVERE, null, iex);
}
} }
/** /**
* Send EntityState, Fire, Comment PDUs that got updated for this loop, reflecting state of current simulation timestep. * This runSimulationLoops() method is for you, a customizable
* @param simTimeSeconds simulation time in second, applied to PDU as timestamp * programmer-modifiable code block for defining and running a new
* @param entityStatePdu the ESPDU to send, if any * simulation of interest.
* @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, public void runSimulationLoops() {
EntityStatePdu entityStatePdu, int turnCount = 0;
FirePdu firePdu, while (turnCount < MAX_TURNS) {
VariableRecordType commentType, if (isPlayer1Turn) {
// vararg... variable-length set of String comments can optionally follow // Player 1 systematically searches Player 2's grid
String... comments) int[] target = selectNextTargetForPlayer1();
{ handleFire(firePduPlayer1, player2Grid, target, "Player 1");
if (entityStatePdu != null) } else {
disChannel.sendSinglePdu(simTimeSeconds, entityStatePdu); // Player 2 fires at Player 1 randomly
int[] target = selectRandomTarget();
if (firePdu != null) handleFire(firePduPlayer2, player1Grid, target, "Player 2");
disChannel.sendSinglePdu(simTimeSeconds, firePdu); // bang }
disChannel.sendCommentPdu(simTimeSeconds, commentType, comments); // empty comments are filtered // 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;
}
} }
/** /**
* 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
* @param args command-line parameters: network address and port * manner.
*
* @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 * Randomly select a target on the grid for Player 2's turn.
* @return simple descriptor name *
* @return the coordinates of the randomly selected target cell.
*/ */
public String getDescriptor() { private int[] selectRandomTarget() {
return descriptor; int x = (int) (Math.random() * GRID_SIZE);
int y = (int) (Math.random() * GRID_SIZE);
return new int[]{x, y};
} }
/** /**
* Set new simple descriptor (such as parent class name) for this network interface, used in trace statements * Handles the firing action, setting relevant data in the FirePdu, checking
* @param newDescriptor simple descriptor name for this interface * 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.
*/ */
public void setDescriptor(String newDescriptor) { private void handleFire(FirePdu firePdu, char[][] grid, int[] target, String player) {
if (newDescriptor == null) int x = target[0];
newDescriptor = ""; int y = target[1];
this.descriptor = newDescriptor;
// Set relevant details in the FirePdu
firePdu.setFiringEntityID(new EntityID().setEntityID(player.equals("Player 1") ? 1 : 2));
firePdu.setTargetEntityID(new EntityID().setEntityID(player.equals("Player 1") ? 1 : 2));
Vector3Double fireLoc = new Vector3Double(); //annoying that there isn't a Vector3Double(x, y, z) constructor...
fireLoc.setX(x);
fireLoc.setY(y);
fireLoc.setZ(0.0);
firePdu.setLocationInWorldCoordinates(fireLoc);
firePdu.setDescriptor(munitionDescriptor1); // Not needed I guess
firePdu.setRange(100.0f);// Not needed I gueess
// Print the firing action
System.out.println(player + " fires at (" + x + ", " + y + ").");
// Determine hit or miss and update the game grid
if (grid[x][y] == 'P') {
grid[x][y] = 'H'; // Mark as Hit
firePdu.setFireMissionIndex(1); // Indicate that this was a successful hit with an index of 1
System.out.println(player + " hits a ship at (" + x + ", " + y + ")!");
} else if (grid[x][y] == '~') {
grid[x][y] = 'M'; // Mark as Miss
firePdu.setFireMissionIndex(0); // Indicate that this was a miss with an index of 0
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 FirePdu to represent the shot
disChannel.sendSinglePdu(simulationTimeSeconds, firePdu);
// Send the updated grid status of both players
sendGridStatus();
}
/**
* 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
} }
/** /**
* parameter accessor method * Sends the current grid status of both players as a CommentPdu.
* @return the simulationTimeStepDuration in seconds
*/ */
public double getSimulationTimeStepDuration() { private void sendGridStatus() {
return simulationTimeStepDuration; // Construct a string representation of both grids
StringBuilder gridStatus = new StringBuilder();
gridStatus.append("Player 1 Grid:\n");
appendGridToString(gridStatus, player1Grid);
gridStatus.append("Player 2 Grid:\n");
appendGridToString(gridStatus, player2Grid);
// Set the grid status in the CommentPdu
gridStatusPdu.getVariableDatums().clear(); // Clear previous comments
gridStatusPdu.getVariableDatums().add(new VariableDatum()
.setVariableDatumID(VariableRecordType.OTHER)
.setVariableDatumValue(gridStatus.toString().getBytes())
.setVariableDatumLengthInBytes(gridStatus.toString().getBytes().length));
// Send the CommentPdu containing the grid status
disChannel.sendSinglePdu(simulationTimeSeconds, gridStatusPdu);
} }
/** /**
* parameter accessor method * Appends the current grid status to a StringBuilder.
* @param timeStepDurationSeconds the simulationTimeStepDuration in seconds to set *
* @param sb the StringBuilder to append to.
* @param grid the grid to represent.
*/ */
public void setSimulationTimeStepDuration(double timeStepDurationSeconds) { private void appendGridToString(StringBuilder sb, char[][] grid) {
this.simulationTimeStepDuration = timeStepDurationSeconds; for (char[] row : grid) {
for (char cell : row) {
sb.append(cell).append(' ');
}
sb.append('\n');
}
} }
/** 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
} }
} }
...@@ -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