Skip to content

Commit c979793

Browse files
authored
Merge pull request #42 from ut-code/1-dimensional
コードテンプレート:1次元ライフゲームの追加
2 parents 69b3702 + 49d9fcc commit c979793

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
"use strict";
2+
3+
let generationFigure = 0;
4+
let currentRow = 0;
5+
6+
//盤面の大きさ
7+
const boardSize = 201; //奇数に設定する
8+
const cellSize = 450 / boardSize;
9+
const centerline = (boardSize - 1) / 2;
10+
11+
//セルの色
12+
const aliveCellColor = "black";
13+
const deadCellColor = "white";
14+
15+
//セルの生存条件(誕生条件)
16+
//今回は0から7までのパターンのうち 4, 3, 2, 1 が生存条件なので、2^4 + 2^3 + 2^2 + 2^1 = 30 から ルール30と呼ばれる。
17+
//他にルール184(7,5,4,3)や、ルール110(6,5,3,2,1)、ルール90(6,4,3,1)などが有名なので試してみましょう
18+
19+
// 生存パターン(2進法)を整数(10進法)で定義
20+
const aliveRules = new Set([4, 3, 2, 1]);
21+
function isNextAlive(left, center, right) {
22+
// ビットシフトで3つの数値を1つの整数にする
23+
// 例: 1, 0, 0 => (1<<2) | (0<<1) | 0 => 4
24+
const pattern = (left << 2) | (center << 1) | right;
25+
// セットに含まれているか確認(1 or 0 を返す)
26+
return aliveRules.has(pattern) ? 1 : 0;
27+
}
28+
29+
function getStyle(cell) {
30+
if (cell === 0) return deadCellColor;
31+
return aliveCellColor;
32+
}
33+
34+
let board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => 0));
35+
board[0][centerline] = 1; //最上段中央のセルだけ生きたセルに変更
36+
const table = document.getElementById("game-board");
37+
38+
function renderBoard() {
39+
document.body.style.display = "flex";
40+
document.body.style.justifyContent = "center";
41+
document.body.style.alignItems = "center";
42+
document.body.style.minHeight = "100vh";
43+
document.body.style.margin = "0";
44+
document.body.style.padding = "0";
45+
46+
table.innerHTML = "";
47+
for (let i = 0; i < boardSize; i++) {
48+
const tr = document.createElement("tr");
49+
tr.style.padding = "0";
50+
for (let j = 0; j < boardSize; j++) {
51+
const td = document.createElement("td");
52+
td.style.padding = "0";
53+
const button = document.createElement("button");
54+
button.style.backgroundColor = board[i][j] ? aliveCellColor : deadCellColor;
55+
if (boardSize >= 50) {
56+
button.style.border = "none";
57+
table.style.border = "1px solid black";
58+
} else {
59+
button.style.border = "0.5px solid black";
60+
}
61+
button.style.width = `${cellSize}px`;
62+
button.style.height = `${cellSize}px`;
63+
button.style.padding = "0";
64+
button.style.display = "block";
65+
td.appendChild(button);
66+
tr.appendChild(td);
67+
}
68+
table.appendChild(tr);
69+
}
70+
}
71+
72+
function rerender() {
73+
// 2回目以降の盤面生成は一行ずつ行う
74+
if (currentRow >= boardSize) return;
75+
for (let j = 0; j < boardSize; j++) {
76+
const button = table.children[currentRow].children[j].children[0];
77+
const currentCellColor = button.style.backgroundColor;
78+
const expectedCellColor = getStyle(board[currentRow][j]);
79+
if (currentCellColor !== expectedCellColor) {
80+
button.style.backgroundColor = expectedCellColor;
81+
}
82+
}
83+
}
84+
85+
renderBoard();
86+
87+
function generationChange(num) {
88+
generationFigure = num;
89+
window.parent.postMessage({ type: "generation_change", data: generationFigure }, "*");
90+
}
91+
92+
function progressBoard() {
93+
if (currentRow >= boardSize - 1) return;
94+
const newBoard = structuredClone(board);
95+
//セルの計算は一行ずつ行う
96+
for (let j = 1; j < boardSize - 1; j++) {
97+
const left = board[currentRow][j - 1];
98+
const center = board[currentRow][j];
99+
const right = board[currentRow][j + 1];
100+
newBoard[currentRow + 1][j] = isNextAlive(left, center, right);
101+
}
102+
board = newBoard;
103+
currentRow += 1;
104+
generationChange(generationFigure + 1);
105+
rerender();
106+
}
107+
108+
on.progress = () => {
109+
progressBoard();
110+
};
111+
112+
on.board_reset = () => {
113+
board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => 0));
114+
board[0][centerline] = 1; //初期状態のドットを再配置
115+
currentRow = 0; //行もリセット
116+
renderBoard();
117+
generationChange(0);
118+
};
119+
120+
on.board_randomize = () => {
121+
board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => 0));
122+
for (let j = 0; j < boardSize; j++) {
123+
board[0][j] = Math.random() > 0.5 ? 1 : 0; //最初の行をランダムにする
124+
}
125+
currentRow = 0;
126+
renderBoard();
127+
generationChange(0);
128+
};
129+
130+
on.save_board = async () => {
131+
window.parent.postMessage({ type: "save_board", data: board }, "*");
132+
};

src/lib/rules-explanation.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import lifespan from "$lib/assets/life-game-rules/lifespan.js?raw";
22
import probabilistics from "$lib/assets/life-game-rules/probabilistics.js?raw";
3+
import wolframcode from "$lib/assets/life-game-rules/wolframcode.js?raw";
34

45
export type RuleExplanation = {
56
name: {
@@ -35,4 +36,15 @@ export const rulesExplanation = {
3536
},
3637
code: probabilistics,
3738
},
39+
wolframcode: {
40+
name: {
41+
ja: "ウルフラム・コード",
42+
en: "Wolfram code",
43+
},
44+
description: {
45+
ja: "物理学者スティーブン・ウルフラムが考案した1次元のセルオートマトンです",
46+
en: "a one-dimensional cellular automaton created by physicist Stephen Wolfram",
47+
},
48+
code: wolframcode,
49+
},
3850
};

0 commit comments

Comments
 (0)