实现康威的生命游戏

在我们深入之前,我们有一些设计选择需要考虑。

生命游戏是在无限的宇宙中进行的,但我们没有无限的内存和计算能力。解决这个相当恼人的限制,通常有以下三种风格:

1。跟踪宇宙的哪个子集发生了有趣的事情,并根据需要,扩展此区域。在最坏的情况下,这种扩展是无限制的,实现将变得越来越慢,最终耗尽内存。

2。创建固定大小的Universe,边缘上的单元格具有较少的邻居比中间的单元格。这种方法的缺点是无限像滑翔机一样到达宇宙尽头的模式被扼杀了。

3。创建一个固定大小的周期性Universe,其中边缘上的单元格具有环绕到Universe另一侧的邻居。因为邻居环绕宇宙的边缘,滑翔机可以永远运行。

我们将实现第三种选择。

这是从本教程中,你要理解和获取的最重要的概念之一!

wasm_bindgen定义了,如何与跨边界复合结构一起工作的共识。它涉及封装Rust结构,将指针包装在JavaScript类中以实现可用性,或者从Rust索引到一个JavaScript对象表格。wasm_bindgen非常方便,但它不需要考虑我们的数据表示,以及跨越这个边界传递什么值和结构.。相反,将其视为实现您选择的接口设计的工具。

在设计WebAssembly和JavaScript之间的接口时,我们希望针对以下属性进行优化:

作为一般的经验法则,一个好的JavaScriptWebAssembly接口设计,通常是将大型,长寿命的数据结构实现,为生活在WebAssembly线性内存中的Rust类型,并作为不透明控制暴露给JavaScript.JavaScript调用,这些持有不透明控制的导出了的WebAssembly函数,转换数据,执行繁重的计算,查询数据,最终返回一个小的可复制结果。通过仅返回计算的小结果,我们避免在JavaScript垃圾收集堆和WebAssembly线性存储器之间,来回复制和序列化所有内容。

让我们首先列举一些要避免的危险。我们不希望在每次tick,都将整个Universe复制到WebAssembly线性内存。我们不希望为宇宙中的每个单元分配对象,也不想强加一个跨边界调用来读写每个单元。

这给我们留下了什么我们可以将Universe表示为,位于WebAssembly线性内存中的平面数组,并且每个单元格都有一个字节。0是一个死单元格,1是一个活单元格。

以下是4x4宇宙在内存中的样子:

要在Universe的给定行和列中,查找单元格的数组索引,我们可以使用以下公式:

在上一章中,我们克隆了一个初始项目模板.我们现在将修改该项目模板.

让我们开始删除wasm-game-of-life/src/lib.rs的alert导入和greet函数,并用单元格的类型定义替换它们:

##![allow(unused_variables)]#fnmain(){#[wasm_bindgen]#[repr(u8)]#[derive(Clone,Copy,Debug,PartialEq,Eq)]pubenumCell{Dead=0,Alive=1,}#}重要的是我们拥有#[repr(u8)],以便每个单元格表示为单个字节。同样重要的是Dead代表0,那个Alive是1,这样我们就可以轻松地计算一个单元格的活邻居。

接下来,让我们定义宇宙(Universe)。宇宙具有宽度和高度,以及长度为width*height的单元格向量。

##![allow(unused_variables)]#fnmain(){#[wasm_bindgen]pubstructUniverse{width:u32,height:u32,cells:Vec,}#}要访问给定行和列的单元格,我们将行和列转换为单元格向量的索引,如前所述:

##![allow(unused_variables)]#fnmain(){implUniverse{fnget_index(&self,row:u32,column:u32)->usize{(row*self.width+column)asusize}//...}#}为了计算单元格的下一个状态,我们需要计算其邻居有多少是活着的。我们来写一个live_neighbor_count方法,做到这一点!

##![allow(unused_variables)]#fnmain(){implUniverse{//...fnlive_neighbor_count(&self,row:u32,column:u32)->u8{letmutcount=0;fordelta_rowin[self.height-1,0,1].iter().cloned(){fordelta_colin[self.width-1,0,1].iter().cloned(){ifdelta_row==0&&delta_col==0{continue;}letneighbor_row=(row+delta_row)%self.height;letneighbor_col=(column+delta_col)%self.width;letidx=self.get_index(neighbor_row,neighbor_col);count+=self.cells[idx]asu8;}}count}}#}live_neighbor_count方法使用deltas和modulo来避免宇宙的边缘情况。当应用-1的增量时,我们添加self.height-1,然后让modulo做它的事,而不是试图减去1。row和column可以为0,如果我们试图减去1,从他们来看,会有一个无符号整数下溢。

##![allow(unused_variables)]#fnmain(){usestd::fmt;implfmt::DisplayforUniverse{fnfmt(&self,f:&mutfmt::Formatter)->fmt::Result{forlineinself.cells.as_slice().chunks(self.widthasusize){for&cellinline{letsymbol=ifcell==Cell::Dead{""}else{""};write!(f,"{}",symbol);}write!(f,"\n");}Ok(())}}#}最后,我们定义一个构造函数,用一个有趣的活单元格和死单元格模式来初始化宇宙,以及render方法:

##![allow(unused_variables)]#fnmain(){///Publicmethods,exportedtoJavaScript.#[wasm_bindgen]implUniverse{//...pubfnnew()->Universe{letwidth=64;letheight=64;letcells=(0..width*height).map(|i|{ifi%2==0||i%7==0{Cell::Alive}else{Cell::Dead}}).collect();Universe{width,height,cells,}}pubfnrender(&self)->String{self.to_string()}}#}有了这个,我们的生命游戏Rust实现的一半就完成了!

在wasm-game-of-life目录内,通过运行wasm-packbuild重新编译为WebAssembly。

首先,让我们添加一个用于渲染宇宙的

元素到wasm-game-of-life/www/index.html,就放在另外,我们想要这个
,以网页中间为中心.我们可以使用CSSflex来完成这项任务。添加以下内容在wasm-game-of-life/www/index.js的顶端,让我们修复我们的导入来引入Universe,而不是旧的greet函数:

import{Universe}from'./wasm_game_of_life';另外,获取我们刚加的

元素,并实例化新Universe的元素:

constpre=document.getElementById('game-of-life-canvas');constuniverse=Universe.new();JavaScript运行在[一个requestAnimationFrame循环][requestanimationframe]。在每次迭代中,它将当前的Universe绘制到

,然后运行Universe::tick。

constrenderLoop=()=>{pre.textContent=universe.render();universe.tick();requestAnimationFrame(renderLoop);};要开始渲染过程,我们所要做的就是为渲染循环的第一次迭代进行初始调用:

在Rust中生成(和分配)一个String,然后有wasm-bindgen将其转换为有效的JavaScript字符串,来会生成Universe单元格的不必要副本。其实在JavaScript代码知道Universe的宽度和高度,并且可以直接从JavaScript中读取WebAssembly线性内存中的单元格字节,我们就可以修改render方法,用来返回单元数组的开头指针。

首先,让我们把pre,换成了一个(它也应该在,为了从Rust实现中获取必要的信息,我们需要为Universe的宽度,高度和指向其单元数组的指针添加更多的一些getter函数。所有这些都暴露在JavaScript中。添加这些内容wasm-game-of-life/src/lib.rs:

##![allow(unused_variables)]#fnmain(){///Publicmethods,exportedtoJavaScript.#[wasm_bindgen]implUniverse{//...pubfnwidth(&self)->u32{self.width}pubfnheight(&self)->u32{self.height}pubfncells(&self)->*constCell{self.cells.as_ptr()}}#}接下来,在wasm-game-of-life/www/index.js,我们也从wasm-game-of-life导入Cell,和让我们定义JavaScript在渲染Canvas时将使用的一些常量:

import{Universe,Cell}from'wasm-game-of-life';constCELL_SIZE=5;//pxconstGRID_COLOR='#CCCCCC';constDEAD_COLOR='#FFFFFF';constALIVE_COLOR='#000000';现在,让我们重写当前的JS代码(导入除外),不再写入

的textContent,而是专注在:

//构造theuniverse,andgetitswidthandheight.constuniverse=Universe.new();constwidth=universe.width();constheight=universe.height();//Givethecanvasroomforallofourcellsanda1pxborder//aroundeachofthem.constcanvas=document.getElementById('game-of-life-canvas');canvas.height=(CELL_SIZE+1)*height+1;canvas.width=(CELL_SIZE+1)*width+1;constctx=canvas.getContext('2d');constrenderLoop=()=>{universe.tick();drawGrid();drawCells();requestAnimationFrame(renderLoop);};为了在单元格之间绘制网格,我们绘制一组等间隔的水平线和一组等间距的垂直线。这些线纵横交错形成网格。

constdrawGrid=()=>{ctx.beginPath();ctx.lineWidth=1/window.devicePixelRatio;ctx.strokeStyle=GRID_COLOR;//Verticallines.for(leti=0;i<=width;i++){ctx.moveTo(i*(CELL_SIZE+1)+1,0);ctx.lineTo(i*(CELL_SIZE+1)+1,(CELL_SIZE+1)*height+1);}//Horizontallines.for(letj=0;j<=height;j++){ctx.moveTo(0,j*(CELL_SIZE+1)+1);ctx.lineTo((CELL_SIZE+1)*width+1,j*(CELL_SIZE+1)+1);}ctx.stroke();};我们可以直接通过memory拿到WebAssembly的线性内存,而这个memory由原生wasm模块wasm_game_of_life_bg提供。为了绘制单元格,我们拿到universe'scells的指针,构造一个覆盖单元格缓存的Uint8Array,迭代每个单元格,并分别根据单元格是死还是活,绘制白色或黑色矩形。通过使用指针和覆盖,我们避免在每次tick上跨边界复制单元格。

//文件顶部,导入WebAssemblymemoryimport{memory}from'./wasm_game_of_life_bg';//...constgetIndex=(row,column)=>{returnrow*width+column;};constdrawCells=()=>{constcellsPtr=universe.cells();//

requestAnimationFrame(renderLoop);请注意,在执行requestAnimationFrame()之前,我们要调用drawGrid()和drawCells()。我们这样做的原因是,在我们进行修改之前,绘制宇宙的初始状态。如果我们改为简单地调用requestAnimationFrame(renderLoop),我们最终得到的第一帧实际的绘制情况是,在第一次调用universe.tick()后,也就是这些单元格生命状态的第二次“tick”。

通过在根wasm-game-of-life目录中运行此命令,来重构建WebAssembly和绑定粘合剂:

wasm-packbuild确保您的开发服务器仍在运行。若没有,请从wasm-game-of-life/www目录内部再次启动:

您可以checkoutchapter-one分支找到完整代码.

答案

##![allow(unused_variables)]#fnmain(){//确保你添加此依赖到了Cargo.toml!externcratefixedbitset;usefixedbitset::FixedBitSet;//...#[wasm_bindgen]pubstructUniverse{width:u32,height:u32,cells:FixedBitSet,}#}可以通过以下方式调整Universe构造函数:

##![allow(unused_variables)]#fnmain(){pubfnnew()->Universe{letwidth=64;letheight=64;letsize=(width*height)asusize;letmutcells=FixedBitSet::with_capacity(size);foriin0..size{cells.set(i,i%2==0||i%7==0);}Universe{width,height,cells,}}#}要更新宇宙的下一个tick中的单元格,我们使用FixedBitSet的set方法:

##![allow(unused_variables)]#fnmain(){next.set(idx,match(cell,live_neighbors){(true,x)ifx<2=>false,(true,2)|(true,3)=>true,(true,x)ifx>3=>false,(false,3)=>true,(otherwise,_)=>otherwise});#}要将指向开头位的指针传递给JavaScript,您可以转换FixedBitSet到切片,然后将切片转换为指针:

##![allow(unused_variables)]#fnmain(){#[wasm_bindgen]implUniverse{//...pubfncells(&self)->*constu32{self.cells.as_slice().as_ptr()}}#}在JavaScript中,构建Wasm的内存成一个Uint8Array,与之前相同,只是数组的长度不再是width*height,而是width*height/8,因为我们一个位有一个单元,而不是字节(8位):

constcells=newUint8Array(memory.buffer,cellsPtr,(width*height)/8);给出一个索引和Uint8Array,你可以确定是否使用以下函数设置nth位:

constbitIsSet=(n,arr)=>{letbyte=Math.floor(n/8);letmask=1<

constdrawCells=()=>{constcellsPtr=universe.cells();//这时,已更新constcells=newUint8Array(memory.buffer,cellsPtr,(width*height)/8);ctx.beginPath();for(letrow=0;row

THE END
1.康威生命游戏Conway'sGameofLife游戏康威生命游戏的简介 Conway's Game of Life, also known as the Game of Life or simply Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. It is the best-known example of a cellular automaton. The "game" is actually a zero-player game, meaning https://www.douban.com/game/36778006
2.康威生命游戏康威生命游戏 康威生命游戏就像一个基于网格的游戏,每个方块都可以是活的也可以是死的。想象一下,一开始有些方块是活的,有些方块是死的。游戏遵循一些简单的想法来决定接下来会发生什么。 如果一个方块是活的,但有很少或太多的活邻居,它会在下一轮中死亡。如果它有恰好数量的邻居,它就会活着。如果一个死方块https://www.silvergames.com/zh/game-of-life
3.康威生命游戏下载康威生命游戏安卓版下载v0.2康威生命游戏是一款黑白系画风的益智闯关手游,游戏采用细胞模式的玩法,通过数字和逻辑推算,将格子中的细胞稳定在一定数量内,完成众多关卡的挑战,感兴趣的玩家赶紧来下载康威生命游戏安卓版试试吧。 康威生命游戏特色 1.日常生活的不一样演化。虽然这仅仅一个简单的游戏,但它能够 使大家能够更好地了解。 https://m.ali213.net/android/300771.html
4.康威生命游戏下载康威生命游戏 ( 剑桥数学家约翰康威发明的“细胞自动机”。 )《康威生命游戏》不是一个典型的电脑游戏,它模拟细胞生存进化,在细胞的基础上,加入了数学的规则,存活、死亡、繁殖的集合,根据初始方案的不同,细胞会在整个游戏过程中形成各种图案。语言:英文http://www.962.net/pcgame/29268.html
5.康威生命游戏游戏下载康威生命游戏游戏安卓版下载手机版康威生命游戏 2250 下载 25.86M 下载试玩 好游戏,一起玩 更多精品游戏尽在4399游戏盒 简介 写评论 发布 一般 您还可以输入300个字 评论详情 × 该游戏礼包只能在游戏盒领取的哦 取消 确认领取 × 马上去4399游戏盒付费,开始游戏吧 取消 确认 打开游戏盒查看详情 ? 如已安装游戏盒app,点击[立即打开]自动打开apphttp://a.4399.com/mobile/196007.html
6.康威的生命游戏Conway'sGameofLife集智百科康威生命游戏 (Conway's Game of Life),又称康威生命棋,是英国数学家约翰·何顿·康威 John Horton Conway在1970年发明的元胞自动机。[1] 该游戏是零玩家游戏,这意味着它的发展由其初始状态决定,不需要进一步的输入。通过创建初始配置并观察其演变,它可以与生命游戏互动。它是具有图灵完备性的,可以模拟通用构造器https://wiki.swarma.org/index.php?title=%E5%BA%B7%E5%A8%81%E7%9A%84%E7%94%9F%E5%91%BD%E6%B8%B8%E6%88%8F_Conway%27s_Game_of_Life
7.康威生命游戏下载康威生命游戏手机版下载v0.3康威生命游戏是款玩法比较有趣的益智小游戏,玩家在游戏中,可以自由的摆放各种生命图案,也能轻松导入各种经典的生命图案,随时随地在线观察这些生命的演化历程,演化规则可以从列表选择,支持自定义规则哦。 康威生命游戏说明 生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机,并被证明了图灵完备性。它最初于http://www.yzz.cn/game/15998.html
8.康威生命游戏手机版下载康威生命游戏免费下载v0.1康威生命游戏介绍 康威生命是一款休闲益智游戏。在游戏中,玩家会发现很多有趣的玩法,玩家会以各种难度挑战生命游戏规则,锻炼自己的逻辑思维能力,体验不同的生命形态,感受大自然的神秘。另外,还有很多关卡等着你去挑战,随着游戏难度的推进,你可以轻松加入进来,随时随地感受游戏的乐趣。喜欢就下载吧! 游戏玩法 1、动动https://www.7230.com/d820395
9.康威生命游戏(测试版)下载康威生命游戏(测试版)官方版下载康威生命游戏测试 开发商:新古拳 暂无评分 快爆评分 模拟器 休闲 单机 模拟 益智 游戏详情 评价 论坛1 游戏尚未发布正式版本,欢迎抢先试玩测试体验,提出你的宝贵意见! 游戏介绍 利用二维平面,探寻生命游戏 生命游戏是英国数学家约翰·何顿·康威在1970年发明的细胞自动机,并被证明了图灵完备性。它最初于1970年10https://www.3839.com/a/133283.htm
10.康威的生命游戏涌现模式:尽管规则很简单,康威的生命游戏却产生了复杂的模式,包括振荡器、滑翔机、宇宙飞船和稳定结构,随着时间的推移,它们表现出不同的行为和相互作用。 计算通用性:康威的生命游戏是图灵完备的,这意味着它可以在给定表示通用图灵机状态的初始配置的情况下模拟任何任意计算。 https://fourweekmba.com/zh-CN/%E5%BA%B7%E7%BB%B4%E6%96%AF%E7%9A%84%E7%94%9F%E5%91%BD%E6%B8%B8%E6%88%8F/
11.康威生命最新2024官网安卓版下载游戏简介 康威生命游戏中能够带给玩家更加烧脑的关卡挑战,通过模拟细胞生物存活的情况来让你了解到其中蕴含的各种生物结构的秘密,用更加简单易懂的操作帮助玩家去了解到不一样的科普知识,简单的像素画风让你能够更好的专注于关卡的破解,挑战更加烧脑的数学谜题! https://www.56yx.cn/game/65275.html
12.康威生命游戏【鼠鼠厨师(迎接期末还剩3天考试)】康威生命游戏,小码王scratch编程社区还有我的世界、跑酷、塔防、吃鸡、王者荣耀等更多趣味编程游戏创作作品,scratch编程就上小码王scratch编程社区https://world.xiaomawang.com/community/main/compose/E3FH666J
13.康威生命游戏剑桥大学约翰·何顿·康威(John Horton Conway)教授设计了一个叫做“生命游戏”的计算机程序,美国趣味数学大师马丁·加德纳(Martin Gardner,1914-2010)通过《科学美国人》杂志,将康威的生命游戏介绍给学术界之外的广大渎者,一时吸引了各行各业一大批人的兴趣,这时细胞自动机课题才吸引了科学家的注意。 https://baike.sogou.com/v175074467.htm
14.康威的生命游戏手游康威的生命游戏安卓预约下载最新手机正版链接豌豆荚康威的生命游戏手游下载官网为玩家们提供康威的生命游戏安卓正版预约下载链接,抢先体验2025最新康威的生命游戏手机版体验服、测试服、正式服等版本玩法,想要预约康威的生命游戏下载就到豌豆荚官网。https://www.wandoujia.com/download/592643/
15.康威生命游戏康威生命游戏作者:forward184 分享于:2024-03-08 21:21:33 转到Scratch 3.0 转到设计页 作品说明 创作过程 资源下载 采用谷歌浏览器体验更佳,点击下载谷歌浏览器绿色版。 902 0 0 评论() 您还可以输入500个字符。 发表 取消 关于我们 | 联系我们 ? 好好搭搭在线 浙ICP备19030393号-1 浙公网安备 https://www.haohaodada.com/show.php?id=1874449
16.康威生命游戏粤实少年蒸汽工坊scratch康威生命游戏 粤实少年 还没有人打赏! 0 0 12 0次打赏 最后修改于2024年11月17日 操作说明 按下空格时间流逝 刚开始请等2秒 备注与谢志 这家伙很懒,什么都没写下 开发日志 2024/11/16 16:052024/11/16 10:592024/11/15 19:32 2024/11/16 16:05https://www.steamcollection.com/project/378952/
17.康威生命游戏:可能是Gitee上最强大的康威生命游戏(GameofLife同步操作将从Futrime/康威生命游戏强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!! 确定后同步将在后台操作,完成时将刷新页面,请耐心等待。 删除在远程仓库中不存在的分支和标签 同步Wiki(当前仓库的 wiki 将会被覆盖!) ?取消? https://gitee.com/huiwei13/Game-of-Life
18.康威生命游戏手机最新版软件下载最新版【#娱乐消遣# #康威生命游戏iPhone版#】 简介描述 【hao86下载?iPhone版】嘿,各位二次元的小伙伴们!是不是对生命起源充满了好奇?今天,就由我这个“凡云酱大魔王”来给大家介绍一款超酷炫的软件——康威生命游戏手机最新版软件!它带你进入了一个奇妙的细胞世界,让你在手机上就能体验到生命的诞生与演变。康威生https://m.hao86.com/download/app_247510.html
19.康威游戏,数字世界中的生命之舞康威游戏还具有极高的可玩性和探索性,玩家可以通过调整初始状态和规则参数来创造出各种各样的生命世界,每个世界都有其独特的生态系统和演化历程,玩家可以观察、研究这些世界的演变过程,甚至可以预测未来的发展趋势,这种互动性和探索性使得康威游戏成为了一个极具吸引力的研究工具。 http://www.gxszxh.com.cn/syzx/52791.html
20.康威生命游戏下载中文康威生命游戏appv0.2安卓版分类:休闲益智 大小:18.1M 语言:中文 版本:v0.2 安卓版 时间:2021-05-07 11:07 星级: 官网:暂无 厂商: 平台:Android 标签:轻竞技手游益智游戏休闲游戏以数字模型来研究细胞生长。应用截图应用介绍 康威生命游戏app,一个在安卓手机上能够模拟细胞生命的小游戏,很具有科学实验道理,自动随机进化,观看不同的数字形态https://www.qqtn.com/azgame/667624.html