# \[QUIZ\] Cellular Automata (#134)

**URL:** <https://rubytalk.org/t/quiz-cellular-automata-134/39806>\
**Category:** ruby-talk\
**Created:** [10 August 2007 12:53 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806 "2007-08-10T12:53:52Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![James\_Edward\_Gray\_II](https://avatars.discourse-cdn.com/v4/letter/j/ea5d25/32.png) [@James\_Edward\_Gray\_II](https://rubytalk.org/u/James_Edward_Gray_II)\
**Post date:** [10 August 2007 12:53 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/1 "2007-08-10T12:53:52Z")

</div>

The three rules of Ruby Quiz:

1. Please do not post any solutions or spoiler discussion for this quiz until  
48 hours have passed from the time on this message.

2. Support Ruby Quiz by submitting ideas as often as you can:

[http://www.rubyquiz.com/](http://www.rubyquiz.com/)

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone  
on Ruby Talk follow the discussion. Please reply to the original quiz message,  
if you can.

> **···**
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> 
> Most of us have probably heard of Conway's Game of Life, but there are other  
> cellular automata that are equally interesting. In fact, there is a group of  
> 256 one-dimensional cellular automata that are quite easy to simulate but still  
> fun to observe.
> 
> To simulate these elementary cellular automata, you first need to construct a  
> rule table. This table is a description of the changes that happen in each  
> discreet step of time. Here's the table for the "rule 30" automaton:
> 
> &nbsp;&nbsp;+-----------------------------------------------------------------+  
> &nbsp;&nbsp;\> Neighborhood | 111 | 110 | 101 | 100 | 011 | 010 | 001 | 000 |  
> &nbsp;&nbsp;+-----------------------------------------------------------------+  
> &nbsp;&nbsp;\> New Center Cell | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |  
> &nbsp;&nbsp;+-----------------------------------------------------------------+
> 
> The first row is the same for this whole family of automata. It represents the  
> "neighborhood" of the cell currently being examined, which includes the cell  
> itself and one cell to either side of it. The current values of those cells,  
> ones being on and zeros being off, can be used to determine the new value for  
> this cell in the next discreet step of time.
> 
> That new value comes from the bottom row. This row is generated by taking the  
> rule number, 30 in this case, in binary form. 1110 is 30 in binary, so we just  
> pad the right side with zeros and we have our table.
> 
> Once you have the rules, you just apply them to a string of cells. For example,  
> given the cells:
> 
> &nbsp;&nbsp;11001
> 
> The rule 30 table creates:
> 
> &nbsp;&nbsp;1101111
> 
> Note that cells outside of what I had were off (zeros) for the purposes of  
> calculating neighborhoods.
> 
> This week's Ruby Quiz is to write a program that accepts up to three parameters:  
> the rule as an integer in decimal, the number of steps to simulate, and the  
> starting state of the cells as a String of ones and zeros. Here's a sample run  
> of my solution using all three options:
> 
> &nbsp;&nbsp;$ ruby cellular\_automaton.rb -r 110 -s 20 -c 1  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXXX XX X  
> &nbsp;&nbsp;&nbsp;&nbsp;XXX XX X XXXXX  
> &nbsp;&nbsp;&nbsp;XX X XXX XXXX X  
> &nbsp;&nbsp;XXXXX XX XXX X XX
> 
> To impress your friends, try adding in support for graphic output in addition to  
> printing to the terminal.

---

<div class="post-metadata">

**Author:** ![Craig\_Demyanovich](https://avatars.discourse-cdn.com/v4/letter/c/e47c2d/32.png) [@Craig\_Demyanovich](https://rubytalk.org/u/Craig_Demyanovich)\
**Post date:** [10 August 2007 13:15 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/2 "2007-08-10T13:15:13Z")

</div>

Noticed a typo in the quiz. 1110 is not 30 in binary; 11110 is.

Regards,  
Craig

> **···**
>
> On Aug 10, 2007, at 8:53 AM, Ruby Quiz wrote:
> 
> > That new value comes from the bottom row. This row is generated by taking the  
> > rule number, 30 in this case, in binary form. 1110 is 30 in binary, so we just  
> > pad the right side with zeros and we have our table.

---

<div class="post-metadata">

**Author:** ![Morton\_Goldberg](https://avatars.discourse-cdn.com/v4/letter/m/7ea924/32.png) [@Morton\_Goldberg](https://rubytalk.org/u/Morton_Goldberg)\
**Post date:** [11 August 2007 00:02 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/3 "2007-08-11T00:02:52Z")

</div>

I'd like to add a little to this quiz description. The cellular automaton James describes is sometimes referred to as the Wolfram automaton because Stephen Wolfram has studied and written extensively on it. There is a good discussion of this problem at

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Elementary Cellular Automaton -- from Wolfram MathWorld](http://mathworld.wolfram.com/ElementaryCellularAutomaton.html)

IIRC, the rule 30 automaton is famous for being chaotic. It looks like this.

![](https://canada1.discourse-cdn.com/flex029/uploads/rubytalk/original/2X/b/bf0dbe356c67ab30d4c63c71b453947b6d3f7ec2.jpg)

> **···**
>
> On Aug 10, 2007, at 8:53 AM, Ruby Quiz wrote:
> 
> > Here's the table for the "rule 30" automaton:
> > 
> > &nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;\> Neighborhood | 111 | 110 | 101 | 100 | 011 | 010 | 001 | 000 |  
> > &nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;\> New Center Cell | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |  
> > &nbsp;&nbsp;+-----------------------------------------------------------------+
> > 
> > The first row is the same for this whole family of automata. It represents the  
> > "neighborhood" of the cell currently being examined, which includes the cell  
> > itself and one cell to either side of it. The current values of those cells,  
> > ones being on and zeros being off, can be used to determine the new value for  
> > this cell in the next discreet step of time.
> > 
> > That new value comes from the bottom row. This row is generated by taking the  
> > rule number, 30 in this case, in binary form. 11110 is 30 in binary, so we just  
> > pad the right side with zeros and we have our table.

---

<div class="post-metadata">

**Author:** ![Jesse\_Merriman](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@Jesse\_Merriman](https://rubytalk.org/u/Jesse_Merriman)\
**Post date:** [12 August 2007 13:13 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/4 "2007-08-12T13:13:36Z")

</div>

Here's my fairly straightforward, no bells-and-whistles solution.

Each state is represented as an Array of Strings. I originally just used  
a String, and split() when needed, but keeping it as an Array makes it a  
bit faster and does simplify the code in a few places.

transformer() builds a Proc that takes a neighborhood as its argument (as  
an Array of Strings) and returns the transformed cell state (as a String).  
A Hash could have been used instead of a Proc.

step() takes a state (as an Array of Strings), tacks [0,0] onto both ends,  
and calls each\_cons(3) to iterate through the neighborhoods, which are  
passed to the transformer Proc.

$ ./cellular\_automata.rb -r 110 -s 1 -n 15  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
&nbsp;&nbsp;&nbsp;XXXXX XX X  
&nbsp;&nbsp;XX X XXX XX  
XXX XXXX X XXX  
XX X XX XXXXX X

[cellular\_automata.rb](https://rubytalk.org/uploads/short-url/jU4Ok5xDlFbfKVPIOEZF2K9ejJI.rb) (1.5 KB)

> **···**
>
> --  
> Jesse Merriman  
> [jessemerriman@warpmail.net](mailto:jessemerriman@warpmail.net)  
> [http://www.jessemerriman.com/](http://www.jessemerriman.com/)

---

<div class="post-metadata">

**Author:** ![Doug1](https://avatars.discourse-cdn.com/v4/letter/d/fbc32d/32.png) [@Doug1](https://rubytalk.org/u/Doug1)\
**Post date:** [12 August 2007 13:54 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/5 "2007-08-12T13:54:50Z")

</div>

Here is my solution. No fancy graphics, the kids didn't give me enough time for that 😉

-Doug Seifert

[automaton.rb](https://rubytalk.org/uploads/short-url/A1yOPtEid2UhrmFx1w6w4rzcbN3.rb) (3.66 KB)

---

<div class="post-metadata">

**Author:** ![Simon\_Kroger](https://avatars.discourse-cdn.com/v4/letter/s/49beb7/32.png) [@Simon\_Kroger](https://rubytalk.org/u/Simon_Kroger)\
**Post date:** [12 August 2007 13:54 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/6 "2007-08-12T13:54:58Z")

</div>

Ruby Quiz wrote:

> [...]  
> This week's Ruby Quiz is to write a program that accepts up to three parameters:  
> the rule as an integer in decimal, the number of steps to simulate, and the  
> starting state of the cells as a String of ones and zeros.

not much time so nothing facing here:

> **···**
>
> ----------------------------------------------------------------------------  
> require 'enumerator'
> 
> puts("usage: ruby q134.rb [rule] [count] [start]") || exit if ARGV.size != 3
> 
> rule, count = ARGV.shift.to\_i, ARGV.shift.to\_i  
> start = [0]\*count + ARGV[0].split('').map{|i|i.to\_i} + [0]\*count
> 
> (0..count).inject(start) do |l, nr|  
> &nbsp;&nbsp;puts l.inject("#{nr}:".rjust(3)){|s, i| s + [' ', '#'][i]}  
> &nbsp;&nbsp;(l[0,1] + l + l[-1,1]).enum\_cons(3).map{|a,b,c| rule[a\*4+b\*2+c]}  
> end  
> ----------------------------------------------------------------------------
> 
> i doubled the last and first item from each line - this seems to create more  
> consistent results with the inverted patterns than just assuming they are 0:
> 
> > ruby q134.rb 129 20 1
> 
> 0: #  
> 1:################### ###################  
> 2:################## # ##################  
> 3:################# #################  
> 4:################ ##### ################  
> 5:############### ### ###############  
> 6:############## ## # ## ##############  
> 7:############# #############  
> 8:############ ############# ############  
> 9:########### ########### ###########  
> 10:########## ## ######### ## ##########  
> 11:######### ####### #########  
> 12:######## ###### ##### ###### ########  
> 13:####### #### ### #### #######  
> 14:###### ## ## ## # ## ## ## ######  
> 15:##### #####  
> 16:#### ############################# ####  
> 17:### ########################### ###  
> 18:## ## ######################### ## ##  
> 19:# ####################### #  
> 20: ###### ##################### ######
> 
> cheers
> 
> Simon

---

<div class="post-metadata">

**Author:** ![Andreas\_Launila](https://avatars.discourse-cdn.com/v4/letter/a/dbc845/32.png) [@Andreas\_Launila](https://rubytalk.org/u/Andreas_Launila)\
**Post date:** [12 August 2007 14:24 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/7 "2007-08-12T14:24:17Z")

</div>

Ruby Quiz wrote:

> This week's Ruby Quiz is to write a program that accepts up to three parameters:  
> the rule as an integer in decimal, the number of steps to simulate, and the  
> starting state of the cells as a String of ones and zeros.

Slightly different/renamed options and no graphics:

&nbsp;&nbsp;ruby cellular\_automaton.rb -r 41 -s 20 -w 30 100100  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X X  
&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXXXX X  
&nbsp;&nbsp;X XXXX  
&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXX X X  
&nbsp;&nbsp;X X X XX  
&nbsp;&nbsp;&nbsp;X XXXXXXXXXXXXXXXXXX X X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X XX  
&nbsp;&nbsp;XXX XXXXXXXXXXXXXXXX X XXXX  
&nbsp;&nbsp;X X X X X  
&nbsp;&nbsp;&nbsp;&nbsp;X X XXXXXXXXXXXXX X XX  
&nbsp;&nbsp;X X X X X  
&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XXXXXXXXXXX X X  
&nbsp;&nbsp;X X X X X X  
&nbsp;&nbsp;&nbsp;X XXX X XXXXXXXXX XXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X X X X X  
&nbsp;&nbsp;XXX XXXXX XXXXXXX X XX  
&nbsp;&nbsp;X X X X X X X  
&nbsp;&nbsp;&nbsp;&nbsp;X X XXX X XXXXXXXXX  
&nbsp;&nbsp;X X X XXXX  
&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XXXXX XXXXXXX X  
&nbsp;&nbsp;X X X X X X X XX

== Code

#!/usr/bin/env ruby  
# == Usage

> **···**
>
> #  
> # cellular\_automaton [OPTIONS] CELLS  
> #  
> # -h, --help:  
> # show help  
> #  
> # -r, --rule RULE:  
> # specified the rule to use as a decimal integer, defaults to 30  
> #  
> # -s, --steps STEPS:  
> # specifies the number of steps that should be shown, defaults to 20  
> #  
> # -w, --width WIDTH:  
> # specifies the number of cells that should be shown per step,  
> # defaults to 20  
> #  
> # CELLS: The initial cell state that should be used. Must be given as a  
> # string of 0 and 1.
> 
> require 'getoptlong'  
> require 'rdoc/usage'  
> require 'enumerator'
> 
> # Describes a state in a cellular automaton.  
> class CellularAutomatonState  
> &nbsp;&nbsp;attr :cells
> 
> &nbsp;&nbsp;private
> 
> &nbsp;&nbsp;# All the possible neighbourhoods of size 3.  
> &nbsp;&nbsp;NEIGHBOURHOODS = [[true, true, true], [true, true, false],  
> &nbsp;&nbsp;&nbsp;&nbsp;[true, false, true], [true, false, false], [false, true, true],  
> &nbsp;&nbsp;&nbsp;&nbsp;[false, true, false], [false, false, true], [false, false, false]]
> 
> &nbsp;&nbsp;public
> 
> &nbsp;&nbsp;# Creates a new state using the specified +rule+ given in decimal.  
> &nbsp;&nbsp;# +inital\_state+ holds an array of booleans describing the initial  
> &nbsp;&nbsp;# state.  
> &nbsp;&nbsp;def initialize(rule, initial\_state)  
> &nbsp;&nbsp;&nbsp;&nbsp;@cells = initial\_state
> 
> &nbsp;&nbsp;&nbsp;&nbsp;# Decode the rule into a hash map. The map is then used when  
> &nbsp;&nbsp;&nbsp;&nbsp;# computing the next state.  
> &nbsp;&nbsp;&nbsp;&nbsp;booleans = rule.to\_s(2).rjust(  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NEIGHBOURHOODS.size, '0').split(//).map{ |x| x == '1' }  
> &nbsp;&nbsp;&nbsp;&nbsp;if booleans.size \> NEIGHBOURHOODS.size  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError, 'The rule is too large.'  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;@rules = {}  
> &nbsp;&nbsp;&nbsp;&nbsp;NEIGHBOURHOODS.each\_with\_index do |neighbourhood, i|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@rules[neighbourhood] = booleans[i]  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end
> 
> &nbsp;&nbsp;# Updates the automaton one step.  
> &nbsp;&nbsp;def step!  
> &nbsp;&nbsp;&nbsp;&nbsp;@new\_cells =   
> &nbsp;&nbsp;&nbsp;&nbsp;# Regard the endings as false.  
> &nbsp;&nbsp;&nbsp;&nbsp;([false] + @cells + [false]).each\_cons(3) do |neighbourhood|  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@new\_cells \<\< @rules[neighbourhood]  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;&nbsp;&nbsp;@cells = @new\_cells  
> &nbsp;&nbsp;end
> 
> &nbsp;&nbsp;def to\_s  
> &nbsp;&nbsp;&nbsp;&nbsp;@cells.map{ |x| x ? 'X' : ' ' }.join  
> &nbsp;&nbsp;end  
> end
> 
> # Defaults  
> rule = 30  
> steps = 20  
> width = 20
> 
> # Options  
> opts = GetoptLong.new(  
> &nbsp;&nbsp;['--help', '-h', GetoptLong::NO\_ARGUMENT],  
> &nbsp;&nbsp;['--rule', '-r', GetoptLong::REQUIRED\_ARGUMENT],  
> &nbsp;&nbsp;['--steps', '-s', GetoptLong::REQUIRED\_ARGUMENT],  
> &nbsp;&nbsp;['--width', '-w', GetoptLong::REQUIRED\_ARGUMENT])  
> opts.each do |opt, arg|  
> &nbsp;&nbsp;case opt  
> &nbsp;&nbsp;&nbsp;&nbsp;when '--help': RDoc::usage  
> &nbsp;&nbsp;&nbsp;&nbsp;when '--rule': rule = arg.to\_i  
> &nbsp;&nbsp;&nbsp;&nbsp;when '--steps': steps = arg.to\_i  
> &nbsp;&nbsp;&nbsp;&nbsp;when '--width': width = arg.to\_i  
> &nbsp;&nbsp;end  
> end
> 
> if ARGV.size != 1  
> &nbsp;&nbsp;abort "Incorrect usage, see --help"  
> end
> 
> # Turn the provided state into an array of booleans, pad if needed.  
> cells = ARGV.shift.rjust(width,'0').split(//).map!{ |cell| cell == '1' }
> 
> # Create the initial state and then step the desired number of times.  
> state = CellularAutomatonState.new(rule, cells)  
> puts state.to\_s  
> steps.times do  
> &nbsp;&nbsp;state.step!  
> &nbsp;&nbsp;puts state.to\_s  
> end
> 
> \_\_END\_\_
> 
> --  
> Andreas Launila

---

<div class="post-metadata">

**Author:** ![Justin\_Ethier](https://avatars.discourse-cdn.com/v4/letter/j/c67d28/32.png) [@Justin\_Ethier](https://rubytalk.org/u/Justin_Ethier)\
**Post date:** [12 August 2007 19:29 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/8 "2007-08-12T19:29:51Z")

</div>

Here is my solution to this week's quiz.  
I have created pasties for the full code:  
Cellular Automata program: [http://pastie.caboo.se/87013](http://pastie.caboo.se/87013)  
RMagick Graphical Extention: [http://pastie.caboo.se/87015](http://pastie.caboo.se/87015)

Here is a quick walk-though of the core logic. First, I included everything  
in its own class:  
&nbsp;&nbsp;&nbsp;class CellularAutomata

I created a method to compute a single iteration (Generation) of the  
cellular automata. The method takes a State array and rule number, and  
builds the next state (generation) of the cells:

&nbsp;&nbsp;def compute\_generation(state, rule)  
&nbsp;&nbsp;&nbsp;&nbsp;result = Array.new

&nbsp;&nbsp;&nbsp;&nbsp;# Pad front and back of state to compute boundaries  
&nbsp;&nbsp;&nbsp;&nbsp;state.insert(0,state[0]).flatten!  
&nbsp;&nbsp;&nbsp;&nbsp;state.push(state[-1])

&nbsp;&nbsp;&nbsp;&nbsp;# Find the 3 digit binary num at each index, and build a list of the  
corresponding bits  
&nbsp;&nbsp;&nbsp;&nbsp;# Uses built-in ruby functionality to index individual bits  
&nbsp;&nbsp;&nbsp;&nbsp;(state.size - 2).times do |i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(rule[convert\_to\_dec(state.slice(i, 3), 2)])  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;end

This method preps the input and runs a series of generations:

&nbsp;&nbsp;def run(rule, steps, state)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Pad state to width of board  
&nbsp;&nbsp;&nbsp;&nbsp;(steps).times do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.insert(0, 0)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.push(0)  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result = .push(Array.new(state))

&nbsp;&nbsp;&nbsp;&nbsp;steps.times do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state = compute\_generation(state, rule)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(Array.new(state))  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;end

Here is a boilerplate method to convert an array of numbers in the given  
base (binary in this program) to a decimal number. There probably is a  
better way to do this in ruby:

&nbsp;&nbsp;def convert\_to\_dec(num\_array, base)  
&nbsp;&nbsp;&nbsp;&nbsp;result, place = 0, 0  
&nbsp;&nbsp;&nbsp;&nbsp;for digit in num\_array.reverse  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result = result + digit \* (base \*\* place)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;place = place + 1  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;end

And finally, here is the code to parse command line args and print  
everything to console:  
if ARGV.size == 3  
&nbsp;&nbsp;cell = CellularAutomata.new  
&nbsp;&nbsp;for generation in cell.run(ARGV[0].to\_i, ARGV[1].to\_i,  
ARGV[2].split("").map{|i| i.to\_i })  
&nbsp;&nbsp;&nbsp;&nbsp;print "\n", generation  
&nbsp;&nbsp;end  
else  
&nbsp;&nbsp;print "Usage: Cellular\_Automata.rb rule\_number number\_of\_steps  
initial\_state"  
end

Here is a sample run:  
Cellular\_Automata.rb 30 10 1

000000000010000000000  
000000000111000000000  
000000001100100000000  
000000011011110000000  
000000110010001000000  
000001101111011100000  
000011001000010010000  
000110111100111111000  
001100100011100000100  
011011110110010001110  
110010000101111011001

A few of the more interesting pictures generated by the RMagick class are  
available online:

> **[Google Sites: Sign-in](https://accounts.google.com/v3/signin/identifier?continue=https%3A%2F%2Fsites.google.com%2Fsite%2Fsites%2Fsystem%2Ferrors%2FWebspaceNotFound%3Fpath%3D%2Fjustinethier%2F134-cellularautomatapictures&followup=https%3A%2F%2Fsites.google.com%2Fsite%2Fsites%2Fsystem%2Ferrors%2FWebspaceNotFound%3Fpath%3D%2Fjustinethier%2F134-cellularautomatapictures&ifkv=ASKXGp0DVIMli5ZQK2AC1tB_kwXtDnQ3MxyS06MfBRqZpZfJpOyuj1BuMcEoUZM0HLRDRerZwEIR&passive=1209600&service=jotspot&flowName=GlifWebSignIn&flowEntry=ServiceLogin&dsh=S-570230436%3A1707410685231819&theme=glif)**
>
> Access Google Sites with a personal Google account or Google Workspace account (for business use).

Thanks,

Justin

> **···**
>
> On 8/10/07, Ruby Quiz \<james@grayproductions.net\> wrote:
> 
> > The three rules of Ruby Quiz:
> > 
> > 1. Please do not post any solutions or spoiler discussion for this quiz  
> > until  
> > 48 hours have passed from the time on this message.
> > 
> > 2. Support Ruby Quiz by submitting ideas as often as you can:
> > 
> > [http://www.rubyquiz.com/](http://www.rubyquiz.com/)
> > 
> > 3. Enjoy!
> > 
> > Suggestion: A [QUIZ] in the subject of emails about the problem helps  
> > everyone  
> > on Ruby Talk follow the discussion. Please reply to the original quiz  
> > message,  
> > if you can.
> > 
> > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> > 
> > Most of us have probably heard of Conway's Game of Life, but there are  
> > other  
> > cellular automata that are equally interesting. In fact, there is a group  
> > of  
> > 256 one-dimensional cellular automata that are quite easy to simulate but  
> > still  
> > fun to observe.
> > 
> > To simulate these elementary cellular automata, you first need to  
> > construct a  
> > rule table. This table is a description of the changes that happen in  
> > each  
> > discreet step of time. Here's the table for the "rule 30" automaton:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> Neighborhood | 111 | 110 | 101 | 100 | 011 | 010 | 001 | 000  
> > \>
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> New Center Cell  
> > \> 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+
> > 
> > The first row is the same for this whole family of automata. It  
> > represents the  
> > "neighborhood" of the cell currently being examined, which includes the  
> > cell  
> > itself and one cell to either side of it. The current values of those  
> > cells,  
> > ones being on and zeros being off, can be used to determine the new value  
> > for  
> > this cell in the next discreet step of time.
> > 
> > That new value comes from the bottom row. This row is generated by taking  
> > the  
> > rule number, 30 in this case, in binary form. 1110 is 30 in binary, so we  
> > just  
> > pad the right side with zeros and we have our table.
> > 
> > Once you have the rules, you just apply them to a string of cells. For  
> > example,  
> > given the cells:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11001
> > 
> > The rule 30 table creates:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1101111
> > 
> > Note that cells outside of what I had were off (zeros) for the purposes of  
> > calculating neighborhoods.
> > 
> > This week's Ruby Quiz is to write a program that accepts up to three  
> > parameters:  
> > the rule as an integer in decimal, the number of steps to simulate, and  
> > the  
> > starting state of the cells as a String of ones and zeros. Here's a  
> > sample run  
> > of my solution using all three options:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ ruby cellular\_automaton.rb -r 110 -s 20 -c 1  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX XXX X XX
> > 
> > To impress your friends, try adding in support for graphic output in  
> > addition to  
> > printing to the terminal.

---

<div class="post-metadata">

**Author:** ![Zed\_Lopez](https://avatars.discourse-cdn.com/v4/letter/z/f07891/32.png) [@Zed\_Lopez](https://rubytalk.org/u/Zed_Lopez)\
**Post date:** [13 August 2007 07:14 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/9 "2007-08-13T07:14:57Z")

</div>

I added another command-line switch to specify the output mapping  
(defaulting to ' ' and 'X' like the example.)

#!/usr/bin/env ruby

require 'optparse'  
require 'enumerator'

ruleset = 0  
steps = 1  
cells = ['0']  
output\_map = ' X'

OptionParser.new do |opts|  
&nbsp;&nbsp;opts.on("-r", "--ruleset RULESET", Integer, "Ruleset specification")  
{|r| ruleset = r }  
&nbsp;&nbsp;opts.on("-s", "--steps STEPS", Integer, "Number of steps") {|s| steps  
= s}  
&nbsp;&nbsp;opts.on("-c", "--cells CELLS", "Initial cells string") {|c| cells =  
c.split(//)}  
&nbsp;&nbsp;opts.on("-m", "--map MAP", "Character map for output") {|m| output\_map  
= m}  
end.parse!(ARGV)

rule = {}  
0.upto(7) {|i| rule[sprintf("%03b", i).split(//)] = ruleset[i].to\_s}

width = steps \* 2 + cells.length + 1  
0.upto(steps) do  
&nbsp;&nbsp;puts [cells.join.tr](http://cells.join.tr)('01', output\_map).center(width)  
&nbsp;&nbsp;cells = (['0','0'] + cells + ['0','0']).enum\_cons(3).map {|l| rule[l]}  
end

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Drew\_Olson](https://avatars.discourse-cdn.com/v4/letter/d/c67d28/32.png) [@Drew\_Olson](https://rubytalk.org/u/Drew_Olson)\
**Post date:** [13 August 2007 13:17 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/10 "2007-08-13T13:17:44Z")

</div>

James Gray wrote:

> The three rules of Ruby Quiz:

Here's my solution. Note: I saw no reason to make the output right  
justified, so mine is left justified. Not sure if this matters much...

Sample output:

drew$ ruby cell.rb 110 20 1  
X  
XX  
XXX  
XX X  
XXXXX  
XX X  
XXX XX  
XX X XXX  
XXXXXXX X  
XX XXX  
XXX XX X  
XX X XXXXX  
XXXXX XX X  
XX X XXX XX  
XXX XXXX X XXX  
XX X XX XXXXX X  
XXXXXXXX XX XXX  
XX XXXX XX X  
XXX XX X XXXXX  
XX X XXX XXXX X  
XXXXX XX XXX X XX

My code:

# file: cell.rb  
# author: drew olson

class CellAutomata  
&nbsp;&nbsp;require 'enumerator'

&nbsp;&nbsp;def initialize rule  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if rule \< 0 || rule \> 255  
&nbsp;&nbsp;&nbsp;&nbsp;@rule\_table = build\_table rule  
&nbsp;&nbsp;end

&nbsp;&nbsp;# simulate a given number of generations. return in string format  
&nbsp;&nbsp;def simulate cur\_gen, num\_gen  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if num\_gen \< 0  
&nbsp;&nbsp;&nbsp;&nbsp;if num\_gen == 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen)  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen) + simulate(build\_new\_gen(cur\_gen),num\_gen-1)  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;private

&nbsp;&nbsp;# format a generation for printing  
&nbsp;&nbsp;def format\_gen gen  
&nbsp;&nbsp;&nbsp;&nbsp;gen.gsub(/0/,' ').gsub(/1/,'X').strip+"\n"  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build new generation based on current generation  
&nbsp;&nbsp;def build\_new\_gen gen  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen = ''  
&nbsp;&nbsp;&nbsp;&nbsp;('00'+gen+'00').split(//).each\_cons(3) do |group|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new\_gen += @rule\_table[group.join('').to\_i(2)]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build rule table based on a number seed  
&nbsp;&nbsp;def build\_table rule  
&nbsp;&nbsp;&nbsp;&nbsp;rule\_string = ("%08d" % rule.to\_s(2)).split(//).reverse.to\_s  
&nbsp;&nbsp;&nbsp;&nbsp;(0..7).inject({}) do |rule\_table,i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table[i] = rule\_string[i,1]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end

# create automation based on command line args  
if \_\_FILE\_\_ == $0 || true  
&nbsp;&nbsp;cell = CellAutomata.new(ARGV[0].to\_i)  
&nbsp;&nbsp;puts cell.simulate(ARGV[2],ARGV[1].to\_i)  
end

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Drew\_Olson](https://avatars.discourse-cdn.com/v4/letter/d/c67d28/32.png) [@Drew\_Olson](https://rubytalk.org/u/Drew_Olson)\
**Post date:** [13 August 2007 14:11 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/11 "2007-08-13T14:11:48Z")

</div>

James Gray wrote:

> The three rules of Ruby Quiz:

My \_working\_ solution 🙂 Thanks for the clarifications James. Output:

drew$ ruby cell.rb 110 20 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
&nbsp;&nbsp;&nbsp;&nbsp;XX XXXX XX X  
&nbsp;&nbsp;&nbsp;XXX XX X XXXXX  
&nbsp;&nbsp;XX X XXX XXXX X  
XXXXX XX XXX X XX

Code:

# file: cell.rb  
# author: drew olson

class CellAutomata  
&nbsp;&nbsp;require 'enumerator'

&nbsp;&nbsp;def initialize rule  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if rule \< 0 || rule \> 255  
&nbsp;&nbsp;&nbsp;&nbsp;@rule\_table = build\_table rule  
&nbsp;&nbsp;end

&nbsp;&nbsp;# simulate a given number of generations. return in string format  
&nbsp;&nbsp;def simulate cur\_gen, num\_gen  
&nbsp;&nbsp;&nbsp;&nbsp;@max\_gen ||= num\_gen+1  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if num\_gen \< 0  
&nbsp;&nbsp;&nbsp;&nbsp;if num\_gen == 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen,num\_gen)  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen,num\_gen) +  
simulate(build\_new\_gen(cur\_gen),num\_gen-1)  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;private

&nbsp;&nbsp;# format a generation for printing  
&nbsp;&nbsp;def format\_gen gen,num\_gen  
&nbsp;&nbsp;&nbsp;&nbsp;("%0#{@max\_gen+(@max\_gen-num\_gen)}d" % gen).gsub(/0/,'  
').gsub(/1/,'X')+"\n"  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build new generation based on current generation  
&nbsp;&nbsp;def build\_new\_gen gen  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen = ''  
&nbsp;&nbsp;&nbsp;&nbsp;('00'+gen+'00').split(//).each\_cons(3) do |group|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new\_gen += @rule\_table[group.join('').to\_i(2)]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build rule table based on a number seed  
&nbsp;&nbsp;def build\_table rule  
&nbsp;&nbsp;&nbsp;&nbsp;rule\_string = ("%08d" % rule.to\_s(2)).split(//).reverse.to\_s  
&nbsp;&nbsp;&nbsp;&nbsp;(0..7).inject({}) do |rule\_table,i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table[i] = rule\_string[i,1]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end

# create automation based on command line args  
if \_\_FILE\_\_ == $0 || true  
&nbsp;&nbsp;cell = CellAutomata.new(ARGV[0].to\_i)  
&nbsp;&nbsp;puts cell.simulate(ARGV[2],ARGV[1].to\_i)  
end

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Daniel\_Martin](https://avatars.discourse-cdn.com/v4/letter/d/dc4da7/32.png) [@Daniel\_Martin](https://rubytalk.org/u/Daniel_Martin)\
**Post date:** [14 August 2007 12:37 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/12 "2007-08-14T12:37:51Z")

</div>

I didn't have much time this weekend, but I had a bit more than  
previous weeks, so here's my solution. The goal here was "minimal  
coding". As a result, the rule-evaluation statement could charitably  
be described as "terse". It just does X's and spaces as in the quiz  
description.

#!ruby  
require 'optparse'

rule = 30  
initial\_pattern = '1'  
steps = 10  
OptionParser.new do |opts|  
&nbsp;&nbsp;opts.banner = "Usage: ca.rb [opts]"  
&nbsp;&nbsp;opts.on("-r", "--rule N", Integer, "Rule number") do |n|  
&nbsp;&nbsp;&nbsp;&nbsp;rule = n  
&nbsp;&nbsp;end  
&nbsp;&nbsp;opts.on("-s", "--states N", Integer,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Number of states (default 10)") do |s|  
&nbsp;&nbsp;&nbsp;&nbsp;steps = s  
&nbsp;&nbsp;end  
&nbsp;&nbsp;opts.on("-c", "--cells BITSTRING", String,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Initial cell pattern as 0s and 1s") do |s|  
&nbsp;&nbsp;&nbsp;&nbsp;initial\_pattern = s  
&nbsp;&nbsp;end  
end.parse!

# This ensures some padding for those nasty odd rules  
pattern = '0' \* steps + initial\_pattern + '0' \* steps;  
(steps-1).times {  
&nbsp;&nbsp;puts [pattern.tr](http://pattern.tr)('01',' X')  
&nbsp;&nbsp;ppat = pattern[0,1] + pattern + pattern[-1,1]  
&nbsp;&nbsp;pattern = (1..pattern.size).inject(""){|s,i|  
&nbsp;&nbsp;&nbsp;&nbsp;s \<\< ((rule \>\> [ppat[i-1,3]].pack('b3')[0])&1).to\_s  
&nbsp;&nbsp;}  
}  
puts [pattern.tr](http://pattern.tr)('01',' X')

\_\_END\_\_

> **···**
>
> --  
> s=%q( Daniel Martin -- [martin@snowplow.org](mailto:martin@snowplow.org)  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "s=%q(#{s})",s.to\_a.last )  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts "s=%q(#{s})",s.to\_a.last

---

<div class="post-metadata">

**Author:** ![Justin\_Ethier](https://avatars.discourse-cdn.com/v4/letter/j/c67d28/32.png) [@Justin\_Ethier](https://rubytalk.org/u/Justin_Ethier)\
**Post date:** [14 August 2007 14:44 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/13 "2007-08-14T14:44:38Z")

</div>

Cleaned up a couple of things in my program, mainly using to\_i to convert  
from binary:

class CellularAutomata

&nbsp;&nbsp;# Compute a single iteration (Generation) of the cellular automata  
&nbsp;&nbsp;# Inputs: State array, rule array  
&nbsp;&nbsp;# Returns: New State array  
&nbsp;&nbsp;def compute\_generation(state, rule)  
&nbsp;&nbsp;&nbsp;&nbsp;result = Array.new

&nbsp;&nbsp;&nbsp;&nbsp;# Pad front and back of state to compute boundaries  
&nbsp;&nbsp;&nbsp;&nbsp;state.insert(0, state[0])  
&nbsp;&nbsp;&nbsp;&nbsp;state.push(state[-1])

&nbsp;&nbsp;&nbsp;&nbsp;# Build a list of the corresponding bits for each 3 digit binary number  
&nbsp;&nbsp;&nbsp;&nbsp;(state.size - 2).times do |i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(rule[state.slice(i, 3).join.to\_i(2)])  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;end

&nbsp;&nbsp;# Run a series of generations  
&nbsp;&nbsp;def run(rule, steps, state)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Pad state to width of board  
&nbsp;&nbsp;&nbsp;&nbsp;(steps).times do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.insert(0, 0)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state.push(0)  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result = .push(Array.new(state))  
&nbsp;&nbsp;&nbsp;&nbsp;steps.times do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state = compute\_generation(state, rule)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.push(Array.new(state))  
&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;result  
&nbsp;&nbsp;end  
end

if ARGV.size == 3  
&nbsp;&nbsp;cell = CellularAutomata.new  
&nbsp;&nbsp;for generation in cell.run(ARGV[0].to\_i, ARGV[1].to\_i,  
ARGV[2].split("").map{|i| i.to\_i })  
&nbsp;&nbsp;&nbsp;&nbsp;print "\n", generation  
&nbsp;&nbsp;end  
else  
&nbsp;&nbsp;print "Usage: Cellular\_Automata.rb rule\_number number\_of\_steps initial\_state"  
end

A pastie of it is here: [http://pastie.caboo.se/87535](http://pastie.caboo.se/87535)  
Thanks,

Justin

> **···**
>
> On 8/10/07, Ruby Quiz \<james@grayproductions.net \> wrote:
> 
> > The three rules of Ruby Quiz:
> > 
> > 1. Please do not post any solutions or spoiler discussion for this quiz  
> > until  
> > 48 hours have passed from the time on this message.
> > 
> > 2. Support Ruby Quiz by submitting ideas as often as you can:
> > 
> > [http://www.rubyquiz.com/](http://www.rubyquiz.com/)
> > 
> > 3. Enjoy!
> > 
> > Suggestion: A [QUIZ] in the subject of emails about the problem helps  
> > everyone  
> > on Ruby Talk follow the discussion. Please reply to the original quiz  
> > message,  
> > if you can.
> > 
> > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> > 
> > Most of us have probably heard of Conway's Game of Life, but there are  
> > other  
> > cellular automata that are equally interesting. In fact, there is a group  
> > of  
> > 256 one-dimensional cellular automata that are quite easy to simulate but  
> > still  
> > fun to observe.
> > 
> > To simulate these elementary cellular automata, you first need to  
> > construct a  
> > rule table. This table is a description of the changes that happen in  
> > each  
> > discreet step of time. Here's the table for the "rule 30" automaton:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> Neighborhood | 111 | 110 | 101 | 100 | 011 | 010 | 001 | 000  
> > \>  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> New Center Cell  
> > \> 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+
> > 
> > The first row is the same for this whole family of automata. It  
> > represents the  
> > "neighborhood" of the cell currently being examined, which includes the  
> > cell  
> > itself and one cell to either side of it. The current values of those  
> > cells,  
> > ones being on and zeros being off, can be used to determine the new value  
> > for  
> > this cell in the next discreet step of time.
> > 
> > That new value comes from the bottom row. This row is generated by taking  
> > the  
> > rule number, 30 in this case, in binary form. 1110 is 30 in binary, so we  
> > just  
> > pad the right side with zeros and we have our table.
> > 
> > Once you have the rules, you just apply them to a string of cells. For  
> > example,  
> > given the cells:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11001
> > 
> > The rule 30 table creates:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1101111
> > 
> > Note that cells outside of what I had were off (zeros) for the purposes of  
> > calculating neighborhoods.
> > 
> > This week's Ruby Quiz is to write a program that accepts up to three  
> > parameters:  
> > the rule as an integer in decimal, the number of steps to simulate, and  
> > the  
> > starting state of the cells as a String of ones and zeros. Here's a  
> > sample run  
> > of my solution using all three options:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ ruby cellular\_automaton.rb -r 110 -s 20 -c 1  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX XXX X XX
> > 
> > To impress your friends, try adding in support for graphic output in  
> > addition to  
> > printing to the terminal.

---

<div class="post-metadata">

**Author:** ![Yossef\_Mendelssohn](https://avatars.discourse-cdn.com/v4/letter/y/f19dbf/32.png) [@Yossef\_Mendelssohn](https://rubytalk.org/u/Yossef_Mendelssohn)\
**Post date:** [15 August 2007 15:12 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/14 "2007-08-15T15:12:23Z")

</div>

My solution, late-ish but not too late:

#!/usr/bin/env ruby

require 'optparse'

cells = nil  
steps = nil  
rule = nil  
OptionParser.new do |opts|  
&nbsp;&nbsp;opts.on('-c', '--cells [CELLS]', 'A string representing the initial  
cell state as a series of 1s and 0s') do |cells\_opt|  
&nbsp;&nbsp;&nbsp;&nbsp;cells = cells\_opt  
&nbsp;&nbsp;end  
&nbsp;&nbsp;opts.on('-s', '--steps [STEPS]', Integer, 'The number of steps to  
simulate') do |steps\_opt|  
&nbsp;&nbsp;&nbsp;&nbsp;steps = steps\_opt.to\_i  
&nbsp;&nbsp;end  
&nbsp;&nbsp;opts.on('-r', '--rule [RULE]', Integer, 'The rule as a decimal  
integer') do |rule\_opt|  
&nbsp;&nbsp;&nbsp;&nbsp;rule = ('%b' % rule\_opt)[0,8].rjust(8, '0')  
&nbsp;&nbsp;end  
&nbsp;&nbsp;opts.parse!(ARGV)  
end

rule\_table = {}  
(0..7).to\_a.reverse.collect { |n| '%b' % n }.zip(rule.split('')) do |  
n, r|  
&nbsp;&nbsp;rule\_table[n.rjust(3, '0')] = r  
end

cells = ('0' \* steps) + cells + ('0' \* steps)

puts cells.gsub(/1/, 'X').gsub(/0/, ' ')  
steps.times do  
&nbsp;&nbsp;check\_cells = "0#{cells}0" # pad with zeroes for ease of checking  
&nbsp;&nbsp;new\_cells = ''

&nbsp;&nbsp;(0...cells.length).each do |i|  
&nbsp;&nbsp;&nbsp;&nbsp;neighborhood = check\_cells[i, 3]  
&nbsp;&nbsp;&nbsp;&nbsp;new\_cells \<\< rule\_table[neighborhood]  
&nbsp;&nbsp;end  
&nbsp;&nbsp;cells = new\_cells  
&nbsp;&nbsp;puts cells.gsub(/1/, 'X').gsub(/0/, ' ')  
end

Cassady:~/stuff yossef$ ./cellular.rb -s 20 -c 1 -r 110  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
&nbsp;&nbsp;&nbsp;XX XXXX XX X  
&nbsp;&nbsp;XXX XX X XXXXX  
XX X XXX XXXX X  
XXXXX XX XXX X XX

> **···**
>
> On Aug 10, 7:53 am, Ruby Quiz \<ja...@grayproductions.net\> wrote:
> 
> > The three rules of Ruby Quiz:
> > 
> > 1. Please do not post any solutions or spoiler discussion for this quiz until  
> > 48 hours have passed from the time on this message.
> > 
> > 2. Support Ruby Quiz by submitting ideas as often as you can:
> > 
> > [http://www.rubyquiz.com/](http://www.rubyquiz.com/)
> > 
> > 3. Enjoy!
> > 
> > Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone  
> > on Ruby Talk follow the discussion. Please reply to the original quiz message,  
> > if you can.
> > 
> > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
> > 
> > Most of us have probably heard of Conway's Game of Life, but there are othercellularautomata that are equally interesting. In fact, there is a group of  
> > 256 one-dimensionalcellularautomata that are quite easy to simulate but still  
> > fun to observe.
> > 
> > To simulate these elementarycellularautomata, you first need to construct a  
> > rule table. This table is a description of the changes that happen in each  
> > discreet step of time. Here's the table for the "rule 30" automaton:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> Neighborhood | 111 | 110 | 101 | 100 | 011 | 010 | 001 | 000 |  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\> New Center Cell | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+-----------------------------------------------------------------+
> > 
> > The first row is the same for this whole family of automata. It represents the  
> > "neighborhood" of the cell currently being examined, which includes the cell  
> > itself and one cell to either side of it. The current values of those cells,  
> > ones being on and zeros being off, can be used to determine the new value for  
> > this cell in the next discreet step of time.
> > 
> > That new value comes from the bottom row. This row is generated by taking the  
> > rule number, 30 in this case, in binary form. 1110 is 30 in binary, so we just  
> > pad the right side with zeros and we have our table.
> > 
> > Once you have the rules, you just apply them to a string of cells. For example,  
> > given the cells:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;11001
> > 
> > The rule 30 table creates:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1101111
> > 
> > Note that cells outside of what I had were off (zeros) for the purposes of  
> > calculating neighborhoods.
> > 
> > This week's Ruby Quiz is to write a program that accepts up to three parameters:  
> > the rule as an integer in decimal, the number of steps to simulate, and the  
> > starting state of the cells as a String of ones and zeros. Here's a sample run  
> > of my solution using all three options:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$ ruby cellular\_automaton.rb -r 110 -s 20 -c 1  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XXXX X XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XX XXXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXX XX XXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX XXXX XX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXX XX X XXXXX  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XX X XXX XXXX X  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XXXXX XX XXX X XX
> > 
> > To impress your friends, try adding in support for graphic output in addition to  
> > printing to the terminal.

---

<div class="post-metadata">

**Author:** ![Gareth\_Adams](https://avatars.discourse-cdn.com/v4/letter/g/c68b51/32.png) [@Gareth\_Adams](https://rubytalk.org/u/Gareth_Adams)\
**Post date:** [10 August 2007 14:49 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/15 "2007-08-10T14:49:18Z")

</div>

Craig Demyanovich \<cdemyanovich \<at\> gmail.com\> writes:

> Noticed a typo in the quiz. 1110 is not 30 in binary; 11110 is.

...

> \> binary, so we just  
> \> pad the right side with zeros and we have our table.

In addition, you'll be padding the left side, Shirley?

---

<div class="post-metadata">

**Author:** ![James\_Britt](https://avatars.discourse-cdn.com/v4/letter/j/22d042/32.png) [@James\_Britt](https://rubytalk.org/u/James_Britt)\
**Post date:** [11 August 2007 02:13 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/16 "2007-08-11T02:13:12Z")

</div>

are these not fractals?

---

<div class="post-metadata">

**Author:** ![James\_Edward\_Gray\_II](https://avatars.discourse-cdn.com/v4/letter/j/ea5d25/32.png) [@James\_Edward\_Gray\_II](https://rubytalk.org/u/James_Edward_Gray_II)\
**Post date:** [12 August 2007 16:21 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/17 "2007-08-12T16:21:54Z")

</div>

My solution does the required tasks and makes PPM graphics. Here's the code:

#!/usr/bin/env ruby -wKU

require "ppm"

require "enumerator"  
require "optparse"

options = {:rule =\> 30, :steps =\> 20, :cells =\> "1", :output =\> :ascii}

ARGV.options do |opts|  
&nbsp;&nbsp;&nbsp;opts.banner = "Usage: #{File.basename($PROGRAM\_NAME)} [OPTIONS]"

&nbsp;&nbsp;&nbsp;opts.separator ""  
&nbsp;&nbsp;&nbsp;opts.separator "Specific Options:"

&nbsp;&nbsp;&nbsp;opts.on( "-r", "--rule RULE", Integer,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"The rule for this simulation." ) do |rule|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise "Rule out of bounds" unless rule.between? 0, 255  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options[:rule] = rule  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;opts.on( "-s", "--steps STEPS", Integer,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"The number of steps to render." ) do |steps|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options[:steps] = steps  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;opts.on( "-c", "--cells CELLS", String,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"The starting cells (1s and 0s)." ) do |cells|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raise "Malformed cells" unless cells =~ /\A[01]+\z/  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options[:cells] = cells  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;opts.on( "-o", "--output FORMAT", [:ascii, :ppm],  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"The output format (ascii or ppm)." ) do |output|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options[:output] = output  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;opts.separator "Common Options:"

&nbsp;&nbsp;&nbsp;opts.on( "-h", "--help",  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Show this message." ) do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts opts  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;begin  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;opts.parse!  
&nbsp;&nbsp;&nbsp;rescue  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puts opts  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit  
&nbsp;&nbsp;&nbsp;end  
end

RULE\_TABLE = Hash[\*%w[111 110 101 100 011 010 001 000].  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zip(("%08b" % options[:rule]).scan(/./)).flatten ]

cells = [options[:cells]]  
options[:steps].times do  
&nbsp;&nbsp;&nbsp;cells \<\< "00#{cells.last}00".scan(/./).  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enum\_cons(3).  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inject("") { |nc, n| nc + RULE\_TABLE[n.join] }  
end

width = cells.last.length  
if options[:output] == :ascii  
&nbsp;&nbsp;&nbsp;cells.each { |cell| puts cell.tr("10", "X ").center(width) }  
else  
&nbsp;&nbsp;&nbsp;image = PPM.new( :width =\> width,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:height =\> cells.length,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:background =\> PPM::Color::BLACK,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:foreground =\> PPM::Color[0, 0, 255],  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:mode =\> "P3" )  
&nbsp;&nbsp;&nbsp;cells.each\_with\_index do |row, y|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;row.center(width).scan(/./).each\_with\_index do |cell, x|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.draw\_point(x, y) if cell == "1"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;image.save("rule\_#{options[:rule]}\_steps\_#{options[:steps]}")  
end

\_\_END\_\_

It requires this tiny PPM library:

#!/usr/bin/env ruby -wKU

# Updated by James Edward Gray II from the Turtle Graphics quiz.

class PPM  
&nbsp;&nbsp;&nbsp;class Color  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def self.(\*args)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;args \<\< args.last while args.size \< 3  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new(\*args)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize(red, green, blue)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@red = red  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@green = green  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@blue = blue  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BLACK = new(0, 0, 0)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WHITE = new(255, 255, 255)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def inspect  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"PPM::Color[#{@red}, #{@green}, #{@blue}]"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def to\_s(mode)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if mode == "P6"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@red, @green, @blue].pack("C\*")  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"#{@red} #{@green} #{@blue}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;DEFAULT\_OPTIONS = { :width =\> 400,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:height =\> 400,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:background =\> Color::BLACK,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:foreground =\> Color::WHITE,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:mode =\> "P6" }

&nbsp;&nbsp;&nbsp;def initialize(options = Hash.new)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;options = DEFAULT\_OPTIONS.merge(options)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@width = options[:width]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@height = options[:height]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@background = options[:background]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@foreground = options[:foreground]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@mode = options[:mode]

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@canvas = Array.new(@height) { Array.new(@width) { @background } }  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def draw\_point(x, y, color = @foreground)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return unless x.between? 0, @width - 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return unless y.between? 0, @height - 1

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@canvas[y] = color  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;# [Bresenham's line algorithm - Wikipedia](http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm)  
&nbsp;&nbsp;&nbsp;def draw\_line(x0, y0, x1, y1, color = @foreground)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;steep = (y1 - y0).abs \> (x1 - x0).abs  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if steep  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x0, y0 = y0, x0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x1, y1 = y1, x1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if x0 \> x1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x0, x1 = x1, x0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y0, y1 = y1, y0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deltax = x1 - x0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deltay = (y1 - y0).abs  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error = 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ystep = y0 \< y1 ? 1 : -1

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y = y0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(x0..x1).each do |x|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if steep  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw\_point(y, x, color)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;draw\_point(x, y, color)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error += deltay  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if 2 \* error \>= deltax  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y += ystep  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;error -= deltax  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;def save(file)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File.open(file.sub(/\.ppm$/i, "") + ".ppm", "w") do |image|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.puts @mode  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.puts "#{@width} #{@height} 255"

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@canvas.each do |row|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixels = row.map { |pixel| pixel.to\_s(@mode) }  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;image.send( @mode == "P6" ? :print : :puts,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pixels.join(@mode == "P6" ? "" : " ") )  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;end  
end

\_\_END\_\_

James Edward Gray II

> **···**
>
> On Aug 12, 2007, at 8:13 AM, Jesse Merriman wrote:
> 
> > Here's my fairly straightforward, no bells-and-whistles solution.

---

<div class="post-metadata">

**Author:** ![Simon\_Strandgaard2](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Simon\_Strandgaard2](https://rubytalk.org/u/Simon_Strandgaard2)\
**Post date:** [12 August 2007 20:01 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/18 "2007-08-12T20:01:55Z")

</div>

[snip]

> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Elementary Cellular Automaton -- from Wolfram MathWorld](http://mathworld.wolfram.com/ElementaryCellularAutomaton.html)
> 
> IIRC, the rule 30 automaton is famous for being chaotic. It looks  
> like this.
> 
> Above picture made with Mathematica, not Ruby.

I don't know if posting images is a good thing, but here is mine.  
Compressed as much as possible 🙂

sorry: I wrote it in objc.

![](https://canada1.discourse-cdn.com/flex029/uploads/rubytalk/original/2X/d/ddf4b5845f503a610277dde18433e9c066bbb7f9.jpg)

> **···**
>
> On 8/11/07, Morton Goldberg \<m\_goldberg@ameritech.net\> wrote:
> 
> --  
> Simon Strandgaard  
> [http://opcoders.com/](http://opcoders.com/)

---

<div class="post-metadata">

**Author:** ![Drew\_Olson](https://avatars.discourse-cdn.com/v4/letter/d/c67d28/32.png) [@Drew\_Olson](https://rubytalk.org/u/Drew_Olson)\
**Post date:** [13 August 2007 13:23 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/19 "2007-08-13T13:23:11Z")

</div>

Drew Olson wrote:

> James Gray wrote:
> 
> > The three rules of Ruby Quiz:
> 
> Here's my solution. Note: I saw no reason to make the output right

Whoops, shouldn't have stripped the output. Updated:

# file: cell.rb  
# author: drew olson

class CellAutomata  
&nbsp;&nbsp;require 'enumerator'

&nbsp;&nbsp;def initialize rule  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if rule \< 0 || rule \> 255  
&nbsp;&nbsp;&nbsp;&nbsp;@rule\_table = build\_table rule  
&nbsp;&nbsp;end

&nbsp;&nbsp;# simulate a given number of generations. return in string format  
&nbsp;&nbsp;def simulate cur\_gen, num\_gen  
&nbsp;&nbsp;&nbsp;&nbsp;raise ArgumentError if num\_gen \< 0  
&nbsp;&nbsp;&nbsp;&nbsp;if num\_gen == 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen)  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;format\_gen(cur\_gen) + simulate(build\_new\_gen(cur\_gen),num\_gen-1)  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end

&nbsp;&nbsp;private

&nbsp;&nbsp;# format a generation for printing  
&nbsp;&nbsp;def format\_gen gen  
&nbsp;&nbsp;&nbsp;&nbsp;gen.gsub(/0/,' ').gsub(/1/,'X')+"\n"  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build new generation based on current generation  
&nbsp;&nbsp;def build\_new\_gen gen  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen = ''  
&nbsp;&nbsp;&nbsp;&nbsp;('00'+gen+'00').split(//).each\_cons(3) do |group|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new\_gen += @rule\_table[group.join('').to\_i(2)]  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;new\_gen  
&nbsp;&nbsp;end

&nbsp;&nbsp;# build rule table based on a number seed  
&nbsp;&nbsp;def build\_table rule  
&nbsp;&nbsp;&nbsp;&nbsp;rule\_string = ("%08d" % rule.to\_s(2)).split(//).reverse.to\_s  
&nbsp;&nbsp;&nbsp;&nbsp;(0..7).inject({}) do |rule\_table,i|  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table[i] = rule\_string[i,1]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rule\_table  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end

# create automation based on command line args  
if \_\_FILE\_\_ == $0 || true  
&nbsp;&nbsp;cell = CellAutomata.new(ARGV[0].to\_i)  
&nbsp;&nbsp;puts cell.simulate(ARGV[2],ARGV[1].to\_i)  
end

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![James\_Edward\_Gray\_II](https://avatars.discourse-cdn.com/v4/letter/j/ea5d25/32.png) [@James\_Edward\_Gray\_II](https://rubytalk.org/u/James_Edward_Gray_II)\
**Post date:** [13 August 2007 13:34 UTC](https://rubytalk.org/t/quiz-cellular-automata-134/39806/20 "2007-08-13T13:34:26Z")

</div>

I don't think the rules should be justified in either direction. The pattern dictates how they expand.

Your code draws some rules differently, for example:

$ ruby -I solutions/James\ Edward\ Gray\ II/ solutions/James\ Edward\ Gray\ II/cellular\_automaton.rb -r 2  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;&nbsp;X  
&nbsp;&nbsp;X  
X  
$ ruby solutions/Drew\ Olson/cell.rb 2 20 1  
X

James Edward Gray II

> **···**
>
> On Aug 13, 2007, at 8:17 AM, Drew Olson wrote:
> 
> > Note: I saw no reason to make the output right  
> > justified, so mine is left justified. Not sure if this matters much...

[Next page](https://rubytalk.org/t/quiz-cellular-automata-134/39806.md?page=2)
