14
7

More than 5 years have passed since last update.

C#: 1次元セルオートマトン - ルール0からルール255まで全て試す

Last updated at Posted at 2018-11-19

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と呼ばれます。

このルールで作成される模様が、ある種の貝殻の表面にある模様と大変よく似ているらしいです。自然が作り出す模様が数学的なルールに基づいていると考えると、とても興味深いですね。

Rule30.png

ルール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次元セルオートマトン)で描けるというのは不思議です。

Rule90.png

つまり、このルールを変えることでいろんな図形を描くことができるわけです。ということで、ルール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以外で特徴的な図形をいくつかピックアップして掲載します。


ルール110

Rule110.png


ルール118

Rule118.png



ルール131

Rule131.png



ルール150

Rule150.png



ルール161

Rule161.png



ルール241

Rule241.png

14
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
7