它并不是真正的“游戏”——更像是数学家约翰·何顿·康威的一套规则。想象一个细胞网格,就像电子表格或一个 <table>
。每个单元格要么存活,要么死亡。“回合”一个接一个地进行。在每一轮中,都有一些规则决定活细胞是否应该继续存活或死亡,以及死细胞是否应该继续死亡或变成活细胞。
规则
它有点像模拟现实生活环境。细胞可能因人口过少或过多而死亡,并且只能在完美的情况下存活。规则非常简单
- 活细胞 – 活邻居少于 2 个 – 死亡(人口过少)。
- 活细胞 – 2 或 3 个邻居 – 继续存活(完美情况)。
- 活细胞 – 活邻居超过 3 个 – 死亡(人口过多)。
- 死细胞 – 恰好有三个活邻居 – 变成活细胞(繁殖)。
为什么要谈论这个?
我对此感到非常怀旧。生命游戏的视觉版本是我在高中做的第一个编程项目。或者如果不是第一个,那就是第一个让我“恍然大悟”的项目,让我意识到编程和设计可以非常有趣和令人着迷。
给任何程序员提出这个问题,他们可能会用稍微不同的方式解决它。
- 应该用什么语言编写?
- 我们如何将其干净地构建?
- 我们如何使其计算速度更快?
- 在它变慢之前,我们可以把它做多大?
- 我们如何最好地存储数据和状态?
- 如何处理边缘?
给任何设计师提出这个问题,结果看起来都会不同。
- 什么颜色有意义?
- 除了存活和死亡之外,我们是否应该为状态使用不同的颜色?
- 单元格应该多大才有趣?
- 回合的速度应该多快才有趣,而不是让人不知所措?
- 你能与之互动吗?
- 你能向前和向后穿越时间吗?
- 如何打开和关闭单元格?点击?拖动?随机化?
- 可以创建哪些最有趣的形状?我们能否展示这些形状?
我之所以提出这一点,还因为我记得几年前尝试制作一个演示,那个演示非常糟糕,以至于我嫉妒所有那些酷炫的演示。我基本上使用 jQuery 查询 DOM 以获取每个单元格的邻居,效率低下得我可能应该被天线打一顿。
示例
我的第一个版本是在旧款苹果电脑上的 Turbo Pascal 上开发的。我很高兴地知道,这个小小的视觉数学练习如今仍然活跃,人们正在使用我构建的工具来制作版本。即使在使用相同技术的演示中,方法也可能有所不同!我还有一个集合。
Canvas 上的 JavaScript
带有一点 jQuery
查看 John H Moore 在 CodePen 上创作的笔 康威的生命游戏(@john-h-moore)。
不带 jQuery
查看 Qbit 在 CodePen 上创作的笔 生命游戏(@Qbit42)。
查看 Dennis Kerzig 在 CodePen 上创作的笔 Canvas 上的生命游戏(@wottpal)。
<table>
上的 JavaScript
查看 Alan R. Soares 在 CodePen 上创作的笔 payKn(@alanrsoares)。
Backbone.js
查看 Eric Miller 在 CodePen 上创作的笔 Backbone 中的生命游戏(@SimpleAsCouldBe)。
使用 CSS box-shadow 绘制单元格
查看 Joris van de Donk 在 CodePen 上创作的笔 box-shadow 生命游戏(@jorisvddonk)。
在 CoffeeScript 中
查看 Hanganu Petru-Alin 在 CodePen 上创作的笔 mctCv(@Lynku)。
在 D3.js 中
快速!
查看 Reed Spool 在 CodePen 上创作的笔 生命游戏 – D3(@reedspool)。
这些仅仅是前端示例,但您可以在任何语言中轻松找到示例。查看 Golly 以获取原生应用程序版本,并查看维基百科页面以获取更多信息。关于生命游戏,一个特别有趣的事情是各种奇怪的结构都是可能的,这些结构以奇怪的方式“创造生命”或维持生命。
我从未见过纯 CSS 版本。这可能吗?使用奇怪的定位和复杂的选取器会非常复杂。但是他们说 Sass 是“图灵完备的”,这意味着它是可能的,对吧?或者是否有其他限制在起作用?
我很想看看生命游戏的更多奇怪的前端示例。或者您过去关于它的任何故事 =)。
这是我的版本,仅使用 238b 的 HTML 和 JS
http://xem.github.io/miniGameOfLife/
喜欢。
关于纯 CSS 版本
Sass 是图灵完备的与问题无关,因为浏览器不使用 Sass——它们使用 Sass 编译成的 CSS。问题应该是,“CSS 是图灵完备的吗?”
快速查看Stack Overflow后,发现答案存在冲突。最佳答案展示了一种将规则110嵌入CSS的方法(查看方法),但正如其中一条评论指出的,CSS很难进行多次迭代。CSS只会被评估一次,然后就结束了。点击查看Stack Overflow讨论
我个人的(基于网络信息形成的)观点是,CSS可能是图灵完备的,但是除非你能想出一种解决迭代问题的方法,否则无法用它创建“真正的”生命游戏。
但这并不意味着你不能尝试!来吧,证明我错了!我很乐意看到! (另外,我基于网络信息形成的观点很有可能就是错的:-)
实际上,less.js及其modifyVars函数可以在一定程度上解决迭代问题,只需要少量JS的辅助。稍等,我去构建它。
我之前做了一个库,降低了创建此类模拟的门槛。如果你感兴趣的话,可以查看一下 :)
为什么不尝试用范畴论来调剂生活?毕竟,
“评估元胞自动机是共单子的” http://blog.sigfpe.com/2006/12/evaluating-cellular-automata-is.html
刚刚看到这个,我很自豪你展示了我的代码!:-D 非常棒的文章
很棒的文章,谢谢!
结果,它也是我的第一个程序……1984年在IBM PC上用Basic编写的:) #ouch
亲爱的Chris,
我能要回我过去三个小时的生命吗?隆重推出……
CSS生命游戏
(单代)
http://codepen.io/AmeliaBR/pen/EifgL?editors=110
我一直对生命游戏情有独钟,但这只是一次荒谬的练习。然而,我确实自学了如何在SCSS和Jade中使用循环和变量,所以时间并没有完全浪费。
对于那些对计算机科学理论感兴趣的人来说,它只能运行一代的原因是,生命游戏是一个基于其内部状态变化的自持续模拟。CSS只能对用户导致的状态变化做出反应,而不能改变自身状态(你无法编写一个基于先前样式变化来选择元素的选择器)。因此,你无法使用第一代的逻辑来改变状态,然后对后续的世代再次使用相同的逻辑;你需要根据初始状态计算所有可能结果的规则。
例如,要创建一个两代系统,你需要考虑一个单元格的邻居的邻居的所有可能状态,然后创建相应的关键帧动画来显示变化。而我这个20*20的单代演示已经拥有足够多的规则来严重降低浏览器的速度……如果有一种方法可以在单个CSS规则中使用多个
nth-of-type
选择器时同步n
值,那么复选框黑客会容易得多。嗯。哇。感谢你探索这个话题。有趣的是,即使你无法迭代到第一轮之后,CSS确实拥有评估所有邻居的工具。
嗨,Amelia,
我不确定你是否会收到邮件回复,但请查看我在此线程中的长篇评论。我认为我找到了一个轮流执行的解决方案。这显然是CSS技巧,但我避免了转向JS :D。我还没有解决游戏本身的部分,所以也许我们可以把这些结合起来。
@Chris:是的,找出邻居很棘手。我走了一些死胡同(例如,单选按钮组),然后意识到我必须将所有复选框放在整个表格前面,以便单元格可以影响渲染顺序中位于它们前面的邻居。
@Rob:有趣的想法,但我仍然认为你无法克服CSS效果的单向性:你可以使用外部框架上的CSS来更改iframe的宽度,然后使用媒体查询做出反应,但你目前无法使用iframe中的CSS影响父框架。在WebComponents提案中,复杂的CSS规则可能会使这种循环变得可行。我还没有弄清楚如何按预期使用所有这些规则,更不用说如何滥用它们将CSS变成完整的编程语言了!
非常感谢
我第一次遇到它是在一个Amstrad 8256 PCW文字处理器中,该处理器也捆绑了CP/M,你可以通过一个我忘记了的键组合启动生命游戏……很棒的文章!
我有一个为JS1k创建的版本,它构建一个随机的“景观”,然后使用生命游戏的规则来模拟“燃烧”它的“火焰”:http://js1k.com/2014-dragons/demo/1709
我用纯CSS制作了一个数独检查器,需要一些JS将值写入属性。
http://codepen.io/FWeinb/pen/lLifw
我认为,CSS生命游戏中最直接的问题是游戏如何继续进行。人们很容易想要转向JS来触发回合。
动画有步骤,但它们是有限的。然而,它们可以循环,所以存在可能性。另一个有趣的事实是,并非所有属性都可以原子地更改,特别是高度/宽度/边距/填充都会影响布局,理论上可以将其用作触发机制。我们在CSS中没有太多监听器,但我们有一些:
:hover
/:active
依赖于用户,但媒体查询是一个有趣的选项,因为它们依赖于我们的朋友width
。现在,众所周知,我们没有元素查询(boo!),但我们确实有iframe,它们充当元素查询(我的评论在遇到一个表情符号后被截断了。
我认为,CSS生命游戏中最直接的问题是游戏如何继续进行。人们很容易想要转向JS来触发回合。
动画有步骤,但它们是有限的。然而,它们可以循环,所以存在可能性。另一个有趣的事实是,并非所有属性都可以原子地更改,特别是高度/宽度/边距/填充都会影响布局,理论上可以将其用作触发机制。我们在CSS中没有太多监听器,但我们有一些:
:hover
/:active
依赖于用户,但媒体查询是一个有趣的选项,因为它们依赖于我们的朋友width
。现在,众所周知,我们没有元素查询(boo!),但我们确实有iframe,它们充当元素查询:smiling_imp:。理论上,我们可以将这些事实结合起来。我们可以将iframe的宽度在循环中从一个小值动画到一个大值。然后在子框架中,我们可以在媒体查询中应用我们的轮流执行步骤。
现在要真正玩游戏,我看到上面评论中的Amelia B R有一个部分解决方案,所以也许我们可以改编它。
注意:iframe在css3动画/过渡方面有时会出现错误,但这没关系,我们只需将iframe宽度设置为100%并使用一个容器。
哦,天哪!我一直想用CSS编写这个,但一直不敢尝试。
这是我使用的方法,将地图分割成块,以减少计算大型地图上每一代所需的时间(警告:我不是设计师)
http://hermann.is/conway/
谢谢!很棒的文章!我永远不会忘记来自commodore的C64游戏;)))。
我的方法,只是Sass生成CSS动画
http://codepen.io/doingweb/pen/GEdHr
另一个例子生命游戏 +大量有趣的模式。尽情享受:-)
我记得在旧的Windows 98(?)计算机上,有一个生命游戏的版本,其中包含一个真正的竞争性“游戏”。
一定数量的“活”细胞被染成红色。
红色细胞可以像蓝色细胞一样相互作用。
目标是在一定数量的回合内使用逻辑消除所有红色细胞,只留下蓝色细胞。
如果你赢了,你就会获得一个数字诺贝尔奖。
用JS实现这一点会很有趣。