康威生命遊戲(細胞自動機)C# 控制檯

效果

規則(來自百度百科,康威生命遊戲詞條)

遊戲開始時,每一個細胞隨機地設定爲「生」或「死」之一的某個狀態。而後,根據某種規則,計算出下一代每一個細胞的狀態,畫出下一代細胞的生死分佈圖。
應該規定什麼樣的迭代規則呢?須要一個簡單的,但又反映生命之間既協同又競爭的生存定律。爲簡單起見,最基本的考慮是假設每個細胞都遵循徹底同樣的生存定律;再進一步,把細胞之間的相互影響只限制在最靠近該細胞的8個鄰居中。
也就是說,每一個細胞迭代後的狀態由該細胞及周圍8個細胞狀態所決定。做了這些限制後,仍然還有不少方法來規定「生存定律」的具體細節。例如,在康威的生命遊戲中,規定了以下生存定律。
(1)當前細胞爲死亡狀態時,當週圍有3個存活細胞時,則迭代後該細胞變成存活狀態(模擬繁殖);若原先爲生,則保持不變。
(2)當前細胞爲存活狀態時,當週圍的鄰居細胞低於兩個(不包含兩個)存活時,該細胞變成死亡狀態(模擬生命數量稀少)。
(3)當前細胞爲存活狀態時,當週圍有兩個或3個存活細胞時,該細胞保持原樣。
(4)當前細胞爲存活狀態時,當週圍有3個以上的存活細胞時,該細胞變成死亡狀態(模擬生命數量過多)。

控制檯實現的關鍵接口

設置控制檯遊標的函數:public static void SetCursorPosition (int left, int top); 其中left參數是列,top參數是行。數組

設置控制檯背景色的屬性:public static ConsoleColor BackgroundColor { get; set; } 黑色用來表示生存的細胞,白色用來表示死亡的細胞。dom

代碼實現

using System;
using System.Threading;

namespace CellularAutomata
{
    class Program
    {
        private static int gridRowCol = 32;
        private static Cell[,] grid = new Cell[gridRowCol, gridRowCol];
        private static int sleepMs = 33;
        private static int initAlivePossibility = 4; // 4 means 1/4

        static void Main(string[] args)
        {
            try
            {
                Init();
                // Main loop
                while (true)
                {
                    Update();
                    Thread.Sleep(sleepMs);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                Console.ReadKey();
            }
        }

        private static void Init()
        {
            // Set Console Size
            Console.BufferHeight = 256;
            Console.BufferWidth = 256;
            Console.WindowWidth = 256;
            Console.WindowHeight = 80;

            Random random = new Random();
            for (int i = 0; i < grid.GetLength(0); i++)
            {
                for (int j = 0; j < grid.GetLength(1); j++)
                {
                    grid[i, j] = new Cell();
                    int value = random.Next(0, initAlivePossibility);
                    if (value == 0)
                    {
                        grid[i, j].Value = true;
                    }
                    else
                    {
                        grid[i, j].Value = false;
                    }
                }
            }
        }

        private static void Update()
        {
            for (int i = 0; i < grid.GetLength(0); i++)
            {
                for (int j = 0; j < grid.GetLength(1); j++)
                {
                    int aliveCount = NeighborAliveCount(i, j);

                    if (grid[i, j].Value) // Alive
                    {
                        if (aliveCount < 2 || aliveCount > 3)
                        {
                            grid[i, j].Value = false;
                        }
                    }
                    else // Death
                    {
                        if (aliveCount == 3)
                        {
                            grid[i, j].Value = true;
                        }
                    }

                    if (grid[i, j].Value)
                    {
                        SetAlive(i, j);
                    }
                    else
                    {

                        SetDeath(i, j);
                    }
                }
            }
        }

        private static int NeighborAliveCount(int i, int j)
        {
            int count = 0;
            for (int m = i - 1; m <= i + 1; m++)
            {
                for (int n = j - 1; n <= j + 1; n++)
                {
                    if (m == i && n == j) continue;
                    if (m < 0 || m >= grid.GetLength(0)) continue;
                    if (n < 0 || n >= grid.GetLength(1)) continue;
                    if (grid[m, n].Value) count++;
                }
            }

            return count;
        }

        private static void SetAlive(int i, int j)
        {
            string aliveStr = "  ";
            Console.SetCursorPosition(j * aliveStr.Length, i);
            Console.BackgroundColor = ConsoleColor.Black;
            Console.Write(aliveStr);
        }

        private static void SetDeath(int i, int j)
        {
            string deathStr = "  ";
            Console.SetCursorPosition(j * deathStr.Length, i);
            Console.BackgroundColor = ConsoleColor.White;
            Console.Write(deathStr);
        }
    }

    public class Cell
    {
        public bool Value { get; set; }
    }
}

 

Cell類是細胞類,其中有一個bool屬性Value,true表示存活,false表示死亡。將細胞單獨寫成類而不是一個bool值是爲了後續可能的擴展。函數

grid變量是一個二維數組,表明格子,大小能夠經過gridRowCol設置,默認32,不宜太大。oop

sleepMs變量是循環之間的間隔時間,單位是毫秒,默認33ms.spa

initAlivePossibility變量決定格子中的細胞初始化時存活的機率,計算方式爲 1/initAlivePossibility,如initAlivePossibility=4,表示初始化時每一個細胞的存活機率是1/4.code

Main()函數中先初始化了格子中的細胞和控制檯大小。設置控制檯大小這一步可能會拋出越界異常,若是出現的話須要修改這個值。 接着是主循環,每次循環的間隔是sleepMs。blog

Update()就是實現規則的函數。接口

NeighborAliveCount()函數獲取指定細胞的相鄰細胞存活數。遊戲

SetAlive()函數和SetDeath()函數設置控制檯上的顯示。get

相關文章
相關標籤/搜索