Advertisement
Guest User

Untitled

a guest
Oct 25th, 2016
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.32 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace kiswa.Games.Life.DataLayer
  7. {
  8.     /// <summary>
  9.     /// Game of Life simulator.
  10.     /// </summary>
  11.     /// <remarks>
  12.     /// This is a Cellular Automaton simulator which defaults to the rules
  13.     /// for Conway's Game of Life.
  14.     /// The universe is represented by an array of boolean values representing
  15.     /// cell states (true or false for 'alive' or 'dead').
  16.     /// When providing rules, use the format 'survival/birth' where Conway's
  17.     /// rules would be "23/3".  This means a living cell with 2 or 3 neighbors
  18.     /// will 'survive' and a dead cell with 3 neighbors will be 'born'.
  19.     /// </remarks>
  20.     public sealed class LifeGame
  21.     {
  22.         #region Properties
  23.         /// <summary>
  24.         /// Gets the number of columns in the grid.
  25.         /// </summary>
  26.         public int Columns { get { return _cols; } }
  27.         /// <summary>
  28.         /// Gets the number of rows in the grid.
  29.         /// </summary>
  30.         public int Rows { get { return _rows; } }
  31.         /// <summary>
  32.         /// Gets the number of cells in the grid.
  33.         /// </summary>
  34.         public int Cells { get { return _cells; } }
  35.         /// <summary>
  36.         /// Gets the number of 'alive' cells.
  37.         /// </summary>
  38.         public int LiveCellCount { get { return _liveCells; } }
  39.         /// <summary>
  40.         /// Gets the string representation of the current rules.
  41.         /// </summary>
  42.         public string Rules { get { return _unparsedRules; } }
  43.         /// <summary>
  44.         /// Gets the bool array current state of the simulation.
  45.         /// </summary>
  46.         public bool[] GameGrid { get { return _currentStates; } }
  47.         #endregion
  48.  
  49.         #region Fields
  50.         private bool[] _currentStates;
  51.         private bool[] _newStates;
  52.         private bool[] _startStates;
  53.         private int _rows;
  54.         private int _cols;
  55.         private int _cells;
  56.         private int _liveCells;
  57.         private List<int> _surviveRules;
  58.         private List<int> _birthRules;
  59.         private string _unparsedRules;
  60.         #endregion
  61.  
  62.         #region Public Constructors
  63.         /// <summary>
  64.         /// Constructor for a Game of Life Simulator.
  65.         /// </summary>
  66.         /// <param name="gridSize">Size of one side of the grid -
  67.         /// used for both to create a square grid.</param>
  68.         public LifeGame(int gridSize)
  69.             : this(gridSize, gridSize, "23/3")
  70.         {
  71.             // Called ctor with default rules
  72.         }
  73.  
  74.         /// <summary>
  75.         /// Constructor for a Game of Life Simulator.
  76.         /// </summary>
  77.         /// <param name="columns">Number of columns in the grid.</param>
  78.         /// <param name="rows">Number of rows in the grid.</param>
  79.         public LifeGame(int columns, int rows)
  80.             : this(columns, rows, "23/3")
  81.         {
  82.             // Called ctor with default rules
  83.         }
  84.  
  85.         /// <summary>
  86.         /// Constructor for a Game of Life Simulator.
  87.         /// </summary>
  88.         /// <param name="columns">Number of columns in the grid.</param>
  89.         /// <param name="rows">Number of rows in the grid.</param>
  90.         /// <param name="rules">String representing the GoL ruleset to use
  91.         /// (e.g. "23/3" for Conway's Life).</param>
  92.         public LifeGame(int columns, int rows, string rules)
  93.         {
  94.             _cols = columns;
  95.             _rows = rows;
  96.             _cells = columns * rows;
  97.  
  98.             ClearGrid();
  99.             _startStates = new bool[_cells];
  100.             ChangeRules(rules);
  101.         }
  102.         #endregion
  103.  
  104.         #region Public Methods
  105.         /// <summary>
  106.         /// Allows changing of ruleset.
  107.         /// </summary>
  108.         /// <param name="rules">String representing the ruleset to use.</param>
  109.         /// <remarks>When invalid rules are input, rules default to 23/3.</remarks>
  110.         public void ChangeRules(string rules)
  111.         {
  112.             if (!rules.All("012345678/".Contains)) {
  113.                 rules = "23/3";
  114.             }
  115.  
  116.             _unparsedRules = rules;
  117.             var survive = rules.Split('/')[0];
  118.             var birth = rules.Split('/')[1];
  119.             _surviveRules = new List<int>();
  120.             _birthRules = new List<int>();
  121.             for (var i = 0; i < survive.Length; i++) {
  122.                 _surviveRules.Add(int.Parse(survive.Substring(i,1)));
  123.             }
  124.             for (var i = 0; i < birth.Length; i++) {
  125.                 _birthRules.Add(int.Parse(survive.Substring(i,1)));
  126.             }
  127.         }
  128.  
  129.         /// <summary>
  130.         /// Clears the grid.
  131.         /// </summary>
  132.         public void ClearGrid()
  133.         {
  134.             _liveCells = 0;
  135.             _currentStates = new bool[_cells];
  136.             _newStates = new bool[_cells];
  137.         }
  138.  
  139.         /// <summary>
  140.         /// Randomly creates live cells in the grid.
  141.         /// </summary>
  142.         /// <param name="probability">Probability of cell creation (0.0=all dead, 1.0=all alive).</param>
  143.         public void Randomize(double probability)
  144.         {
  145.             Random rand = new Random();
  146.             _liveCells = 0;
  147.             for (int i = 0; i < _cells; i++)
  148.             {
  149.                 _currentStates[i] = rand.NextDouble() <= probability;
  150.                 if (_currentStates[i])
  151.                 { _liveCells += 1; }
  152.             }
  153.         }
  154.  
  155.         /// <summary>
  156.         /// Resets the grid to the saved starting state.
  157.         /// </summary>
  158.         public void ResetGrid()
  159.         {
  160.             _startStates.CopyTo(_currentStates, 0);
  161.         }
  162.  
  163.         /// <summary>
  164.         /// Saves the grid state for reset.
  165.         /// </summary>
  166.         public void SetStart()
  167.         {
  168.             _currentStates.CopyTo(_startStates, 0);
  169.         }
  170.  
  171.         /// <summary>
  172.         /// Steps through one generation of the grid.
  173.         /// </summary>
  174.         public void Step()
  175.         {
  176.             advancePopulation();
  177.             _newStates.CopyTo(_currentStates, 0);
  178.         }
  179.  
  180.         /// <summary>
  181.         /// Gets the state of the specified cell.
  182.         /// </summary>
  183.         /// <param name="x">Column location of the cell to test.</param>
  184.         /// <param name="y">Row location of the cell to test.</param>
  185.         /// <returns>True or false for cell 'alive' or 'dead'.</returns>
  186.         public bool GetCellState(int x, int y)
  187.         {
  188.             if (y < 0 || y >= _rows || x < 0 || x >= _cols)
  189.             { return false; }
  190.            
  191.             return _currentStates[x + y * _cols];
  192.         }
  193.  
  194.         /// <summary>
  195.         /// Swaps the state of the specified cell.
  196.         /// </summary>
  197.         /// <param name="x">Column location of the cell to alter.</param>
  198.         /// <param name="y">Row location of the cell to alter.</param>
  199.         public void ToggleCellState(int x, int y)
  200.         {
  201.             if (y < 0 || y >= _rows || x < 0 || x >= _cols)
  202.             { return; }
  203.  
  204.             int index = x + y * _cols;
  205.             _currentStates[index] = !(_currentStates[index]);
  206.            
  207.             if (_currentStates[index])
  208.             { _liveCells += 1; }
  209.             else
  210.             { _liveCells -= 1; }
  211.         }
  212.  
  213.         /// <summary>
  214.         /// Converts the grid to a string representation.
  215.         /// For 'dead' cells uses ".", for 'alive' cells uses "*".
  216.         /// </summary>
  217.         /// <returns>String representation of the grid.</returns>
  218.         public override string ToString()
  219.         {
  220.             StringBuilder sb = new StringBuilder();
  221.  
  222.             for (int y = 0; y < _rows; y++)
  223.             {
  224.                 for (int x = 0; x < _cols; x++)
  225.                 {
  226.                     sb.Append(_currentStates[x + y * _cols] ? '*' : '.');
  227.                 }
  228.                 sb.AppendLine();
  229.             }
  230.  
  231.             return sb.ToString();
  232.         }
  233.         #endregion
  234.  
  235.         #region Private Methods
  236.         /// <summary>
  237.         /// Advances the entire population by one generation.
  238.         /// </summary>
  239.         private void advancePopulation()
  240.         {
  241.             if (_liveCells == 0) return;
  242.             _liveCells = 0;
  243.             int neighbors;
  244.             int index;
  245.             bool alive;
  246.  
  247.             for (var y = 0; y < _rows; y++) {
  248.                 for (var x = 0; x < _cols; x++) {
  249.                     neighbors = getNeighbors(x, y);
  250.                     index = x + y*_cols;
  251.                     alive = _currentStates[index];
  252.                     // If cell is alive and survives, or dead is born.
  253.                     if ((alive && _surviveRules.Contains(neighbors))|| !alive && _birthRules.Contains(neighbors)) {
  254.                         _newStates[index] = true;
  255.                         _liveCells++;
  256.                     }
  257.                     //The cell neither survives nor is born
  258.                     else {
  259.                         _newStates[index] = false;
  260.                     }
  261.                 }
  262.             }
  263.         }
  264.  
  265.         /// <summary>
  266.         /// Gets the count of live neighbors for a specified cell.
  267.         /// </summary>
  268.         /// <param name="x">Column location of the cell to test.</param>
  269.         /// <param name="y">Row location of the cell to test.</param>
  270.         /// <returns>Integer value of live neighbors.</returns>
  271.         private int getNeighbors(int x, int y)
  272.         {
  273.             int neighborCount = 0;
  274.            
  275. /* NW */    if ((x > 0 && y > 0) && _currentStates[x - 1 + (y - 1) * _cols])
  276.             { neighborCount += 1; }
  277. /* N  */    if ((y > 0) && _currentStates[x + (y - 1) * _cols])
  278.             { neighborCount += 1; }
  279. /* NE */    if ((x + 1 < _cols && y > 0) && _currentStates[x + 1 + (y - 1) * _cols])
  280.             { neighborCount += 1; }
  281. /* W  */    if ((x + 1 < _cols) && _currentStates[x + 1 + y * _cols])
  282.             { neighborCount += 1; }
  283. /* SW */    if ((x + 1 < _cols && y + 1 < _rows) && _currentStates[x + 1 + (y + 1) * _cols])
  284.             { neighborCount += 1; }
  285. /* S  */    if ((y + 1 < _rows) && _currentStates[x + (y + 1) * _cols])
  286.             { neighborCount += 1; }
  287. /* SE */    if ((x > 0 && y + 1 < _rows) && _currentStates[x - 1 + (y + 1) * _cols])
  288.             { neighborCount += 1; }
  289. /* E  */    if ((x > 0) && _currentStates[x - 1 + y * _cols])
  290.             { neighborCount += 1; }
  291.  
  292.             return neighborCount;
  293.         }
  294.         #endregion
  295.     }
  296. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement