• 细胞自动机


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

    每个细胞有两种状态 - 存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。(如图,黑色为存活,白色为死亡)
    当前细胞为存活状态时,当周围低于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的十字,每次死循环之后按空格暂停,在中间继续画十字,可以得到非常有趣的图案。尽管尝试吧。。

  • 相关阅读:
    函数对象
    函数的基本使用
    文件处理
    字符编码
    基本数据类型及内置方法二
    流程控制(if while for)
    Django中ajax的基本用法
    CBV之Django中View类部分源码分析
    前端基础之BOM和DOM
    css基础
  • 原文地址:https://www.cnblogs.com/jwk000/p/7496908.html
Copyright © 2020-2023  润新知