资讯专栏INFORMATION COLUMN

康威生命游戏的简单实现

ccj659 / 3721人阅读

摘要:生命游戏,数学家发明的一个游戏,又称康威生命演化,生命棋,细胞自动机。康威有许多好玩有趣的发明,最广为人知的一个是外观数列,这里不多说,另一个就是生命游戏。生命游戏模拟的是二维平面上生命的演化过程。

生命游戏,数学家 John Conway 发明的一个游戏,又称康威生命演化,生命棋,细胞自动机。

康威有许多好玩有趣的发明,最广为人知的一个是外观数列(Look-and-Say),这里不多说,另一个就是生命游戏(Game-of-Life)。

关于康威,摘录一段 Wikipedia 的叙述:

約翰·何頓·康威(John Horton Conway,1937年12月26日-),生於英國利物浦,數學家,活躍於有限群的研究、趣味數學、紐結理論、數論、組合博弈論和編碼學等範疇。
康威年少時就對數學很有強烈的興趣:四歲時,其母發現他背誦二的次方;十一歲時,升讀中學的面試,被問及他成長後想幹甚麼,他回答想在劍橋當數學家。後來康威果然於劍橋大學修讀數學,現時為普林斯頓大學的教授。

生命游戏模拟的是二维平面上生命的演化过程。

规则很简单:每个细胞有两种状态--存活或死亡,每个细胞与以自身为中心的周围八格细胞产生互动。

如果一个活细胞周围有2至3个活细胞,在下一个阶段继续存活,否则死亡;

如果一个死细胞周围有3个活细胞,在下一个阶段将变成活细胞,否则继续保持死亡

康威生命游戏是简单规则产生复杂变化的典型例子。在演变过程中,可以看到一些非常美妙的变化,和一些优美的几何图形。

下面是用 HTML5 Canvas 实现的一个简单版本

源码:https://github.com/mirreal/moon9/tree/master/GameOfLife

DEMO:http://mirreal.net/game-of-life/

JS代码如下:

function Game() {
  this.stones = [];
  this.canvas = new Canvas();

  this.init();
}

Game.prototype.init = function() {
  var self = this;

  this.createRandomStones();
  this.draw();

  this.getAroundStones();

  this.eventHandler();
  
  this.loop = setInterval(function() {
    self.update();
    self.draw();
  }, 120);
};

Game.prototype.eventHandler = function() {
  var self = this;

  var snapshotButton = document.getElementById("snapshotButton"),
      snapshotImageElement = document.getElementById("snapshotImageElement"),
      canvas = document.getElementById("canvas");

  snapshotButton.onclick = function(event) {
    event.preventDefault();

    if (snapshotButton.innerHTML == "Snapshot") {
      clearInterval(self.loop);
      var dataUrl = canvas.toDataURL();
      snapshotImageElement.src = dataUrl;
      snapshotImageElement.style.display = "inline";
      canvas.style.display = "none";
      snapshotButton.innerHTML = "Continue";
    } else {
      self.loop = setInterval(function() {
        self.update();
        self.draw();
      }, 800);
      canvas.style.display = "inline";
      snapshotImageElement.style.display = "none";
      snapshotButton.innerHTML = "Snapshot";
    }
  };
};

Game.prototype.createRandomStones = function() {
  for (var i = 0; i < 32; i++) {
    for (var j = 0; j < 32; j++) {
      var status = Math.random() < 0.2 ? true : false;
      this.stones.push(new Stone({x: i, y: j}, status))
    }
  }
};

Game.prototype.draw = function() {
  var self = this;

  this.canvas.drawGrid("lightgrey", 20, 20);
  this.stones.forEach(function(stone) {
    if (stone.status === true) {
      self.canvas.drawStone(stone);
    }
  });
};

Game.prototype.getAroundStones = function() {
  var self = this;

  this.stones.forEach(function(stone) {
    stone.around.forEach(function(position) {
      stone.aroundStones.push(self.stones[32*position.x + position.y]);
    });
  });
};

Game.prototype.update = function() {
  var self = this;

  this.stones.forEach(function(stone) {
    stone.aroundStones.forEach(function(s) {
      if (s.status === true) stone.aliveCount += 1;
    });

    if (stone.status === true) {
      if (stone.aliveCount === 2 || stone.aliveCount === 3) {
        stone.nextStatus = true;
      } else {
        stone.nextStatus = false;
      }
    } else {
      if (stone.aliveCount === 3) stone.nextStatus = true;
      else stone.nextStatus = false;
    }
  });

  this.stones.forEach(function(stone) {
    stone.status = stone.nextStatus;
    stone.aliveCount = 0;
  });
}




function Stone(position, status) {
  this.x = position.x;
  this.y = position.y;

  this.status = status;
  this.nextStatus = false;

  this.aroundStones = [];
  this.aliveCount = 0;

  this.around = [];
  this.getAround();
}

Stone.prototype.getAround = function() {
  for (var i = this.x-1; i <= this.x+1; i++) {
    for (var j = this.y-1; j <= this.y+1; j++) {
      if (i == this.x && j == this.y) continue;
      if (i < 0 || i >= 32) continue;
      if (j < 0 || j >= 32) continue;
      this.around.push({x: i, y: j});
    }
  }
};


function Canvas() {
  this.canvas = document.getElementById("canvas");
  this.context = canvas.getContext("2d");
}

Canvas.prototype.drawGrid = function(color, stepx, stepy) {
  var canvas = this.canvas;
  var ctx = this.context;

  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.save();
  ctx.strokeStyle = color;
  ctx.lineWidth = 0.5;

  for (var i = stepx + 0.5; i < ctx.canvas.width; i += stepx) {
    ctx.beginPath();
    ctx.moveTo(i, 0);
    ctx.lineTo(i, ctx.canvas.height);
    ctx.stroke();
    ctx.closePath();
  }
  
  for (var i = stepy + 0.5; i < ctx.canvas.height; i += stepy) {
    ctx.beginPath();
    ctx.moveTo(0, i);
    ctx.lineTo(ctx.canvas.width, i);
    ctx.stroke();
    ctx.closePath();
  }
  ctx.restore();
};

Canvas.prototype.drawStone = function(stone) {
  var ctx = this.context;

  var x = 20 * stone.x + 10;
  var y = 20 * stone.y + 10;

  ctx.fillStyle = "orange";
  ctx.beginPath();
  ctx.arc(x, y, 9, 0, Math.PI*2, false);
  ctx.closePath();
  ctx.fill();
};

new Game();

TIPS:

在Google搜索 Conway"s Game of Life ,会看到Google的一个实现。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85293.html

相关文章

  • 简单好玩】细胞自动机小游戏

    摘要:当前细胞为存活状态时,当周围有个以上的存活细胞时,该细胞变成死亡状态。康威生命游戏的自由有了核心的算法游戏规则,康威生命就是一个具有生命的自由游戏。文件导出导入当然加了扩展功能,保存自己喜欢的细胞自动机成文件。 细胞自动机 备注:文末有自己用Javascript简单实现的网页版细胞自动机(还挺好玩) 什么是细胞自动机 showImg(https://segmentfault.com/i...

    yagami 评论0 收藏0
  • 网易容器云平台微服务化实践(一)

    摘要:本文是网易容器云平台的微服务化实践系列文章的第一篇。网易容器云平台的前身是网易应用自动部署平台,它能够利用云提供的基础设施,实现包括构建和部署一体化在内的整个应用生命周期管理。目前网易云容器服务团队以的方式管理着微服务,每周构建部署次数。 此文已由作者冯常健授权网易云社区发布。 欢迎访问网易云社区,了解更多网易技术产品运营经验。 摘要:网易云容器平台期望能给实施了微服务架构的团队提供完...

    zhjx922 评论0 收藏0
  • FCC 成都社区·前端周刊 第 10 期

    摘要:正式发布在过去的一周,正式发布,带来大量改进和修复。这是自开展以来的第七个主要版本,并将在年月成为下一个分支。以后,如果使用具有已知安全问题的代码,的用户会收到警告通知。将自动检查针对数据库的安装请求,并在代码包含漏洞时发出警告通知。 1. Node.js 10 正式发布 在过去的一周,Node.js 10.0.0 正式发布,带来大量改进和修复。这是自 Node.js Foundati...

    BigNerdCoding 评论0 收藏0
  • FCC 成都社区·前端周刊 第 10 期

    摘要:正式发布在过去的一周,正式发布,带来大量改进和修复。这是自开展以来的第七个主要版本,并将在年月成为下一个分支。以后,如果使用具有已知安全问题的代码,的用户会收到警告通知。将自动检查针对数据库的安装请求,并在代码包含漏洞时发出警告通知。 1. Node.js 10 正式发布 在过去的一周,Node.js 10.0.0 正式发布,带来大量改进和修复。这是自 Node.js Foundati...

    li21 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<