ラングトンのアリをよりリッチにする.


以前の投稿でラングトンのアリについてまとめた.

今回はさらにプログラムを発展させて,アリの数を増やしてみた.

コードと実行結果は下記.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Langton's Ant シミュレーション(複数アリ版)
・グリッド上のセルは 0(ライトカラー)と 1(ダークカラー)の2状態
・各アリは、現在のセルが白の場合は右90°回転、黒の場合は左90°回転し、セルの色を反転して前進する
・3匹のアリが同時にシミュレーションを行い、アリごとに異なる色(例: 赤、緑、青)で描画される
・シミュレーションの様子を高品質な画像にキャプチャし、GIF ファイルとして出力する
"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import imageio
import os

def run_multi_ant_simulation(
    grid_size=300,         # グリッドのサイズ(セル数)
    num_steps=30000,       # シミュレーションの総ステップ数
    frame_interval=50,     # 何ステップごとにフレームをキャプチャするか
    fps=20,                # GIF のフレームレート
    output_filename="langtons_ant_multi.gif"
):
    # グリッド初期化(0: ライトセル、1: ダークセル)
    grid = np.zeros((grid_size, grid_size), dtype=np.uint8)

    # 複数のアリの初期設定(位置、向き、色)
    # ※各アリは辞書で管理し、"active" が True のときのみ更新される
    ants = [
        {"y": grid_size // 2,      "x": grid_size // 2,      "dir": 0, "color": "red",   "active": True},
        {"y": grid_size // 2,      "x": grid_size // 2 + 10, "dir": 1, "color": "green", "active": True},
        {"y": grid_size // 2 + 10, "x": grid_size // 2,      "dir": 2, "color": "blue",  "active": True},
    ]

    # 各方向への移動量(0: 上, 1: 右, 2: 下, 3: 左)
    dy = [-1, 0, 1, 0]
    dx = [0, 1, 0, -1]

    # キャプチャしたフレームを保存するリスト
    frames = []

    # カスタムカラーマップ(セルの表示色)
    cmap = ListedColormap(["#e0e0e0", "#333333"])

    # シミュレーションループ
    for step in range(num_steps):
        # 各アリについてルールに従って更新
        for ant in ants:
            if not ant["active"]:
                continue  # グリッド外に出たアリは更新しない

            y, x, d = ant["y"], ant["x"], ant["dir"]
            current_color = grid[y, x]

            if current_color == 0:
                # 白セルの場合:右90°回転、セルを黒に反転
                ant["dir"] = (d + 1) % 4
                grid[y, x] = 1
            else:
                # 黒セルの場合:左90°回転、セルを白に反転
                ant["dir"] = (d - 1) % 4
                grid[y, x] = 0

            # 新しい位置を計算
            new_y = y + dy[ant["dir"]]
            new_x = x + dx[ant["dir"]]

            # 境界チェック: グリッド外へ出た場合はアリを非アクティブにする
            if new_y < 0 or new_y >= grid_size or new_x < 0 or new_x >= grid_size:
                ant["active"] = False
            else:
                ant["y"] = new_y
                ant["x"] = new_x

        # すべてのアリが非アクティブになった場合、シミュレーションを終了
        if not any(ant["active"] for ant in ants):
            print(f"すべてのアリがグリッド外に出ました (step: {step})。シミュレーションを終了します。")
            break

        # 一定間隔でフレームをキャプチャ
        if step % frame_interval == 0:
            # 高品質な図を作成(背景色やレイアウトにこだわる)
            fig, ax = plt.subplots(figsize=(6, 6), dpi=100)
            fig.patch.set_facecolor('#f0f0f0')
            ax.set_facecolor('#f0f0f0')

            # グリッドの状態を描画
            ax.imshow(grid, cmap=cmap, interpolation='nearest')

            # 各アリの現在位置を、個別の色で描画
            for ant in ants:
                if ant["active"]:
                    ax.plot(ant["x"], ant["y"],
                            marker='o', color=ant["color"],
                            markersize=8, markeredgecolor='black',
                            markeredgewidth=1)

            # ステップ数を左上に注釈表示
            ax.text(0.02, 0.95, f"Step: {step}", transform=ax.transAxes,
                    color='blue', fontsize=12, fontweight='bold',
                    bbox=dict(facecolor='white', alpha=0.8, edgecolor='none'))

            # 軸は非表示
            ax.set_xticks([])
            ax.set_yticks([])

            plt.tight_layout()
            fig.canvas.draw()

            # キャンバスのRGBAバッファからRGB部分のみを抽出して画像に変換
            width, height = fig.canvas.get_width_height()
            image = np.frombuffer(fig.canvas.buffer_rgba(), dtype=np.uint8)
            image = image.reshape((height, width, 4))[:, :, :3]  # アルファチャンネルを除去

            frames.append(image)
            plt.close(fig)

    # キャプチャしたフレームを GIF として保存
    if frames:
        imageio.mimsave(output_filename, frames, fps=fps)
        print(f"GIFが正常に保存されました: {os.path.abspath(output_filename)}")
    else:
        print("キャプチャされたフレームがありません。GIFは作成されませんでした。")

if __name__ == '__main__':
    run_multi_ant_simulation()

参考文献

  • Langton, C. G. (1986). Studying artificial life with cellular automata. Physica D: nonlinear phenomena, 22(1-3), 120-149.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です