1.作ろうと思ったきっかけ
自分は最近AtCoderをやりすぎてjavascriptを全然やっていなくてjavascriptが読めなくなるかもしれなかったためjavascriptでなにか作ってみようと思いました。その時、youtubeを見ていたらライフゲームの動画が出てきたためライフゲームを作って見ようと思いました。
2.作り方
今回はCSSは全然書かないだろと思ってHTMLファイルにまとめました。javascriptは長くなりそうだったので別ファイルにしました。その結果HTMLとCSSは30行くらいで書けました。
2-1. HTML+CSSコードの解説
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ライフゲーム</title>
<style>
body{
background-color: black;
color: white;
}
.title{
color: green;
font-size: 60px;
line-height: 0;
text-align: center;
}
#canvas{
border: 5px solid white;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<h1 class="title">ライフゲーム</h1>
<p id="count_frame" style="text-align: center;"></p>
<canvas id="canvas" width="800" height="800"></canvas>
<script src="lifegame.js"></script>
</body>
</html>
だいたい自分の場合は背景色は黒で見出しは緑で書く傾向があります。
- count_frame
フレーム数を表示します
中の構造はjavascriptの解説で書きます - canvas
ライフゲームの盤面となります
2-2.javascriptコードの解説
// 定数定義層
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const dx = [1, 1, 0, -1, -1, -1, 0, 1];
const dy = [0, -1, -1, -1, 0, 1, 1, 1];
const cell_size = 40;
const canvas_size = canvas.width;
// クラス定義層
class Grid {
constructor(type = "random") {
this.cells = [];
const rows = canvas_size / cell_size;
const cols = canvas_size / cell_size;
for (let i = 0; i < rows; i++) {
this.cells[i] = [];
for (let j = 0; j < cols; j++) {
if (type === "random") {
this.cells[i][j] = Math.random() < 0.5;
} else {
this.cells[i][j] = false;
}
}
}
}
draw() {
ctx.clearRect(0, 0, canvas_size, canvas_size);
const rows = canvas_size / cell_size;
const cols = canvas_size / cell_size;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
ctx.fillStyle = this.cells[i][j] ? "green" : "black";
ctx.fillRect(j * cell_size, i * cell_size, cell_size, cell_size);
}
}
}
next() {
const rows = canvas_size / cell_size;
const cols = canvas_size / cell_size;
const newGrid = new Grid("empty");
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
let count = 0;
for (let k = 0; k < 8; k++) {
const ni = (i + dy[k] + rows) % rows;
const nj = (j + dx[k] + cols) % cols;
if (this.cells[ni][nj]) {
count++;
}
}
if (this.cells[i][j]) {
newGrid.cells[i][j] = (count === 2 || count === 3);
} else {
newGrid.cells[i][j] = (count === 3);
}
}
}
this.cells = newGrid.cells;
}
}
// 表示層
let frame = 0;
const grid = new Grid("random");
setInterval(() => {
grid.next();
grid.draw();
document.getElementById("count_frame").innerHTML = `フレーム数:${frame++}`;
}, 100);
- 定数定義層
定数を定義しています
dxやdyなど競技プログラミングのような表記が少しあります - Gridクラス
コンストラクタ: ランダムに初期状態を作ります
draw関数: canvasに表示します
next関数: つぎの盤面を作ります - 表示層
frame: count_frameにフレーム数を表示させるための変数です
grid: グリッドを作ります
setIntervalの中: 100ms毎に
- 次の盤面を作る
- 盤面を表示する
- count_frameのIDを取ってフレーム数を表示する
といった流れです
普通に見てて気持ちいいです。