patterncsharpModerate
'Game of Life' in C#
Viewed 0 times
lifegamestackoverflow
Problem
Unrelated to code:
I have only been programming for three weeks, and this is my first project.
About the code:
-
Uses a preset grid.
-
It was all done on a single page. This, I realise, was a mistake, and I have fixed that since.
-
I used an int array for the grid. I did first think maybe a Boolean array would be better, but for my skill level int was easier. I do plan to try a bool array as soon as this int version is completed.
-
I tried to find another way to implement the logic for the game using a
-
I understand my variable naming is poor and could be greatly improved. I do plan to make changes to them in the near future.
-
I know use of the endgame variable is unnecessary, but I kept it for use in enhancements I plan to make to the project.
What I would like from this:
-
A pointer on how to improve the change from one grid to another, i.e. to improve the flow of the game.
-
Thoughts on how to improve the logic of my grid, by avoiding overuse of conditional statements.
-
General feedback to code both structurally and aesthetically, so I know what to improve in future projects.
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace grid
{
class Program
{
static void Main(string[] args)
{
bool endgame = false;
int[,] grid = new int[,]
{
{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,},
{ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,},
{ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,},
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,},
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,},
{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,},
{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,},
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,},
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,}
};
gridconstructor game
I have only been programming for three weeks, and this is my first project.
About the code:
-
Uses a preset grid.
-
It was all done on a single page. This, I realise, was a mistake, and I have fixed that since.
-
I used an int array for the grid. I did first think maybe a Boolean array would be better, but for my skill level int was easier. I do plan to try a bool array as soon as this int version is completed.
-
I tried to find another way to implement the logic for the game using a
for a,b loop instead of a lot of if statements, but I was unsuccessful. Is it possible to do it this way? -
I understand my variable naming is poor and could be greatly improved. I do plan to make changes to them in the near future.
-
I know use of the endgame variable is unnecessary, but I kept it for use in enhancements I plan to make to the project.
What I would like from this:
-
A pointer on how to improve the change from one grid to another, i.e. to improve the flow of the game.
-
Thoughts on how to improve the logic of my grid, by avoiding overuse of conditional statements.
-
General feedback to code both structurally and aesthetically, so I know what to improve in future projects.
```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace grid
{
class Program
{
static void Main(string[] args)
{
bool endgame = false;
int[,] grid = new int[,]
{
{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 1,},
{ 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,},
{ 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,},
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,},
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,},
{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,},
{ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,},
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,},
{ 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,},
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,}
};
gridconstructor game
Solution
Cell
The first thing I would do is actually not switch to a bool grid but actually make a class that represents a single cell. I'm going to call it
The cell would handle the old and new flags to start with but it would also let you easily add logic for age (some GOL implementations color the cells based on their age).
This will let you encapsulate the logic of the Cell in a single place.
Grid
Next, I would have a class that handles just the grid (look up Single Responsibility Principle for more reasons why). At the base level, it can easily take just a width and height variable and creates an array (of your choice) of
You could have
Since
GridUpdater
If I was writing it, I would have a separate class for updating the state. You could do this within
Breaking apart the
With GOL, you basically have two sweeps. One is to calculate the new values. The second is to move the new value into the current one.
The reason I suggested the logic for cell is because the
You don't need much more than this. Your
Formatting
Typically C# uses PascalCase for all method and property names.
Comprehension wise, it is great if your method names used a verb in the name. So, instead of
EDIT:
The first thing I would do is actually not switch to a bool grid but actually make a class that represents a single cell. I'm going to call it
Cell because I'm not that creative.The cell would handle the old and new flags to start with but it would also let you easily add logic for age (some GOL implementations color the cells based on their age).
Cell would not be aware of anything else.This will let you encapsulate the logic of the Cell in a single place.
Grid
Next, I would have a class that handles just the grid (look up Single Responsibility Principle for more reasons why). At the base level, it can easily take just a width and height variable and creates an array (of your choice) of
Cell objects.You could have
Cell GetCell(x, y) that retrieves a cell at a given location. I'd also write a function List GetAdjacentCells(x, y) to retrieve the list of cells next to the given coordinates. For GOL, that's all you really need.Since
Grid know its height and width, you don't have to get the GetLength() unless you want to.GridUpdater
If I was writing it, I would have a separate class for updating the state. You could do this within
Grid itself, but it would easier to maintain and test if you did it separately (again, see SRP).Breaking apart the
Console stuff out of there also keeps your code relatively clean (and SRP).With GOL, you basically have two sweeps. One is to calculate the new values. The second is to move the new value into the current one.
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
var cell = grid.GetCell(x, y);
var adjacent = grid.GetAdjacentCells(x, y);
cell.Calculate(adjacent);
}
}
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
var cell = grid.GetCell(x, y);
cell.Update(); // Should be a function for encapsulation.
}
}The reason I suggested the logic for cell is because the
Calculate function there is pretty simple.public void Calculate(List adjacent)
{
// All the rules are based on the number of adjacent cells.
var count = adjacent.Count;
// Less than two or greater than three is always dead.
if (count 3) {
NewState = false;
} else {
// For live (OldState = true) cells, they are alive. For dead ones,
// they live only if there is exactly three. This uses the OR logic to
// to combine the two statements together.
NewState = OldState || count == 3;
}
}You don't need much more than this. Your
Console stuff should be in a fourth class because it has nothing to do with the state of a cell, the size of the grid, or how the grid is updated.Formatting
Typically C# uses PascalCase for all method and property names.
while (endgame == false) is while (!endgame).Comprehension wise, it is great if your method names used a verb in the name. So, instead of
activecell, you use CalculateNewState or Update. That way, someone new can understand what that function is supposed to do. "Active" is really just an adjective on "Cell" which is a noun.EDIT:
NewState = false; to say dead.Code Snippets
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
var cell = grid.GetCell(x, y);
var adjacent = grid.GetAdjacentCells(x, y);
cell.Calculate(adjacent);
}
}
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
var cell = grid.GetCell(x, y);
cell.Update(); // Should be a function for encapsulation.
}
}public void Calculate(List<Cell> adjacent)
{
// All the rules are based on the number of adjacent cells.
var count = adjacent.Count;
// Less than two or greater than three is always dead.
if (count < 2 || count > 3) {
NewState = false;
} else {
// For live (OldState = true) cells, they are alive. For dead ones,
// they live only if there is exactly three. This uses the OR logic to
// to combine the two statements together.
NewState = OldState || count == 3;
}
}Context
StackExchange Code Review Q#140772, answer score: 12
Revisions (0)
No revisions yet.