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技术站