/// <summary> /// Cycles through the game starting at generation 0 up to the number of generations set in the Settings /// </summary> public void CycleThroughGame() { SetInitialState(); grid.InitializeWindow(); Stopwatch watch = new Stopwatch(); for (int i = 0; i <= settings.Generations; i++) { grid.SetFootnote($"Generation: {i}"); // Only need to create a new generation from i = 1 onwards if (i != 0) { statusArray = CreateNextGeneration(); } UpdateCellStatus(); int matchIndex = CompareToMemory(); // Only need to compare to memory from i = 1 onwards if (i != 0) { if (matchIndex != -1) { periodicity = i - generationInMemory[matchIndex]; steadyState = true; // Break out of loop to end game break; } } AddToMemory(statusArray, i); grid.Render(); watch.Restart(); // User cycles through 1 generation at a time by pressing space if step mode enabled if (settings.StepMode) { CheckForSpace(writeMsg: false); } // Otherwise game cycles through at the update rate specified in Settings else { while (watch.ElapsedMilliseconds < ((1 / settings.UpdateRate) * 1000)) { ; } } } // Write final array to file if valid output file path specified if (settings.OutputFile != null) { WriteToFile(); } }
/// <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); }
static void Main(string[] args) { Options options = ArgumentProcessor.Process(args); int[,] universe = InitializeUniverse(options); Grid grid = new Grid(options.Rows, options.Columns); var universeList = new List <int[, ]>(); bool isSteadyState = false; bool successfullyWroteToFile = false; Logging.Message("Press spacebar to begin the game..."); WaitSpacebar(); grid.InitializeWindow(); Stopwatch stopwatch = new Stopwatch(); int iteration = 0; while (iteration <= options.Generations) { stopwatch.Restart(); if (iteration != 0) { universe = EvolveUniverse(universe, options.Periodic, options.NeighbourOrder, options.NeighbourhoodType, options.CentreCount, options.BirthRate, options.SurvivalRate); } if (universeList.Count == options.GenerationalMemory) //Remove the first item in the list if the list capacity is reached (Capacity is the generationalMemory) { universeList.RemoveAt(0); } UpdateGrid(grid, universe); grid.SetFootnote($"Generation: {iteration++}"); grid.Render(); isSteadyState = CheckSteadyState(universeList, options, universe); //Check if the current universe have reached a steady state if (isSteadyState) { break; //If a steady state is found then stop the next generation from happening } universeList.Add(universe); if (options.StepMode) { WaitSpacebar(); } else { while (stopwatch.ElapsedMilliseconds < 1000 / options.UpdateRate) { ; } } } grid.IsComplete = true; grid.Render(); if (!string.IsNullOrEmpty(options.OutputFile)) { using StreamWriter writer = new StreamWriter(options.OutputFile); writer.WriteLine("#version=2.0"); OutputToFile(options, universeList, writer); writer.Close(); successfullyWroteToFile = true; } WaitSpacebar(); grid.RevertWindow(); if (isSteadyState && options.IsAllDead == false) { Logging.Message($"Steady-state detected... periodicity = {iteration - 1}"); } if (isSteadyState && options.IsAllDead == true) { Logging.Message($"Steady-state detected... periodicity = N/A"); } if (successfullyWroteToFile) { Logging.Success($": Final generation written to file: {options.OutputFile}"); } Logging.Message("Press spacebar to exit program..."); WaitSpacebar(); }
/// <summary > /// Starts the simulation by running the main loop of the program /// This method calls other methods to collect the information required to use the Display API. /// </ summary > /// <param name =" grid " > Used to display the Cell matrix in the console </ param > public int start(Grid grid) { Stopwatch watch = new Stopwatch(); //initialise time CellState[,] state = new CellState[getRows, getColumns]; //set state for each cell CellState[] ghostState = { CellState.Dark, CellState.Medium, CellState.Light }; //ghost states for (int g = 0; g <= getGenerations; g++) //loop per generation { watch.Restart(); for (int r = 0; r < getRows; r++) // For each of the cells... { for (int c = 0; c < getColumns; c++) { state[r, c] = CellState.Blank; //clear cell state int ghosts = (previousGenerations.Count > 2) ? 2 : previousGenerations.Count - 1; //ghost count ghosts = (ghostMode) ? ghosts : -1; //turn on : off ghost mode for (int gh = ghosts; gh >= 0; gh--) { state[r, c] = (previousGenerations[gh][r, c] == alive) ? ghostState[gh] : state[r, c]; //set ghosts } state[r, c] = (cells[r, c] == alive) ? CellState.Full : state[r, c]; //get new generation states grid.UpdateCell(r, c, state[r, c]); // Update grid } } while (watch.ElapsedMilliseconds < (1 / getMaxUpdate * 1000)) { ; //Timer } grid.SetFootnote("Generation: " + g); //prints current generation grid.Render(); // Render updates to the console window... period = steadyState(cells); //get period if (period > -1) //steady state? End game if true { if (getOutputPath != String.Empty) { outputSeed(cells); //output seed } return(period); } cells = this.mutation(cells); //MUTATION, following the Conways game of life... if (stepMode) { space(); //Step Mode } } if (getOutputPath != String.Empty) { outputSeed(cells); //output seed } return(period); }
/// <summary> /// Main Function which contains all code that wasn't put into methods /// </summary> /// <param name="args"></param> static void Main(string[] args) { // Declaring the variables int Rows = 16; // Default: 16. Change as required for testing. int Columns = 16; // Default: 16. Change as required for testing. bool PeriodicBehaviour = false; // Default: false. Change as required for testing double RandFactor = 0.5; // Default: 0.5. Change as required for testing string InputFile = ""; // Default: NO input. Change as required for testing int Generations = 50; // Default: 50. Change as required fo testing double MaxUpdateRate = 5; // Default: 5. Change as required for testing bool StepMode = false; // Default: NOT step mode. Change as required for testing bool CheckAllConditions = true; //Checking all the parameters //To count the number of generations int GenCount = 0; Stopwatch watch = new Stopwatch(); // Checking the user input for (int count = 0; count < args.Length; count++) { //Checking the dimensions of the game CheckDimensions(ref args, ref count, ref Rows, ref Columns, ref CheckAllConditions); //Checking if the game will have periodic behaviour CheckPeriodic(ref args, ref count, ref PeriodicBehaviour); //Checking Random factor CheckRandomFactor(ref args, ref count, ref RandFactor, ref CheckAllConditions); //Checking the input file CheckSeedfile(ref args, ref count, ref InputFile, ref CheckAllConditions); //Checking the generations GenerationMethod(ref args, ref count, ref Generations, ref CheckAllConditions); //Checking the max update rate MaxUpdaterate(ref args, ref count, ref MaxUpdateRate, ref CheckAllConditions); //Checking step mode StepModeMethod(ref args, ref count, ref StepMode); } //Game array which stores the cell coordinates int[,] GameArray = new int[Rows, Columns]; //Temporary Array to store the neighbours int[,] TempArray = new int[Rows, Columns]; // Construct grid... Grid grid = new Grid(Rows, Columns); //Checking randomness RandomnessMethod(ref InputFile, ref Columns, ref Rows, ref GameArray, ref RandFactor); //Displaying user uput DispUserInput(ref CheckAllConditions, ref InputFile, ref Generations, ref MaxUpdateRate, ref PeriodicBehaviour, ref Rows, ref Columns, ref StepMode, ref RandFactor); // Wait for user to press a key... Console.WriteLine("Press any key to start..."); Console.ReadKey(); // Game // 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("Life " + GenCount); // Declaring variable to see if neighbouring cells are active for next generation int ThreeCount = 0; // For each of the cells... for (int i = 0; i < GameArray.GetLength(0); i++) { for (int j = 0; j < GameArray.GetLength(1); j++) { if (GameArray[i, j] == 1) { // Update grid with a new cell... grid.UpdateCell(i, j, CellState.Full); } else { grid.UpdateCell(i, j, CellState.Blank); } } } // Timer for Life game watch.Restart(); while (watch.ElapsedMilliseconds < (1000 / MaxUpdateRate)) { ; } grid.Render(); //Increasing the generations while (Generations >= GenCount) { //Checking the neighbours of the cells ActualGame(ref Rows, ref Columns, ref GameArray, ref ThreeCount, ref PeriodicBehaviour, ref TempArray); //Step function holding answer till space is pressed if (StepMode == true) { while (Console.ReadKey().Key != ConsoleKey.Spacebar) { ; } } grid.SetFootnote("Life " + GenCount); // For each of the cells... for (int i = 0; i < GameArray.GetLength(0); i++) { for (int j = 0; j < GameArray.GetLength(1); j++) { if (TempArray[i, j] == 1) { // Update grid with a new cell... grid.UpdateCell(i, j, CellState.Full); GameArray[i, j] = TempArray[i, j]; } else { grid.UpdateCell(i, j, CellState.Blank); GameArray[i, j] = 0; } TempArray[i, j] = 0; } } // Timer for Life Game watch.Restart(); while (watch.ElapsedMilliseconds < (1000 / MaxUpdateRate)) { ; } // Render updates to the console window... grid.Render(); GenCount++; } // Set complete marker as true grid.IsComplete = true; grid.Render(); Console.ReadKey(); grid.RevertWindow(); }