• Go语言模拟康威生命游戏Conway‘s Game of Life


            康威生命游戏是一种很有意思的游戏,显示的是细胞的生死状态取决于周边细胞(相邻8个细胞)的存活状态,是一种模拟生命的演化过程。

    反过来看,还可模拟病毒的传染,患者传染给接触者,也可以设定概率,另外是否戴口罩的概率也不一样,这样我们可以可视化病毒在某个地区的传播情况。

    那么对于模拟这个世界的生命游戏,需遵循如下的游戏规则:

    周边存活细胞=2,这个细胞保持原状态不变;
    周边存活细胞<2,这个细胞就孤独而死;周边存活细胞>3,这个细胞就拥挤而死;
    实际若死亡细胞的周边有存活细胞=3,这个死亡细胞会因为繁衍而复活。 

    1. package main
    2. import (
    3. "bytes"
    4. "fmt"
    5. "math/rand"
    6. "time"
    7. )
    8. // 定义一个名为Filed的二维矩阵结构体(存放细胞的生死状态与宽高)
    9. // 高宽就是行列,每个细胞看做是一个单元格
    10. type Field struct {
    11. s [][]bool
    12. w, h int
    13. }
    14. // 创建一个h行w列的二维矩阵(每个细胞默认false,死亡状态)
    15. // 换句话说就是创建一个多大面积的世界
    16. func NewField(w, h int) *Field {
    17. s := make([][]bool, h)
    18. for i := range s {
    19. s[i] = make([]bool, w)
    20. }
    21. return &Field{s: s, w: w, h: h}
    22. }
    23. // 设置指定位置细胞的生死状态
    24. func (f *Field) Set(x, y int, b bool) {
    25. f.s[y][x] = b
    26. }
    27. // 这个游戏里的世界是循环世界,没有边界,就是说左右边缘相邻,上下边缘相邻,如果说超过边界就相当于回到另一边
    28. // 返回指定细胞(坐标点)的生死状态
    29. func (f *Field) Alive(x, y int) bool {
    30. x += f.w
    31. x %= f.w
    32. y += f.h
    33. y %= f.h
    34. return f.s[y][x]
    35. }
    36. // 返回下个时间步的细胞的状态
    37. // 3个存活细胞就复活,2个存活细胞就保持原状
    38. func (f *Field) Next(x, y int) bool {
    39. // 计算相邻的存活细胞数量
    40. alive := 0
    41. for i := -1; i <= 1; i++ {
    42. for j := -1; j <= 1; j++ {
    43. //不包括自己(0,0)的周边8个细胞的状态
    44. if (j != 0 || i != 0) && f.Alive(x+i, y+j) {
    45. alive++
    46. }
    47. }
    48. }
    49. return alive == 3 || alive == 2 && f.Alive(x, y)
    50. }
    51. // 存储每轮生命游戏的状态
    52. type Life struct {
    53. a, b *Field
    54. w, h int
    55. }
    56. // 返回一个随机的新生命(true,活细胞)的游戏状态
    57. func NewLife(w, h int) *Life {
    58. a := NewField(w, h)
    59. for i := 0; i < (w * h / 4); i++ {
    60. a.Set(rand.Intn(w), rand.Intn(h), true)
    61. }
    62. return &Life{
    63. a: a, b: NewField(w, h),
    64. w: w, h: h,
    65. }
    66. }
    67. // 下一代将重新计算并更新所有细胞的状态
    68. func (l *Life) Step() {
    69. // 根据当代世界a的状态去更新下一代世界b的状态
    70. for y := 0; y < l.h; y++ {
    71. for x := 0; x < l.w; x++ {
    72. l.b.Set(x, y, l.a.Next(x, y))
    73. }
    74. }
    75. // 交换世界a与b的状态(世界b的状态成为当代世界,原本a世界保留结构做下一轮计算的缓存)
    76. l.a, l.b = l.b, l.a
    77. }
    78. // 将生命游戏的界面作为字符串返回
    79. func (l *Life) String() string {
    80. var buf bytes.Buffer
    81. for y := 0; y < l.h; y++ {
    82. for x := 0; x < l.w; x++ {
    83. b := byte(' ')
    84. if l.a.Alive(x, y) {
    85. b = '*'
    86. }
    87. buf.WriteByte(b)
    88. }
    89. buf.WriteByte('\n')
    90. }
    91. return buf.String()
    92. }
    93. func main() {
    94. l := NewLife(100, 20)
    95. for i := 0; i < 300; i++ {
    96. l.Step()
    97. fmt.Print("\x0c", l) // 清屏和打印游戏状态
    98. time.Sleep(time.Millisecond*50)
    99. }
    100. }

    当然实际上是动态变化的,这个是循环结束的一张截图,大家运行下可以看看这个生命(细胞)在整个区域的繁衍与死亡的过程。 

    其中Go语言函数的定义遇到和其他语言都不一样的地方,就是函数名称前面有括号的情况:

    1. func (f *Field) Set(x, y int, b bool) {
    2. f.s[y][x] = b
    3. }

    我们看到在函数名称前面出现一个括号(f *Field),这个是Go定义这些,函数将在其上运行的对象的方式。本质上Set函数是一个类型处理程序的方法,可以使用类型处理程序的任何对象来调用,比如f
    我们单独来看一个示例,再熟悉下这个用法以及指针的区别,还记得吗?

    1. import "fmt"
    2. type person struct {
    3. name string
    4. hobby string
    5. }
    6. func (p person) GetInfo1() {
    7. p.name = "Tony"
    8. p.hobby = "Reading"
    9. }
    10. func (p *person) GetInfo2() {
    11. p.name = "Tony"
    12. p.hobby = "Reading"
    13. }
    14. func main() {
    15. p := &person{"小丑", "Murder"}
    16. p.GetInfo1()
    17. fmt.Println(p)
    18. //&{小丑 Murder}
    19. p.GetInfo2()
    20. fmt.Println(p, p.name, p.hobby)
    21. //&{Tony Reading} Tony Reading
    22. }

    可以看出这种调用函数的方式比较特别,需要前面的自定义类型的前缀来调用函数,简单的可以看做自定义类型可以当做class,然后函数当做是class下面的实例对象。 

  • 相关阅读:
    申报设立2022年湖北省博士后创新实践基地条件、时间、流程
    Linux配置Java环境变量 详解
    MySQL 基础篇 约束 多表查询 事务
    华科重要实验
    Flink--7、窗口(窗口的概念、分类、API、分配器、窗口函数)、触发器、移除器
    移动web技术方案
    RPC远程调用框架Dubbo
    C++学习第二十一天----函数
    搬家快递服务预约小程序的作用是什么
    【Elasticsearch】ES选主流程分析
  • 原文地址:https://blog.csdn.net/weixin_41896770/article/details/127613383