Wikipedia「セル・オートマトン」の記事を参考にして、1次元セルオートマトンのルール0からルール255までの全256パターンを描くプログラムを作成してみました。
このなかでは、「ルール30」と「ルール90」が有名ですね。
ルール30のセルオートマトンとは
ある時刻 t+1の中央のセル状態は、時刻 t の 左、中央、右の3つのセルの状態で決定されます。
そのルールを以下に示します。
時刻 t 時刻 t+1
111 → 0
110 → 0
101 → 0
100 → 1
011 → 1
010 → 1
001 → 1
000 → 0
時刻 t の値を並べると 0001110 となり、10進数で 30 となることから、ルール30と呼ばれます。
このルールで作成される模様が、ある種の貝殻の表面にある模様と大変よく似ているらしいです。自然が作り出す模様が数学的なルールに基づいていると考えると、とても興味深いですね。
ルール90のセルオートマトンとは
ルール30で示した規則をルール90のものに置き換えると、典型的なフラクタル図形であるシェルピンスキーのギャスケットが現れます。
そのルール90を以下に示します。
時刻 t 時刻 t+1
111 → 0
110 → 1
101 → 0
100 → 1
011 → 1
010 → 0
001 → 1
000 → 0
時刻 t の値を並べると 01011010 となり、10進数で 90 となることから、ルール90と呼ばれています。
通常のフラクタル図形を描く方法とは全く別の方法(1次元セルオートマトン)で描けるというのは不思議です。
つまり、このルールを変えることでいろんな図形を描くことができるわけです。ということで、ルール0からルール255までの全256パターンを描くプログラムを作成してみました。ルール番号を与えると、対応するルールを作成するようにしていますが、詳しくは後述のコードをみてください。
NGraphicパッケージ
以前このようなプログラムを作成した時は、Silverlightで作成したのですが、もう死んでしまったテクノロージーなので、今回は、コンソールアプリケーションとして作成し、PNGファイルとしてセルオートマトンを描画し出力することにします。
PNGファイルの作成には、NGraphicパッケージを使っています。.NET Core版のNGraphicパッケージで動かそうとしたのですが、どうもコンソールアプリでは無理みたいなので、.NET Framework版のNGraphicパッケージを利用しています。
NGraphicパッケージを隠蔽するEasyCanvasクラスを定義
まずは、EasyCanvasクラスを定義します。
このクラスは、NGraphicパッケージの機能をこの中に隠蔽するためのものです。
SVGにも書き出せればいいなと思ったのでこうしています。まあ、そうなったら、インターフェース定義して云々かんぬんやらないといけないのですが、まあそれは本当に必要になった時にやろうと思います。
必要なのは、点を打つ機能とファイルに出力する機能だけなので、SetPixelメソッドとWriteメソッドを定義しています。
using NGraphics;
namespace Cellautomaton {
class EasyCanvas {
private IImageCanvas canvas;
static EasyCanvas() {
// .NET Coreのパッケージの場合は、このコードが必要?
//Platforms.SetPlatform<SystemDrawingPlatform>();
}
public EasyCanvas(int width, int height) {
canvas = Platforms.Current.CreateImageCanvas(new Size(width, height), scale: 2);
}
public void SetPixel(int x, int y, SolidBrush brush) {
canvas.FillRectangle(x, y, 1, 1, brush);
}
public void Write(string path) {
canvas.GetImage().SaveAsPng(path);
}
}
}
1次元セルオートマトンを実現するCellularAutomatonクラスを定義
このEasyCanvasを使って、1次元セルオートマトンを実現するクラスCellularAutomatonを定義します。
なお、Ruleの数値はコンストラクタで与えられるようにしています。
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Cellautomaton {
class CellularAutomaton {
private bool[] _cells;
private Dictionary<string, bool> _rule;
public CellularAutomaton(int rule, int width) {
_cells = new bool[width];
_cells[width / 2] = true;
_rule = MakeRule(rule);
}
// ルール番号からルールを作成
private Dictionary<string, bool> MakeRule(int rule) {
var list = new[] {
"111", "110", "101", "100", "011", "010", "001", "000"
};
return list.Reverse().Select(k => {
var b = (rule & 0x01) == 0x01;
rule = rule >> 1;
return new { Key = k, Value = b };
}).ToDictionary(p => p.Key, p => p.Value);
}
// すべての世代を列挙する。永遠に列挙するので注意。
public IEnumerable<bool[]> AllGenerations() {
yield return _cells;
while (true) {
List<bool> area = new List<bool>();
foreach (var la in GetAdjoints()) {
area.Add(_rule[LocalAreaToString(la)]);
}
_cells = area.ToArray();
yield return _cells;
}
}
// 3つのセルを文字列に変換
string LocalAreaToString(bool[] area) {
string s = "";
foreach (var a in area) {
s += a == true ? "1" : "0";
}
return s;
}
// 隣接した3つのセルを配列として順に取り出す。
IEnumerable<bool[]> GetAdjoints() {
bool[] area = new bool[3];
for (int i = 0; i < _cells.Length; i++) {
area[0] = (i == 0) ? false : _cells[i - 1];
area[1] = _cells[i];
area[2] = (i == _cells.Length - 1) ? false : _cells[i + 1];
yield return area;
}
}
}
}
Programクラスを定義
そして最後は、Programクラスです。
CellularAutomatonクラスを使ってルール0からルール255までのセルオートマトンを作成しています。
using NGraphics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Cellautomaton {
class Program {
static void Main(string[] args) {
for (int i = 0; i < 256; i++) {
int rule = i;
int generations = 180;
int width = generations * 2;
var ca = new CellularAutomaton(rule, width);
var lines = ca.AllGenerations().Take(generations);
MakeImage(rule, lines, width);
}
}
static void MakeImage(int rule, IEnumerable<bool[]> lines, int width) {
var canvas = new EasyCanvas(width, width / 2 + 10);
int y = 10;
foreach (var line in lines) {
for (int x = 0; x < width; x++) {
if (line[x])
canvas.SetPixel(x, y, Brushes.DarkGray);
}
y++;
}
canvas.Write($"Rule{rule}.png");
}
}
}
このコードを実行すれば、Rule0.pngからRule255.pngまでの256個の画像ファイルが作成できます。
ソースコードはGitHubでも公開しています。
結果
ルール30とルール90以外で特徴的な図形をいくつかピックアップして掲載します。