using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace LifeSimulation.Extensions
{
static class ProcessLifeModelExtension
{
private enum CellOutcome
{
Dies,
Spawns,
NoChange
}
#region Extension methods
public static void Process(this LifeModelBase model, World World)
{
List<Point> dieList = new List<Point>();
List<Point> spawnList = new List<Point>();
for (int i = 0; i < World.Space.GetLength(0); i++)
{
for (int j = 0; j < World.Space.GetLength(1); j++)
{
switch (model.GetCellOutcome(World, i, j))
{
case CellOutcome.Dies:
dieList.Add(new Point(i, j));
break;
case CellOutcome.Spawns:
spawnList.Add(new Point(i, j));
break;
}
}
}
//Die
foreach (Point point in dieList)
World.Space[point.X, point.Y] = 0;
//Spawn
foreach (Point point in spawnList)
World.Space[point.X, point.Y] = model.MaximumAge;
//Age
for (int i = 0; i < World.Space.GetLength(0); i++)
for (int j = 0; j < World.Space.GetLength(1); j++)
if (World.Space[i, j] > 0)
World.Space[i, j]--;
}
public static int GetMaximumNeighbours(this LifeModelBase model)
{
return GetMaximumNeighbours(model.NeighbourDistance);
}
#endregion
#region Public methods
/// <summary>
/// Gets max number of neighbours according to distance indicator as follows...
///
/// Distance = 1
/// 00000
/// 00100
/// 01X10
/// 00100
/// 00000
/// Distance = 2
/// 00000
/// 01110
/// 01X10
/// 01110
/// 00000
/// Distance = 3
/// 00100
/// 01110
/// 11X11
/// 01110
/// 00100
/// Distance = 4
/// 01110
/// 11111
/// 11X11
/// 11111
/// 01110
/// Distance = 5 or more
/// 11111
/// 11111
/// 11X11
/// 11111
/// 11111
/// </summary>
/// <param name="neighbourhoodDistance"></param>
public static int GetMaximumNeighbours(int neighbourhoodDistance)
{
switch (neighbourhoodDistance)
{
case 1: return 4;
case 2: return 8;
case 3: return 12;
case 4: return 20;
default: return 24;
}
}
#endregion
#region Private methods
private static CellOutcome GetCellOutcome(this LifeModelBase model, World World, int i, int j)
{
World.Neighbours[i, j] = World.CountNeighbours(i, j, model.NeighbourDistance);
if (World.Space[i, j] > 0)
{
if (model.CellDeathIndicators.Contains(World.Neighbours[i, j]))
return CellOutcome.Dies;
}
else
{
if (model.CellSpawnIndicators.Contains(World.Neighbours[i, j]))
return CellOutcome.Spawns;
}
return CellOutcome.NoChange;
}
private static int CountNeighbours(this World World, int i, int j, int distance)
{
int c = 0;
int mi = World.Space.GetLength(0) - 1;
int mj = World.Space.GetLength(1) - 1;
int mi2 = mi - 1;
int mj2 = mj - 1;
if (distance >= 1)
{
if (i > 0 && World.Space[i - 1, j] > 0) c++;
if (i < mi && World.Space[i + 1, j] > 0) c++;
if (j > 0 && World.Space[i, j - 1] > 0) c++;
if (j < mj && World.Space[i, j + 1] > 0) c++;
}
if (distance >= 2)
{
if (i > 0 && j > 0 && World.Space[i - 1, j - 1] > 0) c++;
if (i > 0 && j < mj && World.Space[i - 1, j + 1] > 0) c++;
if (i < mi && j > 0 && World.Space[i + 1, j - 1] > 0) c++;
if (i < mi && j < mj && World.Space[i + 1, j + 1] > 0) c++;
}
if (distance >= 3)
{
if (i > 1 && World.Space[i - 2, j] > 0) c++;
if (i < mi2 && World.Space[i + 2, j] > 0) c++;
if (j > 1 && World.Space[i, j - 2] > 0) c++;
if (j < mj2 && World.Space[i, j + 2] > 0) c++;
}
if (distance >= 4)
{
//Left top
if (i > 1 && j > 0 && World.Space[i - 2, j - 1] > 0) c++;
if (i > 0 && j > 1 && World.Space[i - 1, j - 2] > 0) c++;
//Left bottom
if (i > 1 && j < mj && World.Space[i - 2, j + 1] > 0) c++;
if (i > 0 && j < mj2 && World.Space[i - 1, j + 2] > 0) c++;
//Right top
if (i < mi2 && j > 0 && World.Space[i + 2, j - 1] > 0) c++;
if (i < mi && j > 1 && World.Space[i + 1, j - 2] > 0) c++;
//Right bottom
if (i < mi2 && j < mj && World.Space[i + 2, j + 1] > 0) c++;
if (i < mi && j < mj2 && World.Space[i + 1, j + 2] > 0) c++;
}
if (distance >= 5)
{
//Left top
if (i > 1 && j > 1 && World.Space[i - 2, j - 2] > 0) c++;
//Left bottom
if (i > 1 && j < mj2 && World.Space[i - 2, j + 2] > 0) c++;
//Right top
if (i < mi2 && j > 1 && World.Space[i + 2, j - 2] > 0) c++;
//Right bottom
if (i < mi2 && j < mj2 && World.Space[i + 2, j + 2] > 0) c++;
}
return c;
}
#endregion
}
}