Files
2026-05-07 03:23:56 +00:00

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;
}
}
}
}