JavaScript 实现生命游戏

yizhihongxing

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使用FileSystemObject对象写入文本文件内容的方法

    JavaScript的在浏览器端不能直接访问本地文件系统,但是可以通过ActiveXObject对象创建FileSystemObject对象来访问文件系统,可以使用FileSystemObject对象提供的方法进行文件读写操作。本文将详细讲解如何使用FileSystemObject对象写入文本文件内容的方法。 准备工作 在使用FileSystemObject…

    JavaScript 2023年5月27日
    00
  • 使用SWFObject完美解决HTML插入Flash的各浏览器兼容性方案

    使用SWFObject插入Flash可以通过JavaScript动态生成Flash对象,并通过检测当前浏览器是否支持HTML5的canvas元素,自动选择使用原生HTML5的canvas元素或者使用Flash来显示动画。这种方法可以解决HTML插入Flash的各浏览器兼容性问题,并且也可以提高网站的性能。 以下是使用SWFObject完美解决HTML插入Fl…

    JavaScript 2023年6月10日
    00
  • JavaScript实现点击图片换背景

    对于实现点击图片换背景的功能,我们可以通过以下步骤完成: 在HTML中添加需要更换背景的元素和切换背景用的按钮。 <body> <div id="content"> <h1>点击图片换背景</h1> <p>这是一个示例</p> <img id="bg-…

    JavaScript 2023年6月11日
    00
  • 黑客教你破解Session cookie的方法

    首先我们要明确,黑客破解Session Cookie是一种违法行为,严禁个人或组织进行类似活动。下面的内容仅供学术研究和了解安全防范的目的。 概述 “黑客教你破解Session Cookie的方法”是一种常见的网络攻击行为,通过获取合法用户的Session Cookie,黑客可以模拟合法用户进行各种操作,例如进行非法访问、窃取用户信息等等。让我们来了解黑客破…

    JavaScript 2023年6月11日
    00
  • JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】

    下面我将详细讲解“JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】”的完整攻略。 准备工作 在使用FileSaver.js之前,我们需要先在HTML页面中导入该插件: <script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSa…

    JavaScript 2023年5月19日
    00
  • Web 安全之Cookie劫持详细介绍

    Web 安全之 Cookie 劫持是指攻击者利用各种手段,窃取用户身份认证凭证 Cookie 值,进而获取被攻击者的用户身份信息和操作权限,从而进行一系列有害的攻击行为。下面将为大家介绍 Cookie 劫持的攻击方法和防御策略。 什么是 Cookie 劫持? 在 Web 开发中,服务器端通过 Set-Cookie 头信息发送给客户端浏览器,客户端浏览器存储该…

    JavaScript 2023年6月11日
    00
  • String字符串匹配javascript 正则表达式

    String字符串匹配javascript 正则表达式 什么是正则表达式 正则表达式是一种用来匹配、查找和替换文本的工具,它可以精确匹配一个或多个字符,也可以通过通配符匹配一类字符。在Javascript中,我们可以使用RegExp类来操作正则表达式。 正则表达式的基本语法 在 Javascript 中,正则表达式可以使用字面量或者RegExp类来创建。 使…

    JavaScript 2023年5月28日
    00
  • JavaScript实现单例模式实例分享

    下面是JavaScript实现单例模式的完整攻略。 一、什么是单例模式 单例模式是一种常见的设计模式,在整个系统中只有一个实例对象,可以节约系统资源,减少不必要的对象创建,同时也有助于控制对象的管理。在 JavaScript 中,单例模式一般有两种实现方式:闭包和 ES6 的 class 语法糖。 二、闭包实现单例模式 最常见的单例模式实现方式是使用闭包,将…

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