cellular_automata 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 891c6c36e259e19ad44dad69cdfef0336058978a
4
- data.tar.gz: 4e5898cdadcdc8031601e70f4da409b8157fdbb1
3
+ metadata.gz: 0237b3c22f9d23179fc50a5c88bc5217ce95025e
4
+ data.tar.gz: 93bcb9d782c3ec0643fdee8b9e04d0de01c62a3c
5
5
  SHA512:
6
- metadata.gz: 4e7ae0a28aecd0030faefaa03fefe2671ed7d0a1e477190d48506c2178d5a5e9a9322e827fa3f52b21bd4024370ffc2b6448bc8741f49b0fdc4f7a705d6d632e
7
- data.tar.gz: e59aaed8f24f32467b4c069c3df8a40e458d64cb872703f17c553933ec6a469a2b1f1696598dc7bb48dadf4425abd335f1f96929abb39cdbd9e1e2db7ec6f26a
6
+ metadata.gz: b0ae054a68622f16753da6ca3968a20c64af2ea6af76a342a5223f10f435553cc71be98315f607b92f159cf7e29eb435411253f5a626dc13e96d9ba8855ab8f9
7
+ data.tar.gz: dc06e35c815e74eeed6ba5048f352410937d8b51e67d827d7f7b3112c83cc087d3196f5910e357900fd61693d1f9227734cb316652be05de7c3fabe0f976acd7
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  *.gem
11
+ /lib/*.bundle
data/Rakefile CHANGED
@@ -1 +1,4 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+ spec = Gem::Specification.load('cellular_automata.gemspec')
4
+ Rake::ExtensionTask.new('cellular_c', spec)
data/bin/cell_console ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'cellular_automata'
4
+ require 'optparse'
5
+ require 'byebug'
6
+ require 'pry'
7
+
8
+ width = 120
9
+ height = 30
10
+ rule = 'B3S2'
11
+ board = CellularAutomata::Board.new(width: width, height: height, rule: rule)
12
+ board.tick!
13
+ board.tick!
14
+ puts board.to_s
15
+ state = board.state
16
+ binding.pry
17
+ exit
data/bin/cell_gif ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'cellular_automata'
4
+ require 'optparse'
5
+ require 'gosu'
6
+
7
+ def opts_from_cli
8
+ options = {}
9
+ opt_parser = OptionParser.new do |opts|
10
+ opts.program_name = File.basename(__FILE__)
11
+ opts.banner = "#{opts.program_name} [options] RULE"
12
+ opts.on('-w WIDTH', '--width WIDTH', 'Set width') { |w| options[:width] = w.to_i }
13
+ opts.on('-h HEIGHT', '--height HEIGHT', 'Set height') { |h| options[:height] = h.to_i }
14
+ opts.on('-s SCALE', '--scale SCALE', 'Factor by which to scale game board') { |s| options[:scale] = s.to_i }
15
+ opts.on('-c WIDTH', '--cell-width WIDTH', 'Factor by which to scale cells', 'Use 1 for an \'LED\' look',
16
+ 'Use 2 for no borders around cells', 'or choose anything in between') {|w| options[:cell_scale] = w.to_f }
17
+ opts.on('-f FRAMES', '--frames FRAMES', 'Number of frames to write') { |f| options[:frames] = f.to_i }
18
+ opts.on('-v', '--version', 'Print version information') do
19
+ puts "#{File.basename(__FILE__)} #{CellularAutomata::VERSION}"
20
+ exit true
21
+ end
22
+ opts.on('--help', 'Display this screen') do
23
+ puts opts
24
+ exit true
25
+ end
26
+ end
27
+ begin
28
+ opt_parser.parse!
29
+ rescue OptionParser::InvalidOption => e
30
+ puts e.message
31
+ exit false
32
+ end
33
+ options
34
+ end
35
+
36
+ opts = opts_from_cli
37
+ opts[:width] ||= 160
38
+ opts[:height] ||= 120
39
+ opts[:scale] ||= 1
40
+ opts[:cell_scale] ||= 2.0
41
+ opts[:cell_scale] = 2.0 if opts[:cell_scale] > 2.0
42
+ opts[:cell_scale] = 1.0 if opts[:cell_scale] < 1.0
43
+ opts[:frames] ||= 100
44
+ rule = ARGV[0] || 'B3S2'
45
+ opts[:rule] = rule
46
+
47
+ trap 'SIGINT' do
48
+ exit
49
+ end
50
+
51
+ CellularAutomata::GifWriter.write(opts)
52
+ exit
@@ -4,26 +4,29 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'cellular_automata/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = 'cellular_automata'
7
+ spec.name = "cellular_automata"
8
8
  spec.version = CellularAutomata::VERSION
9
- spec.authors = ['Forrest Fleming']
10
- spec.email = ['ffleming@gmail.com']
9
+ spec.authors = ["Forrest Fleming"]
10
+ spec.email = ["ffleming@gmail.com"]
11
11
 
12
12
  spec.summary = %q{A simulation of cellular automata}
13
13
  spec.description = %q{A set of 0-player games, of which Conway's Game of Life is a member.}
14
- spec.homepage = 'https://github.com/ffleming/cellular_automata'
14
+ spec.homepage = "https://github.com/ffleming/cellular_automata"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
- spec.bindir = 'bin'
17
+ spec.bindir = "bin"
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
- spec.require_paths = ['lib']
19
+ spec.require_paths = ["lib"]
20
20
 
21
21
  spec.license = 'MIT'
22
22
 
23
- spec.add_runtime_dependency 'gosu', '~> 0.9'
24
- spec.add_development_dependency 'releasy', '~> 1', '>= 1.8'
25
- spec.add_development_dependency 'bundler', '~> 1', '>= 1.8'
26
- spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.extensions << 'ext/cellular_c/extconf.rb'
24
+
25
+ spec.add_runtime_dependency "gosu", '~> 0', '>= 0.9'
26
+ spec.add_runtime_dependency "rmagick", '~> 2', '>= 2.15'
27
+ spec.add_development_dependency "bundler", "~> 1", ">= 1.8"
28
+ spec.add_development_dependency "rake-compiler", '~> 0', '>= 0.9'
29
+ spec.add_development_dependency "rake", "~> 10.0"
27
30
  spec.add_development_dependency 'pry', '~> 0.10'
28
31
  spec.add_development_dependency 'byebug', '~> 4'
29
32
  spec.add_development_dependency 'pry-byebug', '~> 3.1'
@@ -0,0 +1,76 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+
4
+ VALUE CellularC = Qnil;
5
+ void Init_cellular_c();
6
+ int cell_value(VALUE, int);
7
+ int neighbor_population_of(VALUE, int, int);
8
+ VALUE method_dup_state(VALUE, VALUE);
9
+ VALUE method_next_state(VALUE, VALUE, VALUE);
10
+
11
+ void Init_cellular_c() {
12
+ CellularC = rb_define_module("CellularC");
13
+ rb_define_singleton_method(CellularC, "dup_state", method_dup_state, 1);
14
+ rb_define_singleton_method(CellularC, "next_state", method_next_state, 2);
15
+ }
16
+
17
+ int cell_value(VALUE rule, int num_neighbors) {
18
+ VALUE rule_array = rb_iv_get(rule, "@rule_array");
19
+ VALUE result = rb_ary_entry(rule_array, num_neighbors);
20
+ VALUE live = ID2SYM(rb_intern("birth"));
21
+ VALUE die = ID2SYM(rb_intern("die"));
22
+ if(result == die) {
23
+ return 0;
24
+ } else if(result == live) {
25
+ return 1;
26
+ }
27
+ return -1;
28
+ }
29
+
30
+ int neighbor_population_of(VALUE state, int x, int y) {
31
+ int height = (int)RARRAY_LEN(state);
32
+ int width = (int)RARRAY_LEN(rb_ary_entry(state, 0));
33
+ int min_x = x > 1 ? x - 1 : 0;
34
+ int max_x = x < width - 2 ? x + 1 : width - 1;
35
+ int min_y = y > 1 ? y - 1 : 0;
36
+ int max_y = y < height - 2 ? y + 1 : height - 1;
37
+ int ret = 0;
38
+
39
+ for(int row = min_y; row <= max_y; row++) {
40
+ VALUE row_array = rb_ary_entry(state, row);
41
+ for(int col = min_x; col <= max_x; col++) {
42
+ int alive = FIX2INT(rb_ary_entry(row_array, col));
43
+ if((alive == 1) && ((x != col) || (y != row))) {
44
+ ret += 1;
45
+ }
46
+ }
47
+ }
48
+ return ret;
49
+ }
50
+
51
+ VALUE method_next_state(VALUE self, VALUE state, VALUE rule) {
52
+ VALUE next_state = method_dup_state(self, state);
53
+ int height = (int)RARRAY_LEN(state);
54
+ int width = (int)RARRAY_LEN(rb_ary_entry(state, 0));
55
+ for(int row = 0; row < height; row++) {
56
+ VALUE row_array = rb_ary_entry(next_state, row);
57
+ for(int col = 0; col < width; col++) {
58
+ int new_value = cell_value(rule, neighbor_population_of(state, col, row));
59
+ if(new_value == -1) {
60
+ continue;
61
+ }
62
+ rb_ary_store(row_array, col, INT2FIX(new_value));
63
+ }
64
+ }
65
+ return next_state;
66
+ }
67
+
68
+ VALUE method_dup_state(VALUE self, VALUE state) {
69
+ int height = (int)RARRAY_LEN(state);
70
+ VALUE dup = rb_ary_new2(height);
71
+ for(int y = 0; y < height; y++) {
72
+ VALUE row = rb_ary_dup(rb_ary_entry(state, y));
73
+ rb_ary_push(dup, row);
74
+ }
75
+ return dup;
76
+ }
@@ -0,0 +1,6 @@
1
+ # ext/extconf.rb
2
+ require 'mkmf'
3
+ extension_name = 'cellular_c'
4
+ dir_config(extension_name)
5
+ create_header
6
+ create_makefile(extension_name)
@@ -1,10 +1,13 @@
1
1
  class CellularAutomata::Board
2
- attr_reader :width, :height, :rule
3
- def initialize(rule: 'B3S2', width: 80, height: 20)
2
+ attr_reader :width, :height, :rule, :history, :state
3
+ def initialize(rule: 'B3S2', width: 80, height: 20, max_history: 2)
4
4
  @height = height
5
5
  @width = width
6
6
  @state = build_array
7
7
  @rule = CellularAutomata::Rule.new(rule)
8
+ @history = []
9
+ @max_history = max_history
10
+ max_history.times { history.push build_array }
8
11
  seed!
9
12
  end
10
13
 
@@ -14,7 +17,7 @@ class CellularAutomata::Board
14
17
  @state.each do |row|
15
18
  ret << "|"
16
19
  row.each do |cell|
17
- ret << cell.to_s
20
+ ret << (cell == 0 ? ' ' : '*' )
18
21
  end
19
22
  ret << "|\n"
20
23
  end
@@ -22,17 +25,24 @@ class CellularAutomata::Board
22
25
  end
23
26
 
24
27
  def tick!
25
- next_state = Marshal.load(Marshal.dump @state)
26
- each_cell do |cell|
27
- next_state[cell.y][cell.x].send rule.process(neighbor_population_of cell) #= next_cell #cell.send(rule.process(adj_pop))
28
- end
28
+ next_state = CellularC.next_state(@state, rule)
29
+ history.unshift CellularC.dup_state(@state)
30
+ history.pop if history.length > @max_history
29
31
  @state = next_state
30
32
  end
31
33
 
34
+ def kill(array: , x: , y: )
35
+ array[y][x] = 0
36
+ end
37
+
38
+ def live(array: , x: , y: )
39
+ array[y][x] = 1
40
+ end
41
+
32
42
  def each_cell
33
43
  (0..height-1).each do |y|
34
44
  (0..width-1).each do |x|
35
- yield @state[y][x]
45
+ yield(x, y)
36
46
  end
37
47
  end
38
48
  end
@@ -40,7 +50,7 @@ class CellularAutomata::Board
40
50
  private
41
51
 
42
52
  def seed!
43
- each_cell { |c| c.live! if rand < 0.1 }
53
+ each_cell { |x, y| @state[y][x] = 1 if rand < 0.1 }
44
54
  end
45
55
 
46
56
  def build_array
@@ -48,29 +58,24 @@ class CellularAutomata::Board
48
58
  (0..height-1).each do |y|
49
59
  arr[y] = []
50
60
  (0..width-1).each do |x|
51
- arr[y][x] = CellularAutomata::Cell.new(row: y, column: x, alive: false)
61
+ arr[y][x] = 0
52
62
  end
53
63
  end
54
64
  return arr
55
65
  end
56
66
 
57
- def neighbor_population_of(cell)
58
- neighbors_of(cell).select(&:alive?).length
59
- end
60
-
61
- def cell_at(y, x)
62
- return nil if x < 0 || y < 0
63
- return nil if y > @state.length-1
64
- return nil if x > @state[0].length-1
65
- return @state[y][x]
66
- end
67
-
68
- def neighbors_of(cell)
69
- y = cell.y ; x = cell.x
70
- [ cell_at(y-1, x-1), cell_at(y-1, x ), cell_at(y-1, x+1),
71
- cell_at(y, x+1), cell_at(y , x-1),
72
- cell_at(y+1, x-1), cell_at(y+1, x ), cell_at(y+1, x+1) ].compact
67
+ def neighbor_population_of(x: , y: )
68
+ ret = 0
69
+ min_x = x > 1 ? x - 1 : 0
70
+ max_x = x < width - 2 ? x + 1 : width - 1
71
+ min_y = y > 1 ? y - 1 : 0
72
+ max_y = y < height - 2 ? y + 1 : height - 1
73
+ (min_y..max_y).each do |row|
74
+ (min_x..max_x).each do |col|
75
+ ret += 1 unless ((x == col && y == row) || @state[row][col] == 0)
76
+ end
77
+ end
78
+ ret
73
79
  end
74
-
75
80
  end
76
81
 
@@ -0,0 +1,56 @@
1
+ module CellularAutomata::GifWriter
2
+ class << self
3
+ def write(opts={})
4
+ @scale = opts[:scale]
5
+ @cell_width = scale**opts[:cell_scale]
6
+ @board = CellularAutomata::Board.new(width: opts[:width]/scale, height: opts[:height]/scale, rule: opts[:rule])
7
+ @gif = Magick::ImageList.new
8
+ @width = opts[:width]
9
+ @height = opts[:height]
10
+ @frames = opts[:frames]
11
+ write_gif('test.gif')
12
+ end
13
+
14
+ private
15
+
16
+ attr_reader :board, :scale, :cell_width, :frames, :writer, :height, :width
17
+
18
+ def write_gif(outfile)
19
+ frames.times do |i|
20
+ draw_frame
21
+ board.tick!
22
+ end
23
+ @gif.write(outfile)
24
+ end
25
+
26
+ def draw_frame
27
+ writer = Magick::Draw.new
28
+ frame = Magick::Image.new(width, height) do
29
+ self.background_color = '#000000'
30
+ end
31
+ board.each_cell do |cell|
32
+ prev_1 = board.history[0][cell.y][cell.x]
33
+ prev_2 = board.history[1][cell.y][cell.x]
34
+ color = '#000000'
35
+ if cell.alive?
36
+ color = '#FFFF00'
37
+ elsif prev_1.alive?
38
+ color = '#AAAA00'
39
+ elsif prev_2.alive?
40
+ color = '#444400'
41
+ end
42
+ writer.stroke color
43
+ writer.fill color
44
+ x1 = cell.x * scale**2
45
+ y1 = cell.y * scale**2
46
+ x2 = x1 + cell_width
47
+ y2 = y1 + cell_width
48
+ writer.rectangle(x1, y1, x2, y2)
49
+ end
50
+ writer.draw(frame)
51
+ @gif << frame
52
+ print '.'
53
+ end
54
+ end
55
+ end
56
+
@@ -14,9 +14,18 @@ class CellWindow < Gosu::Window
14
14
  end
15
15
 
16
16
  def draw
17
- board.each_cell do |cell|
18
- color = cell.alive? ? Gosu::Color::YELLOW : Gosu::Color::BLACK
19
- Gosu.draw_rect(cell.x * scale**2, cell.y * scale**2, cell_width, cell_width, color, 0, :default)
17
+ board.each_cell do |x, y|
18
+ prev_1 = board.history[0][y][x] == 1
19
+ prev_2 = board.history[1][y][x] == 1
20
+ color = Gosu::Color::BLACK
21
+ if board.state[y][x] == 1
22
+ color = Gosu::Color.argb(0xff_FFFF00)
23
+ elsif prev_1
24
+ color = Gosu::Color.argb(0xff_AAAA00)
25
+ elsif prev_2
26
+ color = Gosu::Color.argb(0xff_444400)
27
+ end
28
+ Gosu.draw_rect(x * scale**2, y * scale**2, cell_width, cell_width, color, 0, :default)
20
29
  end
21
30
  end
22
31
 
@@ -1,27 +1,24 @@
1
1
  class CellularAutomata::Rule
2
2
  def initialize(rule_string)
3
- @rule_hash = process_rule! rule_string
3
+ rules = rule_string.downcase.scan(/[bs]\d+/)
4
+ raise ArgumentError.new("Invalid rule string #{rule_string}") if rules.length != 2
5
+ birth = rules.select {|s| s.start_with?('b')}.first
6
+ survive = rules.select {|s| s.start_with?('s')}.first
7
+ @rule_array = rules_array_from birth: birth, survive: survive
4
8
  end
5
9
 
6
10
  def process(input)
7
- return @rule_hash[input] || raise(ArgumentError.new("I don't know what to do with #{input.class} #{input}"))
8
- end
9
-
10
- def process2(input)
11
- @rule_hash[input] != :die!
11
+ return @rule_array[input.to_i] || raise(ArgumentError.new("I don't know what to do with #{input.class} #{input}"))
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def process_rule!(rule_string)
17
- rules = rule_string.scan(/[BS]\d+/)
18
- raise ArgumentError.new("Invalid rule string #{rule_string}") if rules.length != 2
19
- birth_string = rules.select {|s| s.start_with?('B')}.first
20
- survive_string = rules.select {|s| s.start_with?('S')}.first
21
- (birth, survive) = [birth_string, survive_string].map { |s| s[1..-1].split('').map(&:to_i) }
22
- death = ((0..8).to_a - birth) - survive
23
- {live!: birth, survive!: survive, die!: death}.each_with_object({}) do |(k, v), ret|
24
- v.each {|int| ret[int] = k}
16
+ def rules_array_from(birth: , survive: )
17
+ ('0'..'8').each_with_object([]) do |i_str, ret|
18
+ val = :die
19
+ val = :survive if survive.include? i_str
20
+ val = :birth if birth.include? i_str
21
+ ret << val
25
22
  end
26
23
  end
27
24
  end
@@ -1,3 +1,3 @@
1
1
  module CellularAutomata
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -2,11 +2,14 @@ require 'pry'
2
2
  require 'byebug'
3
3
  require 'pry-byebug'
4
4
  require 'gosu'
5
+ require 'rmagick'
5
6
  require "cellular_automata/version"
6
7
  require "cellular_automata/cell"
7
8
  require "cellular_automata/rule"
8
9
  require "cellular_automata/board"
9
10
  require "cellular_automata/gui_window"
11
+ require "cellular_automata/gif_writer"
12
+ require 'cellular_c.bundle'
10
13
 
11
14
  module CellularAutomata
12
15
  end
metadata CHANGED
@@ -1,20 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cellular_automata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Forrest Fleming
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-24 00:00:00.000000000 Z
11
+ date: 2015-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ - - ">="
18
21
  - !ruby/object:Gem::Version
19
22
  version: '0.9'
20
23
  type: :runtime
@@ -22,28 +25,31 @@ dependencies:
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - - ">="
25
31
  - !ruby/object:Gem::Version
26
32
  version: '0.9'
27
33
  - !ruby/object:Gem::Dependency
28
- name: releasy
34
+ name: rmagick
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: '1'
39
+ version: '2'
34
40
  - - ">="
35
41
  - !ruby/object:Gem::Version
36
- version: '1.8'
37
- type: :development
42
+ version: '2.15'
43
+ type: :runtime
38
44
  prerelease: false
39
45
  version_requirements: !ruby/object:Gem::Requirement
40
46
  requirements:
41
47
  - - "~>"
42
48
  - !ruby/object:Gem::Version
43
- version: '1'
49
+ version: '2'
44
50
  - - ">="
45
51
  - !ruby/object:Gem::Version
46
- version: '1.8'
52
+ version: '2.15'
47
53
  - !ruby/object:Gem::Dependency
48
54
  name: bundler
49
55
  requirement: !ruby/object:Gem::Requirement
@@ -64,6 +70,26 @@ dependencies:
64
70
  - - ">="
65
71
  - !ruby/object:Gem::Version
66
72
  version: '1.8'
73
+ - !ruby/object:Gem::Dependency
74
+ name: rake-compiler
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0.9'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0.9'
67
93
  - !ruby/object:Gem::Dependency
68
94
  name: rake
69
95
  requirement: !ruby/object:Gem::Requirement
@@ -125,8 +151,11 @@ email:
125
151
  - ffleming@gmail.com
126
152
  executables:
127
153
  - cell
154
+ - cell_console
155
+ - cell_gif
128
156
  - cell_gui
129
- extensions: []
157
+ extensions:
158
+ - ext/cellular_c/extconf.rb
130
159
  extra_rdoc_files: []
131
160
  files:
132
161
  - ".gitignore"
@@ -136,11 +165,16 @@ files:
136
165
  - README.md
137
166
  - Rakefile
138
167
  - bin/cell
168
+ - bin/cell_console
169
+ - bin/cell_gif
139
170
  - bin/cell_gui
140
171
  - cellular_automata.gemspec
172
+ - ext/cellular_c/cellular_c.c
173
+ - ext/cellular_c/extconf.rb
141
174
  - lib/cellular_automata.rb
142
175
  - lib/cellular_automata/board.rb
143
176
  - lib/cellular_automata/cell.rb
177
+ - lib/cellular_automata/gif_writer.rb
144
178
  - lib/cellular_automata/gui_window.rb
145
179
  - lib/cellular_automata/rule.rb
146
180
  - lib/cellular_automata/version.rb
@@ -164,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
198
  version: '0'
165
199
  requirements: []
166
200
  rubyforge_project:
167
- rubygems_version: 2.2.2
201
+ rubygems_version: 2.4.7
168
202
  signing_key:
169
203
  specification_version: 4
170
204
  summary: A simulation of cellular automata