Files
hakorune/examples/game_of_life_canvas.hako

270 lines
7.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 🧬 Conway's Game of Life - Canvas版視覚化
// セルラーオートマトンの美しい可視化
print("🧬 === Conway's Game of Life - Canvas Edition ===")
DEBUG = new DebugBox()
DEBUG.startTracking()
// 🔬 セルBox - 各セルが独立した生命体
box CellBox {
init { alive, nextState, x, y }
CellBox(posX, posY, initialState) {
me.alive = initialState
me.nextState = false
me.x = posX
me.y = posY
}
setNextState(state) {
me.nextState = state
}
update() {
me.alive = me.nextState
}
isAlive() {
return me.alive
}
draw(canvas, cellSize) {
color = "black"
if me.alive {
color = "lime"
}
canvas.setFillStyle(color)
canvas.fillRect(me.x * cellSize, me.y * cellSize, cellSize, cellSize)
// グリッド線
canvas.setStrokeStyle("gray")
canvas.strokeRect(me.x * cellSize, me.y * cellSize, cellSize, cellSize)
}
}
// 🌍 Game of Life世界Box
box GameOfLifeBox {
init { grid, width, height, canvas, cellSize, generation }
GameOfLifeBox(canvasId, gridWidth, gridHeight, pixelCellSize) {
me.width = gridWidth
me.height = gridHeight
me.cellSize = pixelCellSize
me.generation = 0
// Canvas初期化
canvasWidth = gridWidth * pixelCellSize
canvasHeight = gridHeight * pixelCellSize
me.canvas = new WebCanvasBox(canvasId, canvasWidth, canvasHeight)
// グリッド初期化
me.grid = new ArrayBox()
y = 0
loop (y < me.height) {
row = new ArrayBox()
x = 0
loop (x < me.width) {
cell = new CellBox(x, y, false)
row.add(cell)
x = x + 1
}
me.grid.add(row)
y = y + 1
}
DEBUG.trackBox(me, "GameOfLifeWorld")
}
// 指定位置のセルを取得
getCell(x, y) {
if x >= 0 and x < me.width and y >= 0 and y < me.height {
row = me.grid.get(y)
return row.get(x)
}
return new CellBox(-1, -1, false) // 境界外は死んだセル
}
// 近傍の生きているセル数をカウント
countLiveNeighbors(x, y) {
count = 0
// 8近傍をチェック
dy = -1
loop (dy <= 1) {
dx = -1
loop (dx <= 1) {
if not (dx == 0 and dy == 0) { // 自分自身は除外
neighbor = me.getCell(x + dx, y + dy)
if neighbor.isAlive() {
count = count + 1
}
}
dx = dx + 1
}
dy = dy + 1
}
return count
}
// Conway's Game of Lifeルールの適用
applyRules() {
// 次世代の状態を計算
y = 0
loop (y < me.height) {
x = 0
loop (x < me.width) {
cell = me.getCell(x, y)
liveNeighbors = me.countLiveNeighbors(x, y)
newState = false
if cell.isAlive() {
// 生きているセルのルール
if liveNeighbors == 2 or liveNeighbors == 3 {
newState = true // 生存
}
// それ以外は死滅(過疎・過密)
} else {
// 死んでいるセルのルール
if liveNeighbors == 3 {
newState = true // 誕生
}
}
cell.setNextState(newState)
x = x + 1
}
y = y + 1
}
// 状態を一斉更新
y = 0
loop (y < me.height) {
x = 0
loop (x < me.width) {
cell = me.getCell(x, y)
cell.update()
x = x + 1
}
y = y + 1
}
me.generation = me.generation + 1
}
// パターン設定
setPattern(pattern) {
if pattern == "glider" {
// グライダーパターン
me.getCell(1, 0).alive = true
me.getCell(2, 1).alive = true
me.getCell(0, 2).alive = true
me.getCell(1, 2).alive = true
me.getCell(2, 2).alive = true
}
if pattern == "blinker" {
// 点滅パターン
centerX = me.width / 2
centerY = me.height / 2
me.getCell(centerX - 1, centerY).alive = true
me.getCell(centerX, centerY).alive = true
me.getCell(centerX + 1, centerY).alive = true
}
if pattern == "random" {
// ランダムパターン
random = new RandomBox()
y = 0
loop (y < me.height) {
x = 0
loop (x < me.width) {
if random.float() < 0.3 { // 30%の確率で生存
me.getCell(x, y).alive = true
}
x = x + 1
}
y = y + 1
}
}
}
// 描画
render() {
// 背景クリア
me.canvas.setFillStyle("white")
me.canvas.fillRect(0, 0, me.canvas.width, me.canvas.height)
// 全セル描画
y = 0
loop (y < me.height) {
x = 0
loop (x < me.width) {
cell = me.getCell(x, y)
cell.draw(me.canvas, me.cellSize)
x = x + 1
}
y = y + 1
}
// 情報表示
me.canvas.setFillStyle("blue")
me.canvas.fillText("Generation: " + me.generation, 10, 20)
me.canvas.fillText("Conway's Game of Life", 10, 40)
}
// 生きているセルの総数
countAliveCells() {
count = 0
y = 0
loop (y < me.height) {
x = 0
loop (x < me.width) {
if me.getCell(x, y).isAlive() {
count = count + 1
}
x = x + 1
}
y = y + 1
}
return count
}
}
// 🚀 Game of Life開始
print("Creating Conway's Game of Life world...")
game = new GameOfLifeBox("life-canvas", 40, 30, 10)
// パターン設定
print("🧬 Setting up initial patterns...")
game.setPattern("random")
// シミュレーション実行
print("🌱 Running life simulation...")
generation = 0
loop (generation < 50) {
game.render()
aliveCount = game.countAliveCells()
if generation % 10 == 0 {
print("Generation " + generation + ": " + aliveCount + " cells alive")
}
game.applyRules()
generation = generation + 1
}
// 最終統計
finalAlive = game.countAliveCells()
print("🏁 Simulation complete!")
print("Final generation: " + game.generation)
print("Final alive cells: " + finalAlive)
print(DEBUG.memoryReport())
print("✨ Conway's Game of Life - Everything is Box!")
print("🔬 Each cell is an independent CellBox")
print("🌍 The world itself is a GameOfLifeBox")
print("🎨 Beautiful visualization through WebCanvasBox")