| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 7649 人关注过本帖
标题:生命游戏(Game of Life)
只看楼主 加入收藏
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4940
专家分:30047
注 册:2008-10-15
结帖率:100%
收藏
 问题点数:0 回复次数:22 
生命游戏(Game of Life)
想起以前看到这个生命游戏,这个题目本身是要求用C来的,现在考虑用VB写一下。我试了一下,认为这个题目适合新手,可以锻炼以下几个方面的内容:
1、数组,特别是二维数组
2、绘图
---------------------
题目的要求如下:
1.题目描述
生命游戏(GameofLife)是英国数学家约翰·何顿·康威在1970年发明的细胞自动机。在一个二维矩形世界中,每个方格居住着一个活着的或死了的细胞。一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。
规则1.如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变)。
规则2.如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
规则3.在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)

最早研究细胞自动机的科学家是冯·诺伊曼。后来人工生命之父克里斯·朗顿进一步发展了元胞自动机理论,由此认为生命诞生于“混沌的边缘”,从此开辟了“人工生命”这一新兴的交叉学科。
本题目要求你设计一个生命游戏,开始时设置好生命的初始状态(也可以随机设置),模拟其中生命随时间的变化过程。
2.设计提示
1)细胞的世界可以用二维数组表示,每个生命的状态只有两种,即生或死;
2)为便于在屏幕上打印,世界的大小不宜过大,可以取20行70列;
3)程序开始时,设置生命的初始状态,即哪些地方有活着的生命。然后根据上述规则计算出下一个时刻生命的状态,并打印出来;
-------------------
注1:这个题目实在是太古老了,所以最后的要求是打印,其实应该是显示
注2:规则已被精练化,很适合写代码。未精练的版本如下:
1.一個活的格子若只有一個或沒有鄰居,在下一秒將因寂寞而亡.
2.一個活的格子若有四個或四個以上的鄰居,在下一秒將因拥擠而亡.
3.一個活的格子若有二個或三個鄰居,在下一秒將継續活著.
4.一個死的格子若有三個鄰居,在下一秒將活過來.
搜索更多相关主题的帖子: color 游戏 
2016-02-15 15:05
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4940
专家分:30047
注 册:2008-10-15
收藏
得分:0 
我写的代码:
窗体上要放一个定时器控件。

程序代码:
Option Explicit
Private Const 横 = 78                       '横竖格子数
Private Const 竖 = 45
Private Const 灰 = 8421504                  '线框颜色
Private Const 死 = 16777215                 '死颜色
Private Const 生 = 65280                    '生颜色
Dim z(横 + 1, 竖 + 1) As Byte               '目标数组
Dim l(横 + 1, 竖 + 1) As Byte               '中间数组
Dim hd As Long                              '格子大小,横竖
Dim ld As Long
Dim js As Long                              '演变回合
Private Sub Form_Click()
Timer1.Enabled = Not Timer1.Enabled         '单击开始或暂停演变
End Sub
Private Sub Form_Load()
Randomize                                   '初始化随机数
Dim i As Long, j As Long
For i = 1 ToFor j = 1 ToIf Rnd() > 0.5 Then                 '随机情况
            z(i, j) = 1
        Else
            z(i, j) = 0
        End If
    Next j
Next i
Me.WindowState = 2                          '最大化窗口
DoEvents
End Sub
Public Sub view()
'显示每个格子
If hd < Screen.TwipsPerPixelX * 3 Or ld < Screen.TwipsPerPixelY * 3 Then Exit Sub
'如果不够绘图,则直接退出
Dim i As Long, j As Long
For i = 0 To 横 - 1
    For j = 0 To 竖 - 1
        If z(i + 1, j + 1) = 1 Then         '生,就用生画格
            Me.Line (i * hd + Screen.TwipsPerPixelX, j * ld + Screen.TwipsPerPixelY)-(i * hd + hd - Screen.TwipsPerPixelX, j * ld + ld - Screen.TwipsPerPixelY), 生, BF
        Else                                '死,就用死画格
            Me.Line (i * hd + Screen.TwipsPerPixelX, j * ld + Screen.TwipsPerPixelY)-(i * hd + hd - Screen.TwipsPerPixelX, j * ld + ld - Screen.TwipsPerPixelY), 死, BF
        End If
    Next j
Next i
End Sub
Private Sub Form_Paint()
'当窗口需要重绘时,绘制网络
Dim i As Long, j As Long
Me.Cls              '清屏
For i = 0 To 横 - 1
    For j = 0 To 竖 - 1
        Me.Line (i * hd, j * ld)-(i * hd + hd, j * ld + ld), 灰, B          '副格子线,按每个格子均画线,也可以按横和竖分别画线
    Next j
Next i
Call view           '重绘格子
End Sub
Private Sub Form_Resize()
'窗体大小改变时,计算格子大小
Dim i As Long
i = Me.ScaleWidth
hd = i \ 横
i = Me.ScaleHeight
ld = i \ 竖
Call Form_Paint         '缩小时,不会产生重绘事件,需要手动调用
 
End Sub
Public Sub r()              '运算函数
Dim i As Long, j As Long
Dim o As Long
For i = 1 ToFor j = 1 To 竖
        o = 0                       '统计8个格子,这里分了8行写,也可以使用一个二次循环来写,循环需要6行代码
        o = o + z(i - 1, j - 1)
        o = o + z(i, j - 1)
        o = o + z(i + 1, j - 1)
        o = o + z(i - 1, j)
        o = o + z(i + 1, j)
        o = o + z(i - 1, j + 1)
        o = o + z(i, j + 1)
        o = o + z(i + 1, j + 1)
        
        Select Case o
            Case 3
        '规则1:如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),
        '则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。
                l(i, j) = 1
            Case 2
        '规则2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
                l(i, j) = z(i, j)
            Case Else
        '规则3. 在其它情况下,该细胞为死(即该细胞若原先为生,则转为死,若原先为死,则保持不变)
                l(i, j) = 0
        End Select
    Next j
Next i
'把中间结果写入目标
For i = 1 ToFor j = 1 To 竖
        z(i, j) = l(i, j)
    Next j
Next i
Call view
End Sub
Private Sub Timer1_Timer()
'定时器调用演变
js = js + 1
Call r
Me.Caption = "生命游戏(Game of Life) -- " & js
End Sub

授人于鱼,不如授人于渔
早已停用QQ了
2016-02-15 15:20
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
风版主好雅兴!
关于找邻居的算法可以简单为一个小循环解决,和你2楼相关代码如下:
        o = 0                       '统计8个格子,这里分了8行写,也可以使用一个二次循环来写,循环需要6行代码
        For k = 0 To 8
          If k <> 4 Then o = o + z(i + Int(k / 3) - 1, j + k Mod 3 - 1)
        Next
        Select Case o
            Case 3
        '规则1:如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),
        '则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。

能编个毛线衣吗?
2016-02-15 19:00
yangfrancis
Rank: 16Rank: 16Rank: 16Rank: 16
等 级:贵宾
威 望:141
帖 子:1510
专家分:7661
注 册:2014-5-19
收藏
得分:0 
好家伙,有些眼花缭乱了。一时不大看得明白风版的用户操作区坐标是哪个范围。0 to 横+1,0 to 竖+1  还是  1 to 横,1 to 竖?望追加说明一下。判断下一代生死状态的时候为什么不需要专门判断边缘的细胞,全都视为8个邻居?
2016-02-15 22:31
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4940
专家分:30047
注 册:2008-10-15
收藏
得分:0 
数组范围为:  0-横+1 ,使用范围为 1-横,
也就是在 使用范围之外,恒定有一圈为0 的。所以不需要再判断边缘了。

授人于鱼,不如授人于渔
早已停用QQ了
2016-02-16 08:53
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4940
专家分:30047
注 册:2008-10-15
收藏
得分:0 
回复 3楼 wmf2014
双循环转单循环,我一直没去做过。怕麻烦,怕代码可读性不好。

自己写关玩的代码,主要就是怕以后再来看时看不懂。

我自己想到的双循环是:
for k1=-1 to 1
   for k2 = -1 to 1
      o=o+z(i+k1,j+k2)
   next k2
next k1
o= o - z( i,j)
这样的6行代码。

授人于鱼,不如授人于渔
早已停用QQ了
2016-02-16 08:56
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
根据我的理解,部分做简化,不需要定义为全程变量或常数的放进函数里定义,个人认为这样的代码可读性和可维护性强些:
程序代码:
Option Explicit
Private Const 横 = 78                       '横竖格子数
Private Const 竖 = 45
Dim z(横 + 1, 竖 + 1) As Byte               '目标数组
Dim js As Long

Private Sub Form_Click()
Timer1.Interval = Timer1.Interval Xor 200
End Sub
Private Sub Form_Load()
Randomize                                   '初始化随机数
Dim i As Long, j As Long
For i = 1 ToFor j = 1 To 竖
        z(i, j) = 0
        If Rnd() > 0.5 Then z(i, j) = 1                '随机情况
    Next j
Next i
Me.WindowState = 2                          '最大化窗口
Timer1.Interval = 200
End Sub
Public Sub view()
'显示每个格子
Const 灰 = 8421504                  '线框颜色
Const 死 = 16777215                 '死颜色
Const 生 = 65280                    '生颜色
Dim hd As Long, ld As Long, i As Long, j As Long, c As Long
i = Me.ScaleWidth
hd = i \ 横
i = Me.ScaleHeight
ld = i \ 竖
If hd < Screen.TwipsPerPixelX * 3 Or ld < Screen.TwipsPerPixelY * 3 Then Exit Sub
'如果不够绘图,则直接退出
For i = 0 To 横 - 1
    For j = 0 To 竖 - 1
        c = 死
        If z(i + 1, j + 1) = 1 Then c = 生      '生,就用生画格
        Me.Line (i * hd + Screen.TwipsPerPixelX, j * ld + Screen.TwipsPerPixelY)-(i * hd + hd - Screen.TwipsPerPixelX, j * ld + ld - Screen.TwipsPerPixelY), c, BF
    Next j
Next i
End Sub
Private Sub Form_Resize()
'窗体大小改变时,计算格子大小
Dim i As Long
Me.Cls
Call view           '重绘格子
End Sub
Public Sub r()              '运算函数
Dim i As Long, j As Long, k As Integer
Dim o As Long
Dim l(横 + 1, 竖 + 1) As Byte               '中间数组
For i = 1 ToFor j = 1 To 竖
        o = 0                       '统计8个格子,这里分了8行写,也可以使用一个二次循环来写,循环需要6行代码
        For k = 0 To 8
          If k <> 4 Then o = o + z(i + Int(k / 3) - 1, j + k Mod 3 - 1)
        Next
        l(i, j) = 0
        Select Case o
            Case 3
        '规则1:如果一个细胞周围有3个细胞为生(一个细胞周围共有8个细胞),
        '则该细胞为生(即该细胞若原先为死,则转为生,若原先为生,则保持不变) 。
                l(i, j) = 1
            Case 2
        '规则2. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;
                l(i, j) = z(i, j)
        End Select
    Next j
Next i
'把中间结果写入目标
For i = 1 ToFor j = 1 To 竖
        z(i, j) = l(i, j)
    Next j
Next i
Call view
End Sub
Private Sub Timer1_Timer()
'定时器调用演变
js = js + 1
Call r
Me.Caption = "生命游戏(Game of Life) -- " & js
End Sub

能编个毛线衣吗?
2016-02-16 09:10
xiangyue0510
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:86
帖 子:938
专家分:5244
注 册:2015-8-10
收藏
得分:0 
这个绘图还算简单,复杂的就够呛了。 DX 的VB教程太少。我现在都转向VC++了,不过头疼啊。
2016-02-16 11:04
风吹过b
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:364
帖 子:4940
专家分:30047
注 册:2008-10-15
收藏
得分:0 
回复 7楼 wmf2014
中间结果,我知道可以不用定义为全局变量,我当时的考虑是:因为中间结果这个数据是每次都是固定大小,如果定义为局部变量,每次运行都要重新分配,运行速度方面应该会受到影响。
颜色变量:主要是为了放到程序头,便于修改。还有, 常量,以及常量表达式,在预编译阶段会被值给代替,也就是说这个常量定义对于代码来说,无论定义在什么地方,编译时都是一样的使用结果,只是有一个作用域的区别。
关于格子大小的变量:
格子线绘制我是放在 改变窗体重绘事件中,所以 每个格子的大小需要在二个过程中使用。
如果格子线绘制也一起放在 view 过程中,会因为事务过多,屏幕闪烁更明显。
JS:我显示在窗体标题上,用于显示当前演示到第几回合。我一般使用全局变量,也可以使用静态变量。


[此贴子已经被作者于2016-2-17 17:24编辑过]


授人于鱼,不如授人于渔
早已停用QQ了
2016-02-16 17:22
yuk_yu
Rank: 3Rank: 3
等 级:论坛游侠
帖 子:334
专家分:134
注 册:2009-3-16
收藏
得分:0 
回复 9楼 风吹过b
静静的看版主们讨论,我不出声!
2016-02-17 09:32
快速回复:生命游戏(Game of Life)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020254 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved