一次元セルオートマトン


## セルオートマトンとは
[wikipedia](https://ja.wikipedia.org/wiki/セル・オートマトン)

wikiが充実してるのでそちらを。

単純なコードで目に楽しい出力です。
ちなみに二次元セルオートマトンはライフゲームという名で有名ですね。

## Rubyで
やってみます。

### make_all_pattern
一次元の場合パターンが256しかないので、力任せに全てのパターンを生成します。
８重forという酷いコード。

```ruby
class Cells
  attr :table, :cells

  def initialize
    @cells = [1]
    @table = make_all_patterns
  end

  def make_all_patterns
    cs = [0,1]
    ops = []
    ips = []
    ps = [] 

    for i1 in cs
      for i2 in cs
        for i3 in cs
          ips.push [i1,i2,i3]
        end
      end
    end

    for o1 in cs
      for o2 in cs
        for o3 in cs
          for o4 in cs
            for o5 in cs
              for o6 in cs
                for o7 in cs
                  for o8 in cs
                    os = [o1,o2,o3,o4,o5,o6,o7,o8]
                    n = os.map { |o| o.to_s }.reduce(:+).to_i(2)
                    ops[n] = os
                  end
                end
              end
            end
          end
        end
      end
    end

    ops.each_with_index { |os,n|
      ps[n] = {}
      for o,i in os.reverse.zip ips
        ps[n][i] = o 
      end
    }

    ps
  end
```

### apply
各セルにパターンを適応します。
両端に一つずつセルを追加して成長させ、
周囲のセルの状態と自分の状態で次の状態をパターンによって決めていきます。
パターンマッチはただのHashでできてしまいました。Rubyすごい。

```ruby
  def apply pn
    pt = @table[pn]    
    s = @cells.size
    f = -> i { (i < 0 || i >= s) ? 0 : @cells[i] }
    newCells = []
    for i in -1 .. s
      cs = [f.call(i-1), f.call(i), f.call(i+1)]
      newCells.push(pt[cs])
    end 
    @cells = newCells
  end
```

### show
パターンとセルを見やすく。

```ruby
  def show_cells
    #@cells.map { |c| c == 1 ? "O" : " " }.join
    @cells.join
  end

  def show_table pn
    "[#{pn}] " + 
      @table[pn].keys.map { |k| "#{k.join} = #{@table[pn][k]}" }.join(", ")
  end
```

### run
ビジュアライズ。
runの引数は0から255までで。
ターミナルの幅と高さに合わせて表示。
表示が終わったところで@cellsを初期化しておきます。

```ruby
  require "io/console"
  def run pn
    raise "expected arg in 0..255" unless pn < 256
    puts show_table pn
    rs, cs = IO.console.winsize
    (rs - 2).times  {
      puts show_cells.center(cs)
      apply pn
    }
    @cells = [1]
  end
end
```

### main
折角なので全パターン実行。
newで全パターン生成してるのでuptoの外に。
sleepで目で追える程度に調整。

```ruby
cs = Cells.new
0.upto(255) { |n| 
  cs.run(n)
  sleep 0.3
}
```

#### ルール90
こんな感じで表示されます。

[90] 000 = 0, 001 = 1, 010 = 0, 011 = 1, 100 = 1, 101 = 0, 110 = 1, 111 = 0

>                                              1                                                
>                                             101                                               
>                                            10001                                              
>                                           1010101                                             
>                                          100000001                                            
>                                         10100000101                                           
>                                        1000100010001                                          
>                                       101010101010101                                         
>                                      10000000000000001                                        
>                                     1010000000000000101                                       
>                                    100010000000000010001                                      
>                                   10101010000000001010101                                     
>                                  1000000010000000100000001                                    
>                                 101000001010000010100000101                                   
>                                10001000100010001000100010001                                  
>                               1010101010101010101010101010101                                 
>                              100000000000000000000000000000001                                
>                             10100000000000000000000000000000101                               
>                            1000100000000000000000000000000010001                              
>                           101010100000000000000000000000001010101                             
>                          10000000100000000000000000000000100000001                            
>                         1010000010100000000000000000000010100000101                           
>                        100010001000100000000000000000001000100010001                          
>                       10101010101010100000000000000000101010101010101                         
>                      1000000000000000100000000000000010000000000000001                        
>                     101000000000000010100000000000001010000000000000101                       
>                    10001000000000001000100000000000100010000000000010001                      
>                   1010101000000000101010100000000010101010000000001010101                     
>                  100000001000000010000000100000001000000010000000100000001                    
>                 10100000101000001010000010100000101000001010000010100000101                   
>                1000100010001000100010001000100010001000100010001000100010001                  
>               101010101010101010101010101010101010101010101010101010101010101                 

## 終
make_all_patternsの８重forがダサいですが、
パターンマッチがHashで済んでしまう所はクールでした。
簡単ながらそこそこ作り甲斐があるので新しい言語覚える時は、
hello,worldの代わりに書いたりしてます。