Skip to content

Instantly share code, notes, and snippets.

@margusmartsepp
Created March 4, 2016 11:59
Show Gist options
  • Save margusmartsepp/3cb220557822f6ed2a01 to your computer and use it in GitHub Desktop.
Save margusmartsepp/3cb220557822f6ed2a01 to your computer and use it in GitHub Desktop.
Conway's Game of Life
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
namespace ConwaysGameOfLife
{
class Program
{
public class GameOfLifeConsoleUi
{
private readonly GameOfLife _life;
public GameOfLifeConsoleUi(GameOfLife life)
{
_life = life;
Console.BackgroundColor = ConsoleColor.Gray;
Console.Clear();
Console.CursorVisible = false;
var width = Math.Max(life.Dimensions.Width, 8) * 2 + 1;
var height = Math.Max(life.Dimensions.Height, 8) + 1;
Console.SetWindowSize(width, height);
Console.SetBufferSize(width, height);
const ConsoleColor deadColor = ConsoleColor.White;
const ConsoleColor liveColor = ConsoleColor.Black;
Console.BackgroundColor = deadColor;
Console.ForegroundColor = liveColor;
}
public void DrawBoard()
{
Console.SetCursorPosition(0, 0);
Console.Write(_life);
}
}
public class GameOfLife
{
private bool[,] Board { get; set; }
public bool LoopEdges { get; set; }
public int Generation { get; private set; }
public readonly Size Dimensions;
public DateTime ZeroGenerationDateTime { get; }
public GameOfLife(Size dimensions, bool loop)
{
ZeroGenerationDateTime = DateTime.Now;
Generation = 0;
Dimensions = dimensions;
Board = new bool[dimensions.Width, dimensions.Height];
LoopEdges = loop;
}
public override string ToString()
{
var builder = new StringBuilder();
for (var y = 0; y < Board.GetLength(0); y++)
{
for (var x = 0; x < Board.GetLength(1); x++)
{
var c = Board[x, y] ? '\u2588' : ' ';
builder.Append(c).Append(c);
}
builder.Append('\n');
}
return builder.ToString();
}
public void Randomize()
{
var random = new Random();
for (var y = 0; y < Board.GetLength(0); y++)
for (var x = 0; x < Board.GetLength(1); x++)
Board[x, y] = random.NextDouble() >= 0.5;
}
public void Update()
{
Board = GetNextGeneration(Board, LoopEdges);
Generation++;
}
public static bool[,] GetNextGeneration(bool[,] current, bool loopEdges)
{
var newBoard = new bool[current.GetLength(0), current.GetLength(1)];
for (var y = 0; y < current.GetLength(0); y++)
{
for (var x = 0; x < current.GetLength(1); x++)
{
var liveNeighbors = CountLiveNeighbors(current, x, y, loopEdges);
var currentState = current[x, y];
newBoard[x, y] = WillCellBeAlive(currentState, liveNeighbors);
}
}
return newBoard;
}
private static int CountLiveNeighbors(bool[,] current, int x, int y, bool loopEdges)
{
var liveNeighborsCount = 0;
const int relativeFrom = -1;
const int relativeTo = 1;
for (var j = relativeFrom; j <= relativeTo; j++)
{
if (IsOffBoard(y, loopEdges, j, current.GetLength(1)))
continue;
for (var i = relativeFrom; i <= relativeTo; i++)
{
if (IsOffBoard(x, loopEdges, i, current.GetLength(0)))
continue;
var relativeConjugationY = (y + j + current.GetLength(1)) % current.GetLength(1);
var relativeConjugationX = (x + i + current.GetLength(0)) % current.GetLength(0);
liveNeighborsCount += current[relativeConjugationX, relativeConjugationY] ? 1 : 0;
}
}
return current[x, y] ? liveNeighborsCount - 1: liveNeighborsCount;
}
private static bool IsOffBoard(int currentPosition, bool loopEdges, int relativePosition, int upperBound, int lowerBound = 0)
{
return !loopEdges
&& currentPosition + relativePosition < lowerBound
|| currentPosition + relativePosition >= upperBound;
}
private static bool WillCellBeAlive(bool currentState, int liveNeighbors)
{
return currentState
&& (liveNeighbors == 2 || liveNeighbors == 3)
|| !currentState && liveNeighbors == 3;
}
public void StoreGenerationImage()
{
var image = GetGenerationImage();
var filename = $"GoL_{ZeroGenerationDateTime:HH_mm_ss_fff}_{Generation}.png";
image.Save(filename, ImageFormat.Png);
}
private Bitmap GetGenerationImage()
{
var generationBitmap = new Bitmap(Dimensions.Width, Dimensions.Height);
using (var generationGraphics = Graphics.FromImage(generationBitmap))
{
var aBrush = Brushes.Black;
var bBrush = Brushes.Yellow;
for (var y = 0; y < Board.GetLength(0); y++)
for (var x = 0; x < Board.GetLength(1); x++)
generationGraphics.FillRectangle(Board[x, y] ? aBrush : bBrush, x, y, 1, 1);
}
return generationBitmap;
}
}
static void Main(string[] args)
{
var life = new GameOfLife(new Size(1024, 1024), loop: true);
life.Randomize();
//var ui = new GameOfLifeConsoleUi(life);
//var delay = 50;
// Run the game until the Escape key is pressed.
while (!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.Escape)
{
//ui.DrawBoard();
life.Update();
life.StoreGenerationImage();
Console.WriteLine(life.Generation);
// Wait for a bit between updates.
//Thread.Sleep(delay);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment