class Automaton
attr_accessor :rule_number
attr_reader :rule_map
FILLED_CHAR = '#'
EMPTY_CHAR = '.'
def initialize(rule_number, initial_state)
puts "INITIAL STATE CTOR: #{initial_state}"
@rule_number = rule_number
@chars = initial_state.length
@num = 0
initial_state.reverse.split(//).each_with_index do |c, idx|
@num += 2 ** idx if '1' == c
end
initialize_rule_map
end
def initialize_rule_map
@rule_map = []
n = @rule_number
(0..7).each do |idx|
@rule_map[idx] = n & 1 != 0 ? 1 : 0
n = n >> 1 unless n == 0
end
end
def run(iters = 20)
puts "INITIAL STATE: #{@num}" if
cols = @chars + iters * 2
(0..iters).each do |i|
@num = print_line(@num, @chars, i, cols)
@chars += 2
end
end
def print_line(num, chars, iter, cols)
if iter == 0
puts ("%0#{chars}b" % num).gsub("1", FILLED_CHAR).gsub("0", EMPTY_CHAR).center(cols)
return num
end
num = num << 2
ret = 0
line = ""
(0..chars-1).each do |count|
idx = num & 7
if @rule_map[idx] == 1
line << FILLED_CHAR
ret += 2 ** count
else
line << EMPTY_CHAR
end
num = num >> 1
end
puts line.reverse.center(cols)
return ret
end
end
if __FILE__ == $0
require 'ostruct'
require 'optparse'
options = OpenStruct.new
options.rule_num = nil
options.start_state = '1'
options.iterations = 20
options.verbose = false
opts = OptionParser.new do |opts|
opts.banner = "Usage: ruby automata.rb [options]"
opts.separator ""
opts.on("-r", "--rule-number NUMBER",
"Set the automata rule number, 0-255.") do |rn|
options.rule_num = rn.to_i
end
opts.on("-c", "--cell-state BINARY_STRING", /^[10]+$/,
"Set the automata starting state, defaults to 1.") do |sn|
options.start_state = sn
end
opts.on("-s", "--steps NUMBER",
"Set the number of iterations, defaults to 20.") do |i|
options.iterations = i.to_i
end
opts.on_tail("-v", "--verbose",
"Turn on verbose diagnostic output.") do
options.verbose = true
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit 1
end
end
opts.parse!(ARGV)
if options.rule_num.nil?
puts "Rule number must be specified."
puts opts
exit 2
end
if options.rule_num < 0 || options.rule_num > 255
puts "Rule number must be >=0 and <= 255."
puts opts
exit 3
end
a = Automaton.new(options.rule_num, options.start_state)
if options.verbose
puts "start state = '#{options.start_state}'"
puts "rule_map:"
(0..7).each { |n| print "%03b" % n; print " " }
puts
a.rule_map.each { |n| print "%3b" % n; print " " }
puts
end
a.run(options.iterations)
end