细胞自动机

今天发奇想,想试试康威生命游戏。规则非常简单:

每个细胞有两种状态 - 存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。(如图,黑色为存活,白色为死亡)
当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)

用C#实现起来也是非常顺滑,只在那个嵌套for循环的地方为了避免O(n*8)复杂度过大做了一个catch处理。一个winform就可以了:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 
 11 namespace Cell
 12 {
 13     public partial class Form1 : Form
 14     {
 15         public Form1()
 16         {
 17             InitializeComponent();
 18             this.Width = m_kXCount * m_kGridSize + m_kGridSize;
 19             this.Height = m_kYCount * m_kGridSize + m_kGridSize;
 20             DoubleBuffered = true;
 21             StartPosition = FormStartPosition.CenterScreen;
 22             BackColor = Color.White;
 23             initGrids();
 24             initTimer();
 25         }
 26 
 27         //网格对象
 28         class Grid
 29         {
 30             public Rectangle rect;
 31             public bool alive;
 32             public bool next;
 33             public Point pos;//topleft
 34         }
 35 
 36         const int m_kGridSize = 20;
 37         const int m_kXCount = 100;
 38         const int m_kYCount = 60;
 39         const int m_kAntCount = 1;
 40 
 41         Grid[,] m_allGrids = new Grid[m_kXCount, m_kYCount];
 42         void initGrids()
 43         {
 44             for (int x = 0; x < m_kXCount; x++)
 45             {
 46                 for (int y = 0; y < m_kYCount; y++)
 47                 {
 48                     m_allGrids[x, y] = new Grid
 49                     {
 50                         alive = false,
 51                         pos = new Point(x, y),
 52                         rect = new Rectangle(x * m_kGridSize, y * m_kGridSize, m_kGridSize, m_kGridSize),
 53                     };
 54                 }
 55             }
 56         }
 57 
 58         //细胞
 59         List<Grid> m_allCells = new List<Grid>();
 60 
 61         //定时器
 62         Timer m_timer = new Timer();
 63         void initTimer()
 64         {
 65             m_timer.Interval = 100;//蚂蚁移动速度
 66             m_timer.Tick += onTimerTick;
 67             m_timer.Enabled = false;
 68         }
 69 
 70         Size[] m_8offset = new Size[8]
 71         {
 72             new Size(-1,-1),
 73             new Size(0,-1),
 74             new Size(1,-1),
 75             new Size(-1,0),
 76             new Size(1,0),
 77             new Size(-1,1),
 78             new Size(0,1),
 79             new Size(1,1)
 80         };
 81 
 82         private void onTimerTick(object sender, EventArgs e)
 83         {
 84             //每个细胞有两种状态 - 存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。(如图,黑色为存活,白色为死亡)
 85             //当前细胞为存活状态时,当周围低于2个(不包含2个)存活细胞时, 该细胞变成死亡状态。(模拟生命数量稀少)
 86             //当前细胞为存活状态时,当周围有2个或3个存活细胞时, 该细胞保持原样。
 87             //当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成死亡状态。(模拟生命数量过多)
 88             //当前细胞为死亡状态时,当周围有3个存活细胞时,该细胞变成存活状态。 (模拟繁殖)
 89 
 90             List<Grid> newCells = new List<Grid>();
 91             List<Grid> checkedCell = new List<Grid>();
 92             foreach(var cell in m_allCells)
 93             {
 94                 int cnt = 0;
 95                 foreach(var s in m_8offset)
 96                 {
 97                     var p = cell.pos + s;
 98                     if (p.X < 0) p.X = m_kXCount - 1;
 99                     if (p.Y < 0) p.Y = m_kYCount - 1;
100                     if (p.X == m_kXCount) p.X = 0;
101                     if (p.Y == m_kYCount) p.Y = 0;
102 
103                     var _cell = m_allGrids[p.X, p.Y];
104                     if (_cell.alive)
105                     {
106                         cnt++;
107                     }
108                     else
109                     {
110                         if (checkedCell.Contains(_cell))
111                             continue;
112 
113                         checkedCell.Add(_cell);
114 
115                         //死亡状态的细胞
116                         int _cnt = 0;
117                         foreach(var _s in m_8offset)
118                         {
119                             var _p = _cell.pos + _s;
120                             if (_p.X < 0) _p.X = m_kXCount - 1;
121                             if (_p.Y < 0) _p.Y = m_kYCount - 1;
122                             if (_p.X == m_kXCount) _p.X = 0;
123                             if (_p.Y == m_kYCount) _p.Y = 0;
124 
125                             var __cell = m_allGrids[_p.X, _p.Y];
126                             if (__cell.alive)
127                             {
128                                 _cnt++;
129                             }
130                         }
131                         if (_cnt == 3)
132                         {
133                             _cell.next = true;
134                             newCells.Add(_cell);
135                         }
136                     }
137                 }
138                 if (cnt < 2 || cnt > 3)
139                     cell.next = false;
140                 else
141                     cell.next = true;
142             }
143             foreach(var cell in m_allCells)
144             {
145                 cell.alive = cell.next;
146             }
147             foreach(var cell in newCells)
148             {
149                 cell.alive = cell.next;
150             }
151             m_allCells.RemoveAll(c => !c.alive);
152             m_allCells.AddRange(newCells);
153             Invalidate();
154         }
155 
156         //鼠标选择活细胞
157         protected override void OnMouseClick(MouseEventArgs e)
158         {
159             base.OnMouseClick(e);
160             if (m_isRunning) return;
161             //计算位置
162             int x = e.X / m_kGridSize;
163             int y = e.Y / m_kGridSize;
164             var grid = m_allGrids[x, y];
165             grid.alive = true;
166             m_allCells.Add(grid);
167 
168             Invalidate();
169         }
170 
171         bool m_isRunning = false;
172         //键盘控制启动暂停
173         protected override void OnKeyDown(KeyEventArgs e)
174         {
175             base.OnKeyDown(e);
176             if (e.KeyCode == Keys.Space)
177             {
178                 m_isRunning = !m_isRunning;
179                 m_timer.Enabled = !m_timer.Enabled;
180             }
181         }
182 
183         Pen m_gridPen = new Pen(Color.Black, 1);
184         protected override void OnPaint(PaintEventArgs e)
185         {
186             base.OnPaint(e);
187             var g = e.Graphics;
188 
189             //绘制网格
190             for (int x = 0; x < m_kXCount; x++)
191             {
192                 for (int y = 0; y < m_kYCount; y++)
193                 {
194                     var grid = m_allGrids[x, y];
195                     if (grid.alive)
196                     {
197                         g.FillRectangle(Brushes.Brown, grid.rect);
198                     }
199                     g.DrawRectangle(m_gridPen, grid.rect);
200                 }
201             }
202         }
203 
204     }
205 }

定时器默认是关闭的,用鼠标点选一个初始形状作为种子,按空格键开始/暂停。我尝试了一个3*3的十字,每次死循环之后按空格暂停,在中间继续画十字,可以得到非常有趣的图案。尽管尝试吧。。

 

posted @ 2017-09-09 00:08  mjwk  阅读(4410)  评论(0编辑  收藏  举报