patterncsharpMinor
Optimizing Conway's Game of Life code to run faster
Viewed 0 times
conwaycodefastergameoptimizingliferun
Problem
How could I take this code and optimize it so that I could possibly run Conway's Game of Life on a large grid at 15 frames per second?
```
public partial class MainWindow : Window
{
Cell[,] activeCells;
//List nextGenCells;
static Timer time;
bool onOff = true;
int columnNum = 10;
int rowNum = 10;
int codeColumn;
int codeRow;
public MainWindow()
{
InitializeComponent();
createGrid(10, 10);
}
public void createGrid(int width, int height)
{
if (cellPanel != null)
{
cellPanel.Children.Clear();
codeColumn = width;
codeRow = height;
cellPanel.Columns = width;
cellPanel.Rows = height;
activeCells = new Cell[width, height];
for (int i = 0; i nextGenCells;
nextGenCells = new List();
for (int i = 0; i 3)
{
nextGenCells.Add(c);
}
if (!c.IsAlive && neighbors == 3)
{
nextGenCells.Add(c);
}
}
}
foreach (Cell cell in nextGenCells)
{
cell.IsAlive = !cell.IsAlive;
}
}
private void oneGenerationButton_Click(object sender, RoutedEventArgs e)
{
updateCells();
}
private void CreateBoardButton(object sender, RoutedEventArgs e)
{
rowNum = (int) heightSlider.Value;
columnNum = (int)widthSlider.Value;
createGrid(rowNum, columnNum);
}
private void randomizeButton_Click(object sender, RoutedEventArgs e)
{
Random rand = new Random();
for (int i = 0; i < codeColumn; i++)
{
for (int j = 0; j < codeRow; j++)
{
if (rand.Next(0, 3) == 1)
{
activeCells[i, j].IsAlive = true;
}
else
{
activeCells[i, j].IsAlive = false;
}
}
}
}
private void playButton_Click(object sender, RoutedEventArgs e)
{
if(onOff)
{
onOff = !onOff;
time = new Timer(1000 / speedSlider.Value);
time.Elapsed += time_Elapsed;
```
public partial class MainWindow : Window
{
Cell[,] activeCells;
//List nextGenCells;
static Timer time;
bool onOff = true;
int columnNum = 10;
int rowNum = 10;
int codeColumn;
int codeRow;
public MainWindow()
{
InitializeComponent();
createGrid(10, 10);
}
public void createGrid(int width, int height)
{
if (cellPanel != null)
{
cellPanel.Children.Clear();
codeColumn = width;
codeRow = height;
cellPanel.Columns = width;
cellPanel.Rows = height;
activeCells = new Cell[width, height];
for (int i = 0; i nextGenCells;
nextGenCells = new List();
for (int i = 0; i 3)
{
nextGenCells.Add(c);
}
if (!c.IsAlive && neighbors == 3)
{
nextGenCells.Add(c);
}
}
}
foreach (Cell cell in nextGenCells)
{
cell.IsAlive = !cell.IsAlive;
}
}
private void oneGenerationButton_Click(object sender, RoutedEventArgs e)
{
updateCells();
}
private void CreateBoardButton(object sender, RoutedEventArgs e)
{
rowNum = (int) heightSlider.Value;
columnNum = (int)widthSlider.Value;
createGrid(rowNum, columnNum);
}
private void randomizeButton_Click(object sender, RoutedEventArgs e)
{
Random rand = new Random();
for (int i = 0; i < codeColumn; i++)
{
for (int j = 0; j < codeRow; j++)
{
if (rand.Next(0, 3) == 1)
{
activeCells[i, j].IsAlive = true;
}
else
{
activeCells[i, j].IsAlive = false;
}
}
}
}
private void playButton_Click(object sender, RoutedEventArgs e)
{
if(onOff)
{
onOff = !onOff;
time = new Timer(1000 / speedSlider.Value);
time.Elapsed += time_Elapsed;
Solution
if (rand.Next(0, 3) == 1)
{
activeCells[i, j].IsAlive = true;
}
else
{
activeCells[i, j].IsAlive = false;
}I'd assign the variable like
activeCells[i, j].IsAlive = (rand.Next(0, 3) == 1); instead. It simplifies the structure.if (c.IsAlive && neighbors 3)
{
nextGenCells.Add(c);
}
if (!c.IsAlive && neighbors == 3)
{
nextGenCells.Add(c);
}If you use
else if here, that should save you a couple cycles.List nextGenCells;
nextGenCells = new List();Declare this on one line, there's no reason for you to split it up like you do.
public int getLivingNeighbors(int x, int y)This function is filled with repeated if statements containing combinations of previously tested variables. Consider storing those in temporary variables instead and reusing them. That should improve readability.
Additionally, I can think of a couple things you could try to increase performance on an algorithmic level:
- Turn
Cells into a net of objects where each object has a reference to its neighbors. This allows you to perform a for-loop over each cell's neighbors, countingisAlive. Such a thing might simplify and speed up the algorithm. Do your own benchmarking to test this.
- Skip large sections of empty cells. This might be hard to implement in the array based implementation, but if you kept a list of live cells, you could opt to check only the live cells and their neighbors. You could even enable and disable this strategy as certain percentages of tiles are alive, or just check per 5x5 block if it contains live cells. Having some sort of class to track sections also allows you to keep some sort of
hasChangedflag, only including the section in calculations ifhasChangedis true.
- Surround your actual grid with dead cells that you never check. This saves all the if-statement complexity at the cost of some memory.
- Alter your algorithm to return early. You check for up to 8 living neighbors, but any neighbor count above 4 is irrelevant.
Code Snippets
if (rand.Next(0, 3) == 1)
{
activeCells[i, j].IsAlive = true;
}
else
{
activeCells[i, j].IsAlive = false;
}if (c.IsAlive && neighbors < 2)
{
nextGenCells.Add(c);
}
if (c.IsAlive && neighbors > 3)
{
nextGenCells.Add(c);
}
if (!c.IsAlive && neighbors == 3)
{
nextGenCells.Add(c);
}List<Cell> nextGenCells;
nextGenCells = new List<Cell>();public int getLivingNeighbors(int x, int y)Context
StackExchange Code Review Q#58982, answer score: 2
Revisions (0)
No revisions yet.