96 lines
3.0 KiB
C#
96 lines
3.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using GameOfLife.Entities;
|
|
|
|
namespace GameOfLife
|
|
{
|
|
public abstract class LifeBase : ILife
|
|
{
|
|
public int Generation { get; protected set; }
|
|
public int Population { get; protected set; }
|
|
public abstract bool IsCellAlive(Cell cell);
|
|
public virtual bool IsCellAlive(short x, short y) => IsCellAlive(new Cell(x,y));
|
|
public bool AllAlive(IEnumerable<Cell> cells) => cells.All(IsCellAlive);
|
|
public bool AllDead(IEnumerable<Cell> cells) => cells.All(c => !IsCellAlive(c));
|
|
|
|
private IReadOnlyList<Tuple<Cell, short>> _neighborhoodField;
|
|
|
|
public IReadOnlyList<Tuple<Cell, short>> NeighborhoodField =>
|
|
// cache values this expensive operation
|
|
_neighborhoodField ?? (_neighborhoodField = Neighborhood.GetNeighborField(LivingCells).ToList());
|
|
|
|
private Pattern _livingCellPattern;
|
|
|
|
public Pattern LivingCellPattern =>
|
|
_livingCellPattern ?? (_livingCellPattern = LivingCells.ToPattern());
|
|
|
|
public bool ToggleCell(Cell cell)
|
|
{
|
|
var alive = ToggleCell_Internal(cell);
|
|
Population += alive ? 1 : -1;
|
|
return alive;
|
|
}
|
|
|
|
protected abstract bool ToggleCell_Internal(Cell cell);
|
|
|
|
public void IncrementGeneration()
|
|
{
|
|
_neighborhoodField = null;
|
|
_livingCellPattern = null;
|
|
Population = IncrementGeneration_Internal();
|
|
Generation++;
|
|
}
|
|
|
|
protected abstract int IncrementGeneration_Internal();
|
|
|
|
public abstract IEnumerable<Cell> LivingCells { get; }
|
|
|
|
public static readonly short[,] NeighborOffsets =
|
|
{
|
|
{ -1, -1 }, { -1, 0 }, { -1, 1 },
|
|
{ 0, -1 }, { 0, 1 },
|
|
{ 1, -1 }, { 1, 0 }, { 1, 1 },
|
|
};
|
|
|
|
public byte GetNeighborCount(short x, short y)
|
|
{
|
|
byte numberOfNeighbors = 0;
|
|
|
|
for (var i = 0; i < 8; i++)
|
|
{
|
|
numberOfNeighbors +=
|
|
IsCellAlive((short)(x + NeighborOffsets[i,0]), (short)(y + NeighborOffsets[i,1]))
|
|
? (byte)1
|
|
: (byte)0;
|
|
}
|
|
|
|
return numberOfNeighbors;
|
|
}
|
|
|
|
protected bool ShouldLive(short x, short y)
|
|
{
|
|
var numberOfNeighbors = GetNeighborCount(x, y);
|
|
|
|
var isAlive = IsCellAlive(x, y);
|
|
|
|
return LifeRule(isAlive, numberOfNeighbors);
|
|
}
|
|
|
|
protected bool LifeRule(bool isAlive, int neighborCount)
|
|
{
|
|
switch (isAlive)
|
|
{
|
|
case false
|
|
when neighborCount == 3:
|
|
case true
|
|
when neighborCount == 2
|
|
|| neighborCount == 3:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
} |