JavaScript 实现生命游戏

JavaScript 实现生命游戏攻略

生命游戏是一个经典的细胞自动机,它是由英国数学家约翰·何顿·康威于1970年发明的。该游戏规则虽然简单,但是可玩性极高,主要涉及到生死、繁衍和群体规律等内容。

本文主要介绍了如何使用 JavaScript 实现生命游戏,分别从实现规则和游戏界面两个方面进行阐述。

实现规则

生命游戏的规则和初始状态都是在网格上的,它主要受到它周围细胞的影响,如果相邻细胞数量过多,那么它就会死亡;相邻细胞数量过少也会死亡;相邻细胞数量适中,可以幸存下来。当一个死亡的细胞周围刚好有三个活细胞时,它就会变成活细胞。由此可见,游戏的规则相对复杂,需要使用 JavaScript 进行较多计算。

在 JavaScript 中,我们可以使用二维数组来表示整个网格。数组中的每个元素都是一个对象,记录了该细胞的坐标和当前状态(1 代表活细胞,0 代表死细胞)。下面是一个初始化网格的示例代码:

const width = 10;
const height = 10;
const cells = [];

for (let i = 0; i < width; i++) {
  cells[i] = [];
  for (let j = 0; j < height; j++) {
    cells[i][j] = {
      x: i,
      y: j,
      state: 0
    };
  }
}

在网格中随机设置几个细胞为活细胞,我们可以通过指定活细胞个数和网格范围进行。下面是一个简单的随机初始化代码:

const activeCellsCount = 10;

for (let i = 0; i < activeCellsCount; i++) {
  const randomX = Math.floor(Math.random() * width);
  const randomY = Math.floor(Math.random() * height);
  cells[randomX][randomY].state = 1;
}

接下来,我们需要计算出每个细胞周围的活细胞个数,根据生命游戏的规则进行状态更新。下面是一个完整的生命游戏计算函数:

function gameOfLife() {
  // 创建一个新数组,用于存储下一次迭代后的状态
  const newCells = cells.map(c => Object.assign({}, c));

  // 对于每个细胞,计算其周围的活细胞数量
  for (let i = 0; i < width; i++) {
    for (let j = 0; j < height; j++) {
      const cell = cells[i][j];
      const neighbors = getNeighbors(cell);
      const numActiveNeighbors = neighbors.filter(n => n.state === 1).length;

      // 更新该细胞的状态
      if (cell.state === 1 && (numActiveNeighbors < 2 || numActiveNeighbors > 3)) {
        newCells[i][j].state = 0;
      } else if (cell.state === 0 && numActiveNeighbors === 3) {
        newCells[i][j].state = 1;
      } else {
        newCells[i][j].state = cell.state;
      }
    }
  }

  // 将新状态赋值给旧状态
  cells = newCells;
}

其中,getNeighbors 函数用于计算指定细胞周围的八个细胞。这个函数的实现比较简单,这里不再赘述。

游戏界面

在生命游戏中,我们需要能够实时看到当前状态和每一步的变化。因此,我们需要实现一个简单的游戏界面用于展示生命游戏的状态。由于用户不会手动参与到游戏过程中,我们可以通过设置一个定时器循环计算和更新游戏状态,从而实现动态效果。

下面是一个简单的生命游戏界面实现代码:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>生命游戏</title>
  <style>
    .cell {
      width: 10px;
      height: 10px;
      display: inline-block;
    }

    .active {
      background-color: black;
    }
  </style>
</head>
<body>
  <div id="game"></div>

  <script>
    const width = 40;
    const height = 40;
    let cells = [];

    // 创建网格和初始化细胞
    const gameContainer = document.getElementById('game');
    for (let i = 0; i < width; i++) {
      const row = document.createElement('div');
      cells[i] = [];
      for (let j = 0; j < height; j++) {
        const cell = document.createElement('span');
        cell.classList.add('cell');
        if (i === 0 && j === 0) {
          cell.classList.add('active');
          cells[i][j] = 1;
        } else {
          cells[i][j] = 0;
        }
        row.appendChild(cell);
      }
      gameContainer.appendChild(row);
    }

    // 游戏循环
    setInterval(gameOfLife, 200);

    // 更新界面
    function updateView() {
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = gameContainer.children[i].children[j];
          cell.classList.toggle('active', cells[i][j] === 1);
        }
      }
    }

    // 生命游戏计算函数
    function gameOfLife() {
      // 创建一个新数组,用于存储下一次迭代后的状态
      const newCells = cells.map(c => c.slice());

      // 对于每个细胞,计算其周围的活细胞数量
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = cells[i][j];
          const neighbors = getNeighbors(cell);
          const numActiveNeighbors = neighbors.filter(n => n === 1).length;

          // 更新该细胞的状态
          if (cell === 1 && (numActiveNeighbors < 2 || numActiveNeighbors > 3)) {
            newCells[i][j] = 0;
          } else if (cell === 0 && numActiveNeighbors === 3) {
            newCells[i][j] = 1;
          }
        }
      }

      // 将新状态赋值给旧状态
      cells = newCells;
      updateView();
    }

    // 计算指定细胞周围的细胞状态数组
    function getNeighbors(cell) {
      const result = [];
      for (let i = cell.x - 1; i <= cell.x + 1; i++) {
        for (let j = cell.y - 1; j <= cell.y + 1; j++) {
          if (i < 0 || j < 0 || i >= width || j >= height || (i === cell.x && j === cell.y)) {
            continue;
          }
          result.push(cells[i][j]);
        }
      }
      return result;
    }
  </script>
</body>
</html>

在上述代码中,我们首先创建了一个基础的 HTML 结构,用于显示生命游戏的网格。随后,我们定义了一个定时器循环执行计算和更新状态的游戏循环。在游戏循环的实现中,我们通过获取 DOM 元素并用类名控制来实现网格的渲染。最后,我们实现了一个 getNeighbors 函数用于计算指定细胞周围的细胞状态数组。

示例

我们可以通过修改上述示例来实现各种生命游戏变化效果,例如实现不同的初始状态、不同的网格大小和不同的更新频率等等。下面展示了两个简单的示例代码。

示例一

在这个示例代码中,我们实现了一个仅包含单个活细胞的简单生命游戏。游戏过程中,该细胞会通过繁衍和死亡不断变化,最终可能会进入某种稳定状态。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>生命游戏示例1</title>
  <style>
    .cell {
      width: 10px;
      height: 10px;
      display: inline-block;
    }

    .active {
      background-color: black;
    }
  </style>
</head>
<body>
  <div id="game"></div>

  <script>
    const width = 40;
    const height = 40;
    let cells = [];

    // 创建网格和初始化细胞
    const gameContainer = document.getElementById('game');
    for (let i = 0; i < width; i++) {
      const row = document.createElement('div');
      cells[i] = [];
      for (let j = 0; j < height; j++) {
        const cell = document.createElement('span');
        cell.classList.add('cell');
        if (i === 20 && j === 20) {
          cell.classList.add('active');
          cells[i][j] = 1;
        } else {
          cells[i][j] = 0;
        }
        row.appendChild(cell);
      }
      gameContainer.appendChild(row);
    }

    // 游戏循环
    setInterval(gameOfLife, 200);

    // 更新界面
    function updateView() {
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = gameContainer.children[i].children[j];
          cell.classList.toggle('active', cells[i][j] === 1);
        }
      }
    }

    // 生命游戏计算函数
    function gameOfLife() {
      // 创建一个新数组,用于存储下一次迭代后的状态
      const newCells = cells.map(c => c.slice());

      // 对于每个细胞,计算其周围的活细胞数量
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = cells[i][j];
          const neighbors = getNeighbors(cell);
          const numActiveNeighbors = neighbors.filter(n => n === 1).length;

          // 更新该细胞的状态
          if (cell === 1 && (numActiveNeighbors < 2 || numActiveNeighbors > 3)) {
            newCells[i][j] = 0;
          } else if (cell === 0 && numActiveNeighbors === 3) {
            newCells[i][j] = 1;
          }
        }
      }

      // 将新状态赋值给旧状态
      cells = newCells;
      updateView();
    }

    // 计算指定细胞周围的细胞状态数组
    function getNeighbors(cell) {
      const result = [];
      for (let i = cell.x - 1; i <= cell.x + 1; i++) {
        for (let j = cell.y - 1; j <= cell.y + 1; j++) {
          if (i < 0 || j < 0 || i >= width || j >= height || (i === cell.x && j === cell.y)) {
            continue;
          }
          result.push(cells[i][j]);
        }
      }
      return result;
    }
  </script>
</body>
</html>

示例二

在这个示例代码中,我们实现了一个包含随机活细胞的生命游戏。由于该游戏初始状态随机生成,因此每次的运行效果都是不同的。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>生命游戏示例2</title>
  <style>
    .cell {
      width: 10px;
      height: 10px;
      display: inline-block;
    }

    .active {
      background-color: black;
    }
  </style>
</head>
<body>
  <div id="game"></div>

  <script>
    const width = 40;
    const height = 40;
    const activeCellsCount = 150;
    let cells = [];

    // 创建网格和随机初始化细胞
    const gameContainer = document.getElementById('game');
    for (let i = 0; i < width; i++) {
      const row = document.createElement('div');
      cells[i] = [];
      for (let j = 0; j < height; j++) {
        const cell = document.createElement('span');
        cell.classList.add('cell');
        if (Math.random() > 0.5) {
          cell.classList.add('active');
          cells[i][j] = 1;
        } else {
          cells[i][j] = 0;
        }
        row.appendChild(cell);
      }
      gameContainer.appendChild(row);
    }

    // 游戏循环
    setInterval(gameOfLife, 100);

    // 更新界面
    function updateView() {
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = gameContainer.children[i].children[j];
          cell.classList.toggle('active', cells[i][j] === 1);
        }
      }
    }

    // 生命游戏计算函数
    function gameOfLife() {
      // 创建一个新数组,用于存储下一次迭代后的状态
      const newCells = cells.map(c => c.slice());

      // 对于每个细胞,计算其周围的活细胞数量
      for (let i = 0; i < width; i++) {
        for (let j = 0; j < height; j++) {
          const cell = cells[i][j];
          const neighbors = getNeighbors(cell);
          const numActiveNeighbors = neighbors.filter(n => n === 1).length;

          // 更新该细胞的状态
          if (cell === 1 && (numActiveNeighbors < 2 || numActiveNeighbors > 3)) {
            newCells[i][j] = 0;
          } else if (cell === 0 && numActiveNeighbors === 3) {
            newCells[i][j] = 1;
          }
        }
      }

      // 将新状态赋值给旧状态
      cells = newCells;
      updateView();
    }

    // 计算指定细胞周围的细胞状态数组
    function getNeighbors(cell) {
      const result = [];
      for (let i = cell.x - 1; i <= cell.x + 1; i++) {
        for (let j = cell.y - 1; j <= cell.y + 1; j++) {
          if (i < 0 || j < 0 || i >= width || j >= height || (i === cell.x && j === cell.y)) {
            continue;
          }
          result.push(cells[i][j]);
        }
      }
      return result;
    }
  </script>
</body>
</html>

以上就是使用 JavaScript 实现生命游戏的完整攻略,希望对您有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 实现生命游戏 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • javascript基本数据类型和对象类型归档问题解析

    JavaScript基本数据类型和对象类型归档问题解析 基本数据类型 在JavaScript中,基本数据类型分为以下几种: Number:数字类型,包括整数和浮点数。 String:字符串类型。 Boolean:布尔类型,包括true和false。 Undefined: 值为undefined的类型。 Null:值为null的类型。 Symbol:ES6新增…

    JavaScript 2023年5月27日
    00
  • 关于vue 结合原生js 解决echarts resize问题

    关于vue结合原生js解决echarts resize问题,可以使用下面的攻略: 攻略说明 采用vue-echarts插件加载echarts,并且绑定图表的 DOM 元素到 vue 实例中 使用 js 的 resize() 方法,监听 window 大小变化,当窗口大小发生改变时,使用 triggerResize() 方法通知echarts自适应大小 示例说…

    JavaScript 2023年6月11日
    00
  • quickjs 封装 JavaScript 沙箱详情

    下面我将详细讲解如何封装JavaScript沙箱并提供两个实例说明。 QuickJS 封装 JavaScript 沙箱 前置要求 在开始封装JavaScript沙箱前,我们需要了解以下知识: QuickJS: 一款高效的Javascript引擎 沙箱: 限制JavaScript执行环境,避免恶意代码执行或获取主程序敏感信息 思路与方案 为了实现封装JavaS…

    JavaScript 2023年6月10日
    00
  • JavaScript 函数表达式与函数声明的用法及区别

    JavaScript 中函数是一等公民,这意味着函数可以用作变量,参数或返回值来传递。我们可以使用两种方式声明和定义函数:函数声明和函数表达式。 函数声明 函数声明是使用 function 关键字定义函数的方式。函数声明提升(Hoisting),这意味着可以在函数声明之前调用函数。因为在 JavaScript 中,函数声明会被提升到作用域的顶部或当前的函数中…

    JavaScript 2023年5月27日
    00
  • JavaScript函数节流概念与用法实例详解

    JavaScript函数节流概念与用法实例详解 函数节流概念 函数节流是一种优化高频率执行某个函数的方案,它能够将您预设的函数以固定的时间间隔执行,避免函数过于频繁的被执行。常用于一些高频触发事件如滚动条滚动、鼠标移动、窗口大小改变等。 如何实现函数节流 在Javascript中,当我们需要实现函数节流时,最简单的方式是通过返回一个闭包函数,内部使用 set…

    JavaScript 2023年5月27日
    00
  • js将列表组装成树结构的两种实现方式分享

    让我们来详细讲解“js将列表组装成树结构的两种实现方式分享”的完整攻略。 1. 背景 在开发网站时,经常会遇到需要将列表数据组装成树形结构的需求。比如,某个商品分类下有多个子分类,子分类又有自己的子分类,这就是一棵树形结构。如果我们只有一份列表数据,该如何将它组装成一棵树呢? 2. 实现方式一:递归 2.1 实现思路 递归是一种非常自然且直观的方法,它通过不…

    JavaScript 2023年5月27日
    00
  • js保存当前路径(cookies记录)

    要保存当前路径,可以使用浏览器的 cookies 功能。cookies 可以将一些数据保存在用户端,当用户再次访问网站时,网站可以获取 cookies 中保存的数据。因此,我们可以将当前路径存储在 cookies 中,以便用户下次访问时可以直接跳转到上次访问的路径。 下面是实现此功能的步骤: 1. 引入 js-cookie 库 我们可以使用 js-cooki…

    JavaScript 2023年6月11日
    00
  • js动态获取时间的方法分析

    让我为你详细讲解“js动态获取时间的方法分析”的完整攻略。 1. 时间获取的概述 在JavaScript中,获取时间的方法有很多,常见的有Date对象、moment.js等。其中,Date对象是最常用的时间获取方式,它可以获取当前时间或指定日期的时间,并对时间进行格式化处理。 2. 使用Date对象获取时间 Date对象获取时间非常简单,只需实例化该对象,即…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部