public static void CheckSurvivalAndBirthValues(CLA currentValues) { double numNeighbours = 0; bool throwError = false; try { if (currentValues.Neighbourhood == "Moore") { // Calculate number of neighbours based on the order int order = currentValues.NeighbourhoodSize + 1; numNeighbours = Math.Pow(2 * order - 1, 2); // Reduce number of neighbours by 1 if the centre cell of a neighbourhood isn't being checked if (!currentValues.CentreCheck) { numNeighbours--; } // Check all survival values and make sure that none of them are above the number of possible // neighbours - if the is a value exceeding the number, reset the survival values to default. for (int i = 0; i < currentValues.SurvivalList.Length; i++) { if (currentValues.SurvivalList[i] != "" && Convert.ToDouble(currentValues.SurvivalList[i]) > numNeighbours) { string[] values = { "2", "3" }; currentValues.SurvivalList = values; currentValues.Survival = "2...3"; throwError = true; break; } } // Check all birth values and make sure that none of them are above the number of possible // neighbours - if the is a value exceeding the number, reset the birth values to default. for (int i = 0; i < currentValues.BirthList.Length; i++) { if (currentValues.BirthList[i] != "" && Convert.ToDouble(currentValues.BirthList[i]) > numNeighbours) { string[] values = { "3" }; currentValues.BirthList = values; currentValues.Birth = "3"; throwError = true; break; } } } else if (currentValues.Neighbourhood == "Von Neumann") { // Calculate number of neighbours based on the order int order = currentValues.NeighbourhoodSize; numNeighbours = Math.Pow(order, 2) + Math.Pow(order + 1, 2); // Reduce number of neighbours by 1 if the centre cell of a neighbourhood isn't being checked if (!currentValues.CentreCheck) { numNeighbours--; } // Check all survival values and make sure that none of them are above the number of possible // neighbours - if the is a value exceeding the number, reset the survival values to default. for (int i = 0; i < currentValues.SurvivalList.Length; i++) { if (currentValues.SurvivalList[i] != "" && Convert.ToDouble(currentValues.SurvivalList[i]) > numNeighbours) { string[] values = { "2", "3" }; currentValues.SurvivalList = values; currentValues.Survival = "2...3"; throwError = true; break; } } // Check all birth values and make sure that none of them are above the number of possible // neighbours - if the is a value exceeding the number, reset the birth values to default. for (int i = 0; i < currentValues.BirthList.Length; i++) { if (currentValues.BirthList[i] != "" && Convert.ToDouble(currentValues.BirthList[i]) > numNeighbours) { string[] values = { "3" }; currentValues.BirthList = values; currentValues.Birth = "3"; throwError = true; break; } } } if (throwError) { throw new SurvivalOrBirthOutsideNumberOfNeighboursException(); } } catch (SurvivalOrBirthOutsideNumberOfNeighboursException) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"[ERROR] One or more Survival or Birth values exceeds the " + $"number of neighbours ({numNeighbours})."); Console.WriteLine("[ERROR] Resetting the exceeding value holder (either Survival or Birth or both) " + "to their default values."); Console.ForegroundColor = ConsoleColor.White; return; } return; }
/// <summary> /// Helper method to print the command in a readable format /// </summary> /// <returns> /// return string formatted command /// </returns> public override string ToString() { return("ApduCommand CLA=" + CLA.ToString("X2") + ",INS=" + INS.ToString("X2") + ",P1=" + P1.ToString("X2") + ",P2=" + P2.ToString("X2") + ((CommandData != null && CommandData.Length > 0) ? (",Data=" + BitConverter.ToString(CommandData).Replace("-", "")) : "")); }
/// <summary> /// Main method, which runs the entire program and calls external methods found above and below Main. /// </summary> /// <author>Zac Wolter</author> /// <date>September 2020</date> static void Main(string[] args) { int periodicity = 0; // Check for command line arguments... Console.WriteLine("Interpreting command line arguments..."); if (args.Length == 0) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("[SUCCESS] No command line arguments found."); Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("The program will use the following default settings."); //Call the WriteValues method with no parameters, hence printing default set values WriteFinalValues(); } // If command line arguments exist, perform the for loop to check each value else if (args.Length > 0) { for (int i = 0; i < args.Length; i++) { // Check if the current value contains the dimensions flag if (args[i].Contains("--dimensions")) { DimensionArgCheck(args); } // Check if the current value contains the survival flag else if (args[i].Contains("--survival")) { SurvivalArgCheck(args); } // Check if the current value contains the survival flag else if (args[i].Contains("--birth")) { BirthArgCheck(args); } //Check for periodic behaviour boolean else if (args[i].Contains("--periodic")) { PerioidicArgCheck(); } //Check for Random Factor double else if (args[i].Contains("--random")) { RandomArgCheck(args, i); } // Check for seed argument else if (args[i].Contains("--seed")) { SeedFileCheck(args, i); } // Check for generations argument else if (args[i].Contains("--generations")) { GenerationArgCheck(args, i); } // Check for maximum update rate else if (args[i].Contains("--max-update")) { MaxUpdateArgCheck(args, i); } // Check for step mode value else if (args[i].Contains("--step")) { StepArgCheck(); } // Check for neighbourhood value else if (args[i].Contains("--neighbour")) { NeighourhoodCheck(args, i, currentValues.Rows, currentValues.Columns); } // Check for memory value else if (args[i].Contains("--memory")) { MemoryArgCheck(args, i); } // Check for ghost mode value else if (args[i].Contains("--ghost")) { GhostArgCheck(); } // Check for output file value else if (args[i].Contains("--output")) { OutputFileCheck(args, i); } } // Check that the given survival and birth values supplied by the user are less than or equal to the number // of neighbourhing cells depending on the neighbourhood type CheckSurvivalAndBirthValues(currentValues); // Check that the given neighbourhood order supplied by the user is less than or equal to half the shortest // grid dimension NeighbourhoodOrderCheck(currentValues.NeighbourhoodSize, currentValues.Rows, currentValues.Columns); WriteFinalValues(); } CLA paramValues = storedValues(); // Wait until the user presses the spacebar before beginning the simulation Console.WriteLine("Press Spacebar to begin."); WaitForSpacebarPress(); int[,,] currentCells = new int[currentValues.Rows, currentValues.Columns, currentValues.Memory]; int[,,] newCells = new int[currentValues.Rows, currentValues.Columns, 1]; // HOW THE NEW 3D ARRAY WILL WORK: // EACH CELL: { x, y, z} // Where: // x = x coordinate // y = y coordinate // z = generation // Seed file initialisation or random seed generation if (currentValues.InputFile == "N/A") { currentCells = GenerateRandomGrid(currentValues.Probability, currentCells, currentValues.Rows, currentValues.Columns); } else { currentCells = CheckAndInitialiseInputFile(currentValues.InputFilePath, currentCells, currentValues.Rows, currentValues.Columns); } // Construct grid... Grid grid = new Grid(currentValues.Rows, currentValues.Columns); // Initialize the grid window (this will resize the window and buffer) grid.InitializeWindow(); // Set the footnote (appears in the bottom left of the screen). grid.SetFootnote($"Generation: 0"); Stopwatch watch = new Stopwatch(); // Initialise cells InitialiseFirstGen(grid, currentCells); // Render updates to the console window... grid.Render(); // Integer to keep track of the number of iterations int iterations = Convert.ToInt32(currentValues.Generations); int passes = 0; // Calculate speed of simulation (applies only if step mode is off) int updateTime = 1000 / Convert.ToInt32(currentValues.MaxRefreshRate); // Run the simulation while (passes < iterations) { watch.Restart(); grid.SetFootnote($"Generation: {passes}"); grid.Render(); passes++; // Check all x layers for any similarities against all other layers periodicity = steadyStateCheck(currentCells); if (periodicity != -1) { steadyStateCompletion(grid, periodicity, currentCells); break; } // Method that checks every cell in the grid for alive neighbours, decides if each cell is alive or // dead in the next generation, and updates the display based on if ghost mode is activated or not SimulateNextGen(currentValues.GhostMode, currentCells, grid, newCells); // Generates a new array of cells with the previous layers moved forward 1 layer // First layer [0] is empty currentCells = RotateMemory(currentCells, newCells); // Check if step mode is enabled, if so, wait for key press if (currentValues.StepMode == true) { while (Console.ReadKey(true).Key != ConsoleKey.Spacebar) { ; } } else { // Update timer if required... while (watch.ElapsedMilliseconds < updateTime) { ; } } } grid.SetFootnote("Press Space to Exit"); // Set complete marker as true grid.IsComplete = true; // Render updates to the console window (grid should now display COMPLETE)... grid.Render(); // Wait for user to press a key... while (true) { var keyPress = Console.ReadKey(true); if (keyPress.Key == ConsoleKey.Spacebar) { break; } } // Revert grid window size and buffer to normal grid.RevertWindow(); // Tell user that no steady-state was detected (this code will only execute if the number of generations // is reached before a steady-state occurs) Console.WriteLine("Steady-state not detected..."); if (currentValues.OutputFile != "N/A") { GenerateOutputFile(currentValues.OutputFile, currentValues.Rows, currentValues.Columns, currentCells); } Console.WriteLine("Press spacebar to close program..."); // Wait for user to press spacebar... while (true) { var keyPress = Console.ReadKey(true); if (keyPress.Key == ConsoleKey.Spacebar) { break; } } // Close the program here Environment.Exit(0); }