static (int, int) SimulateWithAdjecency(Matrix2D <char> matrix, Func <int, int, Matrix2D <char>, int[]> adjacencyFunc = null, int crowdedThreshold = 4, bool output = false) { if (adjacencyFunc == null) { adjacencyFunc = FindImmediateNeighbours; } int[] indices = new int[128 * 128]; //max 128*128 int[][] adjacencyLists = new int[128 * 128][]; //max 128*128 for (int y = 0; y < matrix.Height; y++) { for (int x = 0; x < matrix.Width; x++) { int index = (y << 7) + x; var ptr = matrix.GetIndex(x, y); indices[index] = ptr; adjacencyLists[index] = adjacencyFunc(x, y, matrix); } } var current = matrix; var next = matrix.Clone(); int numFlipped = 1; int iterations = 0; while (numFlipped > 0) { numFlipped = 0; for (int y = 0; y < matrix.Height; y++) { for (int x = 0; x < matrix.Width; x++) { int index = (y << 7) + x; var adjacency = adjacencyLists[index]; if (adjacency == null) { continue; //null or floor } var ptr = indices[index]; var c = current.Array[ptr]; if (c == 'L' && IsClear(adjacency, current)) { next.Array[ptr] = '#'; numFlipped++; } else if (c == '#' && IsCrowded(adjacency, current, crowdedThreshold)) { next.Array[ptr] = 'L'; numFlipped++; } else { next.Array[ptr] = current.Array[ptr]; } } } if (output) { Console.CursorLeft = 0; Console.CursorTop = 0; next.Dump(); Thread.Sleep(50); } //bufferswap var tmp = current; current = next; next = tmp; iterations++; } return(current.Array.Count(c => c == '#'), iterations); }