【生命游戏】从零实现一个可交互的Web前端模拟器

发布时间:2026/10/25 20:14:14

【生命游戏】从零实现一个可交互的Web前端模拟器 1. 生命游戏简介与实现思路生命游戏Game of Life是英国数学家约翰·康威在1970年提出的一种细胞自动机。它由一个二维网格组成每个格子代表一个细胞细胞有两种状态存活或死亡。游戏的规则非常简单孤单死亡如果细胞的邻居小于等于1个则该细胞在下一次状态将死亡拥挤死亡如果细胞的邻居在4个及以上则该细胞在下一次状态将死亡稳定如果细胞的邻居为2个或3个则下一次状态为稳定存活复活如果某位置原无细胞存活而该位置的邻居为2个或3个则该位置将复活一个细胞这些简单的规则却能产生极其复杂和有趣的行为模式这也是生命游戏经久不衰的魅力所在。实现一个Web版的生命游戏模拟器我们需要考虑以下几个核心部分网格系统用二维数组表示细胞状态渲染系统将细胞状态可视化展示规则引擎计算每个细胞的下一个状态交互系统允许用户与模拟器互动控制面板提供开始/暂停、速度调节等功能2. 搭建基础HTML结构我们先从最基础的HTML结构开始。创建一个index.html文件包含以下内容!DOCTYPE html html head meta charsetutf-8 title生命游戏模拟器/title link relstylesheet hrefstyle.css /head body div classcontainer h1生命游戏模拟器/h1 div classgame-container div classgame-intro h2游戏规则/h2 p生命游戏为1970年由英国数学家J. H. Conway所提出.../p !-- 规则说明 -- /div div classgame-grid idgrid/div div classgame-controls div classsettings div classsetting label网格大小:/label input typenumber idgrid-size min10 max100 value30 /div div classsetting label演化速度(ms):/label input typenumber idspeed min50 max2000 value200 /div /div div classbuttons button idstart开始/button button idpause暂停/button button idreset重置/button button idrandom随机填充/button button idnext下一步/button /div /div /div /div script srcscript.js/script /body /html这个结构包含了三个主要部分游戏规则说明区游戏网格展示区控制面板区3. 使用CSS美化界面接下来我们添加一些基本的样式。创建style.css文件* { margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif; } body { background-color: #f0f0f0; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; } h1 { text-align: center; margin: 20px 0; color: #333; } .game-container { display: flex; gap: 20px; margin-top: 20px; } .game-intro { flex: 1; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .game-grid { flex: 2; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); display: grid; grid-template-columns: repeat(30, 1fr); grid-template-rows: repeat(30, 1fr); aspect-ratio: 1/1; } .cell { border: 1px solid #eee; cursor: pointer; } .cell.alive { background-color: #4CAF50; } .game-controls { flex: 1; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .settings { margin-bottom: 20px; } .setting { margin-bottom: 15px; } .setting label { display: block; margin-bottom: 5px; font-weight: bold; } .setting input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } .buttons { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } .buttons button { padding: 10px; border: none; border-radius: 4px; background-color: #4CAF50; color: white; cursor: pointer; transition: background-color 0.3s; } .buttons button:hover { background-color: #45a049; } .buttons button:active { background-color: #3e8e41; }4. JavaScript核心逻辑实现现在我们来编写JavaScript代码。创建script.js文件// 游戏状态 const gameState { gridSize: 30, speed: 200, isRunning: false, grid: [], nextGrid: [], timer: null }; // 初始化游戏 function initGame() { const gridElement document.getElementById(grid); gridElement.innerHTML ; gridElement.style.gridTemplateColumns repeat(${gameState.gridSize}, 1fr); gridElement.style.gridTemplateRows repeat(${gameState.gridSize}, 1fr); // 初始化网格数组 gameState.grid Array(gameState.gridSize).fill().map(() Array(gameState.gridSize).fill(0) ); gameState.nextGrid Array(gameState.gridSize).fill().map(() Array(gameState.gridSize).fill(0) ); // 创建网格元素 for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { const cell document.createElement(div); cell.className cell; cell.dataset.row i; cell.dataset.col j; cell.addEventListener(click, toggleCell); gridElement.appendChild(cell); } } } // 切换细胞状态 function toggleCell(e) { if (gameState.isRunning) return; const row parseInt(e.target.dataset.row); const col parseInt(e.target.dataset.col); gameState.grid[row][col] gameState.grid[row][col] ? 0 : 1; e.target.classList.toggle(alive); } // 计算下一代 function nextGeneration() { // 计算每个细胞的下一个状态 for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { const neighbors countNeighbors(i, j); // 应用生命游戏规则 if (gameState.grid[i][j] 1) { gameState.nextGrid[i][j] (neighbors 2 || neighbors 3) ? 1 : 0; } else { gameState.nextGrid[i][j] (neighbors 3) ? 1 : 0; } } } // 更新网格和UI updateGrid(); } // 计算邻居数量 function countNeighbors(row, col) { let count 0; for (let i -1; i 1; i) { for (let j -1; j 1; j) { if (i 0 j 0) continue; const newRow row i; const newCol col j; if (newRow 0 newRow gameState.gridSize newCol 0 newCol gameState.gridSize) { count gameState.grid[newRow][newCol]; } } } return count; } // 更新网格显示 function updateGrid() { const cells document.querySelectorAll(.cell); for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { gameState.grid[i][j] gameState.nextGrid[i][j]; const index i * gameState.gridSize j; if (gameState.grid[i][j] 1) { cells[index].classList.add(alive); } else { cells[index].classList.remove(alive); } } } } // 随机填充网格 function randomFill() { const cells document.querySelectorAll(.cell); for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { gameState.grid[i][j] Math.random() 0.7 ? 1 : 0; const index i * gameState.gridSize j; if (gameState.grid[i][j] 1) { cells[index].classList.add(alive); } else { cells[index].classList.remove(alive); } } } } // 重置游戏 function resetGame() { stopGame(); initGame(); } // 开始游戏 function startGame() { if (gameState.isRunning) return; gameState.isRunning true; gameState.timer setInterval(nextGeneration, gameState.speed); document.getElementById(start).disabled true; document.getElementById(pause).disabled false; } // 暂停游戏 function stopGame() { if (!gameState.isRunning) return; gameState.isRunning false; clearInterval(gameState.timer); document.getElementById(start).disabled false; document.getElementById(pause).disabled true; } // 更新游戏速度 function updateSpeed() { gameState.speed parseInt(document.getElementById(speed).value); if (gameState.isRunning) { stopGame(); startGame(); } } // 更新网格大小 function updateGridSize() { const newSize parseInt(document.getElementById(grid-size).value); if (newSize 10 newSize 100) { gameState.gridSize newSize; resetGame(); } } // 初始化事件监听 function initEvents() { document.getElementById(start).addEventListener(click, startGame); document.getElementById(pause).addEventListener(click, stopGame); document.getElementById(reset).addEventListener(click, resetGame); document.getElementById(random).addEventListener(click, randomFill); document.getElementById(next).addEventListener(click, nextGeneration); document.getElementById(speed).addEventListener(change, updateSpeed); document.getElementById(grid-size).addEventListener(change, updateGridSize); } // 初始化应用 function initApp() { initEvents(); initGame(); } // 启动应用 window.onload initApp;5. 性能优化与Canvas实现虽然上面的实现已经可以工作但当网格变大时使用DOM元素渲染性能会下降。我们可以改用Canvas来提升性能// 替换原来的game-grid div为canvas div classgame-area canvas idgame-canvas/canvas /div // 更新CSS .game-area { flex: 2; background: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); position: relative; } #game-canvas { width: 100%; height: 100%; display: block; } // 修改JavaScript部分 const canvas document.getElementById(game-canvas); const ctx canvas.getContext(2d); let cellSize 0; function initGame() { // 设置canvas尺寸 const container document.querySelector(.game-area); canvas.width container.clientWidth; canvas.height container.clientHeight; cellSize canvas.width / gameState.gridSize; // 初始化网格数组 gameState.grid Array(gameState.gridSize).fill().map(() Array(gameState.gridSize).fill(0) ); gameState.nextGrid Array(gameState.gridSize).fill().map(() Array(gameState.gridSize).fill(0) ); // 绘制网格 drawGrid(); // 添加点击事件 canvas.addEventListener(click, handleCanvasClick); } function drawGrid() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制背景 ctx.fillStyle white; ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制网格线 ctx.strokeStyle #eee; ctx.lineWidth 0.5; for (let i 0; i gameState.gridSize; i) { // 垂直线 ctx.beginPath(); ctx.moveTo(i * cellSize, 0); ctx.lineTo(i * cellSize, canvas.height); ctx.stroke(); // 水平线 ctx.beginPath(); ctx.moveTo(0, i * cellSize); ctx.lineTo(canvas.width, i * cellSize); ctx.stroke(); } // 绘制存活细胞 ctx.fillStyle #4CAF50; for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { if (gameState.grid[i][j] 1) { ctx.fillRect( j * cellSize 1, i * cellSize 1, cellSize - 2, cellSize - 2 ); } } } } function handleCanvasClick(e) { if (gameState.isRunning) return; const rect canvas.getBoundingClientRect(); const x e.clientX - rect.left; const y e.clientY - rect.top; const col Math.floor(x / cellSize); const row Math.floor(y / cellSize); if (row 0 row gameState.gridSize col 0 col gameState.gridSize) { gameState.grid[row][col] gameState.grid[row][col] ? 0 : 1; drawGrid(); } } function updateGrid() { for (let i 0; i gameState.gridSize; i) { for (let j 0; j gameState.gridSize; j) { gameState.grid[i][j] gameState.nextGrid[i][j]; } } drawGrid(); }6. 添加更多功能与优化现在我们的生命游戏模拟器已经基本完成但还可以添加一些有用的功能模式选择预定义一些有趣的初始模式颜色主题允许用户自定义细胞颜色网格显示切换可以隐藏网格线历史记录记录演化历史导出/导入保存和加载特定模式// 在控制面板添加新按钮 div classbuttons !-- 原有按钮... -- button idpatterns模式/button button idtheme切换主题/button button idtoggle-grid隐藏网格/button /div // 添加模式选择对话框 div idpattern-modal classmodal div classmodal-content span classclosetimes;/span h3选择模式/h3 div classpattern-list div classpattern>
延伸阅读

更多相关文章

2026/10/24 17:43:24

Wireshark网络数据分析实战:从FTP/Telnet协议解析到攻击链还原

1. 项目概述与核心价值“2019年全国职业院校技能大赛中职组‘网络空间安全’-数据分析3”,这个标题对于圈内人来说,一眼就能看出其分量。它不是一个简单的练习题,而是直接对标国内顶尖职业技能竞赛的实战场景。这类赛题的核心,从来…

2026/10/24 16:33:58

第23篇-macOS伴侣应用.md

【OpenClaw 从入门到精通】第 23 篇:macOS 伴侣应用(OpenClaw.app) 本系列定位:零基础入门,从安装配置到高级架构全覆盖。 本篇你将学到 macOS 伴侣应用功能菜单栏控制Voice Wake 唤醒词macOS 权限设置 一、OpenClaw.…

2026/10/24 18:50:45

Gemini Live代管复杂任务:从语音指令到数字代理的跃迁

去年年底有几个晚上,我几乎每天都在反复切换手机上的语音助手和各类效率工具,只为了把一件其实并不复杂的事情理顺:安排一次跨三个城市的出差行程,同时要处理两封需要不同措辞的邮件,还要在间隙里找到时间把当天的会议…

2026/10/25 20:10:04

统计学习方法三要素:模型、策略与算法实战解析

简介:清华大学数据分析与统计学系列课程第一章“统计学习方法概论”PPT讲义,面向数据科学、机器学习初学者及需要系统梳理统计学习基础的研究者。这一章共32页,系统搭建统计学习的完整框架:从统计学习对象与目的出发,讲…

2026/10/25 20:10:04

BP神经网络在沥青路面裂缝识别中的工程落地实践

简介:本资源是一篇聚焦工程实践与算法落地的学术论文,面向交通工程、智能检测及人工智能应用领域的研究者与高年级本科生,旨在解决沥青路面图像噪声强、传统边缘检测易误判裂缝等实际问题。论文提出基于BP神经网络的裂缝识别方法:…

2026/10/25 20:10:04

C#文件元数据采集:逻辑大小、物理占用与Win32底层属性全解析

简介:这是一份面向C#初学者与Windows桌面开发者的实用文件操作示例工程,解决批量获取目录内文件元信息的实际需求,适用于文件管理工具开发、系统运维脚本编写等场景。资源为完整VS解决方案包,共12个文件,包含6个核心C#…

2026/10/25 20:10:04

分片向量检索的“无损合并”,究竟需要哪些前提

分片结果合并前,先问每个分片返回的是什么。若它返回同一距离定义下的精确Top-K,合并不是近似问题;若分片内部已经漏召回,协调器排得再认真,也只能处理手里那批候选。 原理示意,非真实系统截图或性能测量。…

2026/10/25 20:05:03

美赛数学建模QGIS地图底图与空间分析实战指南

简介:面向数学建模参赛者与地理数据分析学习者的中国地理数据包,聚焦美赛等竞赛中涉及中国空间问题的建模需求。资源共2000个文件,全部为json格式,压缩包约38.67MB,涵盖国家级至县级行政边界及省市区规划信息&#xff…

2026/10/25 20:05:03

物流运输管理系统Java源码实战:核心模块与部署全流程解析

简介:物流运输管理系统java.zip是一套面向物流企业和Java开发者的完整TMS运输管理解决方案,覆盖订单管理、车辆管理、路线规划、货物追踪、费用计算、报表分析和客户服务等核心业务,适合用于物流信息化项目二次开发或Java Web综合实践。压缩包…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/25 0:02:22

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/25 0:02:23

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/25 0:02:23

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑