はじめに
初投稿です。
古来より伝わる「ライフゲーム」をモダンな言語で実装するチャレンジやってみます。
最初は自分の得意なSwift言語でやっていきます。
開発環境
- MacStudio2023(M2 Max)
- macOS Tahoe(26.1)
- Swift Playground(4.6.4)
ライフゲームとは
概要は先駆者様の解説に委ねます。
コーディングに必要なルールは以下となります。
- 2次元グリッド上で展開され、各セルは「生」または「死」の2つの状態を持つ。
- 各世代で、「隣接(上下左右と斜め4方向の計8方向にある)」セルを以下のルールに従って状態が更新される。
- 誕生:死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代で誕生する。
- 生存:生きているセルに隣接する生きたセルが2つまたは3つならば、次の世代でも生存する。
- 過疎:生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。
- 過密::生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。
- 端は常に死んでいるとみなす(固定境界)
各コードについて
セル部分
class Cell {
let x: Int
let y: Int
var isAlive: Bool
// 隣接セルのリスト
var neighborCells: [Cell]
init(x: Int, y: Int, isAlive: Bool = false) {
self.x = x
self.y = y
self.isAlive = isAlive
self.neighborCells = []
}
/// 近接情報の登録
func setNeighborCells(cells: [Cell]) {
// 1. 自分自身ではない=座標が完全一致しない
// 2. 相手との横座標の距離が1以下
// 3. 相手との縦座標の距離が1以下
self.neighborCells = cells.filter { !($0.x == self.x && $0.y == self.y) && abs($0.x - self.x) <= 1 && abs($0.y - self.y) <= 1 }
}
/// 近接の生存数を返す
func countSurvivors() -> Int {
var result = 0
self.neighborCells.map { result += $0.isAlive ? 1 :0 }
return result
}
/// 次の世代での生存状態を返す
func getNextDeadOrAlive(survivorCount: Int) -> Bool {
if self.isAlive {
// 過疎: 生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する
// 過密: 生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する
return (survivorCount <= 1 || survivorCount >= 4 ? false : true)
// 生存: 生きているセルに隣接する生きたセルが2つまたは3つならば、次の世代でも生存する
}
// 誕生: 死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代で誕生する
return (survivorCount == 3 ? true : false)
}
}
モダンっぽい(個人感)部分
- オブジェクト指向ライクに「Cell」クラスで1つのセルの状態を管理
- 配列操作を「map」「filter」で実装=if文を極力減らす
- セルの情報に「隣接しているセルの一覧」を登録できるようにする(ルール上「セルの状態変化は『生死』のみで、位置情報は変化しない」ため実装可能)
- 「近接の生存数」「次の世代での自身の生存状態」をセル自身で判定
ゲームコントローラー部分
class LifeGameController {
private(set) var cells: [Cell]
let width: Int
let height: Int
/// コンストラクタ
init(width: Int, height: Int) {
self.width = width
self.height = height
// セル生成
self.cells = []
for y in 0..<height {
for x in 0..<width {
self.cells.append(Cell(x: x, y: y))
}
}
// 近接情報の登録
self.cells.map { $0.setNeighborCells(cells: self.cells) }
}
/// 生存セルを決定
func setAlivedCell(index: Int) {
guard index < self.cells.count else { return }
let cell = self.cells[index]
cell.isAlive = true
}
func setAlivedCell(x: Int, y: Int) {
let index = y * self.width + x
self.setAlivedCell(index: index)
}
/// 世代更新
func updateGeneration() {
// 次の世代の状態を保持する配列
var nextGenALives: [Bool] = []
// インデックスでループ
for index in 0..<self.cells.count {
let nowCell = self.cells[index]
// 生きている近傍の数をカウントする
let aliveCount = nowCell.countSurvivors()
// 次世代の生存状態更新
let isAlive = nowCell.getNextDeadOrAlive(survivorCount: aliveCount)
nextGenALives.append(isAlive)
}
// 現在のセルの生存状態を更新
for (index,cell) in self.cells.enumerated() {
cell.isAlive = nextGenALives[index]
}
}
/// 現在のグリッドの状態を出力する
func printGrid(isNumber: Bool = false) {
print("---------")
var firstIndex: Int = 0
for y in 0..<self.height {
let lastIndex = firstIndex + self.width - 1
var rowString = ""
if isNumber {
// 隣接するセルの生存数を表示
rowString = self.cells[firstIndex...lastIndex].map {
"\($0.neighborCells.filter{ $0.isAlive }.count)"
}.joined(separator: " ")
} else {
rowString = self.cells[firstIndex...lastIndex].map { $0.isAlive ? "■" : "□" }.joined(separator: " ")
}
print(rowString)
firstIndex += self.width
}
}
}
モダンっぽい(個人感)部分
- オブジェクト指向ライクに「LifeGameController」クラスで1ゲームのコントロールを管理
- セルオブジェクト自身は更新せずに生存状態のみを更新する
- 出力処理にデバッグ用(隣接するセルの生存数を出力)が選択できる
ゲーム実行部分
ゲームコントローラー生成
// ワールドのサイズを決定
let world_width = 20
let world_height = 16
let gameController = LifeGameController(width: world_width, height: world_height)
初期状態の設定
// 初期パターン設定
// 疑似乱数による決定の例
for index in 0..<(world_width * world_height) {
if index % 3 == 0 || index % 7 == 0 {
gameController.setAlivedCell(index: index)
}
}
// 座標直接指定の例
gameController.setAlivedCell(x: 8, y: 6)
gameController.setAlivedCell(x: 8, y: 7)
gameController.setAlivedCell(x: 9, y: 6)
gameController.setAlivedCell(x: 9, y: 7)
gameController.setAlivedCell(x: 10, y: 6)
gameController.setAlivedCell(x: 10, y: 7)
初期状態の配置を出力
print("初期状態 (世代 0)")
gameController.printGrid()
有限世代までゲーム実施と出力
// 有限世代シミュレーションを実行
let last_generation = 10
for generation in 1...last_generation {
gameController.updateGeneration()
print("\n 世代 \(generation)")
gameController.printGrid()
}
実行結果例
セル1つのみ
初期状態 (世代 0)
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 1
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
セル2×2
初期状態 (世代 0)
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 1
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 2
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 3
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
※以下変化無し
セル3×3
初期状態 (世代 0)
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 1
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ □ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ □ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ □ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 2
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ ■ □ ■ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 3
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ □ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ □ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ □ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 4
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ ■ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ ■ ■ ■ □ ■ ■ ■ □ □ □ □ □ □
□ □ □ □ □ □ □ ■ □ ■ □ ■ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 5
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 6
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ ■ ■ ■ □ □ □ ■ ■ ■ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 7
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 8
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ ■ ■ ■ □ □ □ ■ ■ ■ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 9
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ ■ □ □ □ □ □ ■ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ ■ ■ ■ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
世代 10
---------
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ ■ ■ ■ □ □ □ ■ ■ ■ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ ■ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □
実行して判った事
- 初期化に時間がかかっている、レトロな書き方(世代ごとに毎回ゲームアルゴリズムを実行する)方が全体として時間短縮する可能性が高い
- それはさておき、言語学習の題材として有用だと思われる
- 結果が可視化できる
- 少ない条件で無数の結果を試すことができる
今後の展開予定
- UIKitかSKSceneを用いてリアルタイム進行で出力
- Xcodeプロジェクトとしてアプリケーション化
- 他の言語でのチャレンジ
あとがき
記事を書くまでの経緯
- 脳科学者の茂木健一郎氏が自身のYouTubeチャンネルで「ライフゲーム(game of life)と、生命の起源」という動画で語っているのを視聴
- そのとき自分が35年前(!)に初めて購入したPCであるMSX2+マシンで初めて組んだプログラムが専門書籍に載っていたライフゲームの(行番号必須な方の)BASICプログラムだった事を思い出した
- 現在の自分は言葉通りの「独立」状態だったので、35年の沈黙(?)を破って今の技術で集中して再チャレンジしたくなった
- 今ならただ組むだけではなく技術公開するほうがモチベーションが維持できると思い、投稿を前提に進めようと思った
おわりに
ここまで読んでいただきありがとうございます。
今後も思いつくままに記事投稿を続けて行きたい所存であります。
以後、お見知り置きを。