cellular_automata 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 39fe07d2e8c8d0a1108c4cdd4bafe42016fb1814
4
- data.tar.gz: 775052c3229724fdc2aff5ec27c59c45d831c156
3
+ metadata.gz: ebba5fb93b878df9d9d9e87e16301f9df0c32cae
4
+ data.tar.gz: 505da2bb9ad0ed69bc29c8acc86f67ad7a8df745
5
5
  SHA512:
6
- metadata.gz: bd59f7522b9cc0c6695dc6f04f3f67ad227e0e4c851a7c0c2a42d113249b7d7892c0d116d1bc6f9882ca6d72fb24c9bf16d6b54d86943ad943225d60aa5078b0
7
- data.tar.gz: b9aed23d3eb5e69ad623000dfc7e04ce5722deb2ecc9c43b43a2af832f6e8a850833aafccb971f8a71b7994d01d5c524f42a998fb73c28ea9abe68b5adef4d81
6
+ metadata.gz: 2846a0d673eb8cb36ec8d30225bd7cdc5615621c05bb91f6645024e5206f06e7618f5a802966b86d70d03fb36d1c97a5b48fc261dd7bca1816cd8a4a3d41a19f
7
+ data.tar.gz: 5628a93b80ec95eca7d7ebf03b4d9f6360852da1d55e8c147c30edf8b30c8768a8d5bca3b475131ba656cb47cc7b5cf892e5e453fa1928e53d36d0d134f0b509
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # CellularAutomata
2
2
 
3
- This is yet another cellular automata implementation. First Conway's, and then
4
- we'll see where it goes.
3
+ This is yet another cellular automata implementation. Public API is liable to
4
+ break until 0.2.0.
5
5
 
6
6
  ## Installation
7
7
 
data/bin/cell CHANGED
@@ -1,5 +1,48 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'cellular_automata'
4
+ require 'optparse'
4
5
 
5
- CellularAutomata::Animator.animate
6
+ def opts_from_cli
7
+ options = {}
8
+ opt_parser = OptionParser.new do |opts|
9
+ opts.program_name = File.basename(__FILE__)
10
+ opts.banner = "#{opts.program_name} [options] RULE"
11
+ opts.on('-w WIDTH', '--width WIDTH', 'Set width') { |w| options[:width] = w.to_i }
12
+ opts.on('-h HEIGHT', '--height HEIGHT', 'Set height') { |h| options[:height] = h.to_i }
13
+ opts.on('-r REFRESH', '--refresh REFRESH', 'Set refresh rate in seconds') { |r| options[:refresh] = r.to_f }
14
+ opts.on('-v', '--version', 'Print version information') do
15
+ puts "#{File.basename(__FILE__)} #{CellularAutomata::VERSION}"
16
+ exit true
17
+ end
18
+ opts.on('--help', 'Display this screen') do
19
+ puts opts
20
+ exit true
21
+ end
22
+ end
23
+ begin
24
+ opt_parser.parse!
25
+ rescue OptionParser::InvalidOption => e
26
+ puts e.message
27
+ exit false
28
+ end
29
+ options
30
+ end
31
+
32
+ opts = opts_from_cli
33
+ opts[:width] ||= 120
34
+ opts[:height] ||= 30
35
+ opts[:refresh] ||= 0.1
36
+ rule = ARGV[0] || 'B3S2'
37
+ board = CellularAutomata::Board.new(width: opts[:width], height: opts[:height], rule: rule)
38
+
39
+ trap 'SIGINT' do
40
+ exit
41
+ end
42
+
43
+ while true do
44
+ puts "\e[H\e[2J"
45
+ board.tick!
46
+ puts board.to_s
47
+ sleep opts[:refresh]
48
+ end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["ffleming@gmail.com"]
11
11
 
12
12
  spec.summary = %q{A simulation of cellular automata}
13
- spec.description = %q{A superset of 0-player games, of which Conway's Game of Life is a member.}
13
+ spec.description = %q{A set of 0-player games, of which Conway's Game of Life is a member.}
14
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)/}) }
@@ -22,4 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1", ">= 1.8"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency 'pry', '~> 0.10'
26
+ spec.add_development_dependency 'byebug', '~> 4'
27
+ spec.add_development_dependency 'pry-byebug', '~> 3.1'
25
28
  end
@@ -1,17 +1,17 @@
1
1
  class CellularAutomata::Board
2
- attr_reader :width, :height
3
- def initialize(width: 80, height: 20)
4
- @height = height
5
- @width = width
6
- @array = build_array
7
- CellularAutomata::Cell::array = @array
2
+ attr_reader :width, :height, :rule
3
+ def initialize(rule: 'B3S2', width: 80, height: 20)
4
+ @height = height
5
+ @width = width
6
+ @state = build_array
7
+ @rule = CellularAutomata::Rule.new(rule)
8
8
  seed!
9
9
  end
10
10
 
11
11
  def to_s
12
12
  line = '+' << ('-' * width) << "+\n"
13
13
  ret = '' << line
14
- @array.each do |row|
14
+ @state.each do |row|
15
15
  ret << "|"
16
16
  row.each do |cell|
17
17
  ret << cell.to_s
@@ -21,56 +21,56 @@ class CellularAutomata::Board
21
21
  ret << line
22
22
  end
23
23
 
24
- def cycle!
24
+ def tick!
25
+ next_state = Marshal.load(Marshal.dump @state)
25
26
  each_cell do |cell|
26
- case cell.live_neighbors.length
27
- when 0..1
28
- cell.die!
29
- when 3
30
- cell.live!
31
- when 4..8
32
- cell.die!
33
- end
34
- end
35
- end
36
-
37
- def animate(steps=1000, refresh=0.1)
38
- (1..steps).each do |i|
39
- puts "\e[H\e[2J"
40
- cycle!
41
- puts self.to_s
42
- sleep refresh
27
+ next_state[cell.y][cell.x].send rule.process(neighbor_population_of cell) #= next_cell #cell.send(rule.process(adj_pop))
43
28
  end
29
+ @state = next_state
44
30
  end
45
31
 
46
32
  private
47
33
 
48
34
  def each_cell
49
- (0..height-1).each do |row|
50
- (0..width-1).each do |col|
51
- yield @array[row][col]
35
+ (0..height-1).each do |y|
36
+ (0..width-1).each do |x|
37
+ yield @state[y][x]
52
38
  end
53
39
  end
54
-
55
40
  end
56
41
 
57
42
  def seed!
58
- (0..height-1).each do |row|
59
- (0..width-1).each do |col|
60
- @array[row][col].live! if rand < 0.2
61
- end
62
- end
43
+ each_cell { |c| c.live! if rand < 0.1 }
63
44
  end
64
45
 
65
46
  def build_array
66
47
  arr = []
67
- (0..height-1).each do |i|
68
- arr[i] = []
69
- (0..width-1).each do |j|
70
- arr[i][j] = CellularAutomata::Cell.new(row: i, column: j)
48
+ (0..height-1).each do |y|
49
+ arr[y] = []
50
+ (0..width-1).each do |x|
51
+ arr[y][x] = CellularAutomata::Cell.new(row: y, column: x, alive: false)
71
52
  end
72
53
  end
73
54
  return arr
74
55
  end
56
+
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
73
+ end
74
+
75
75
  end
76
76
 
@@ -1,31 +1,12 @@
1
1
  class CellularAutomata::Cell
2
- class << self
3
- attr_accessor :array
4
- end
5
-
6
- attr_accessor :row, :column
7
- attr_reader :alive
2
+ attr_reader :alive, :row, :column
8
3
  alias x column
9
- alias x= column=
10
4
  alias y row
11
- alias y= row=
12
5
  alias alive? alive
13
- def initialize(row: , column: )
6
+ def initialize(alive: false, row: , column:)
7
+ @alive = alive
14
8
  @row = row
15
9
  @column = column
16
- @alive = false
17
- end
18
-
19
- def die!
20
- @alive = false
21
- end
22
-
23
- def live!
24
- @alive = true
25
- end
26
-
27
- def dead?
28
- !alive?
29
10
  end
30
11
 
31
12
  def to_s
@@ -33,60 +14,22 @@ class CellularAutomata::Cell
33
14
  '*'
34
15
  end
35
16
 
36
- def live_neighbors
37
- neighbors.select {|n| n.alive? }
38
- end
39
-
40
- private
41
-
42
- def neighbors
43
- [
44
- n_neighbor,
45
- ne_neighbor,
46
- e_neighbor,
47
- se_neighbor,
48
- s_neighbor,
49
- sw_neighbor,
50
- w_neighbor,
51
- nw_neighbor
52
- ].compact
53
- end
54
-
55
- def n_neighbor
56
- neighbor(y-1, x)
57
- end
58
-
59
- def ne_neighbor
60
- neighbor(y-1, x+1)
61
- end
62
-
63
- def e_neighbor
64
- neighbor(y, x+1)
65
- end
66
-
67
- def se_neighbor
68
- neighbor(y+1, x+1)
69
- end
70
-
71
- def s_neighbor
72
- neighbor(y+1, x)
17
+ def live!
18
+ @alive = true
73
19
  end
74
20
 
75
- def sw_neighbor
76
- neighbor(y+1, x-1)
21
+ def die!
22
+ @alive = false
77
23
  end
78
24
 
79
- def w_neighbor
80
- neighbor(y, x+1)
25
+ def survive!
81
26
  end
82
27
 
83
- def nw_neighbor
84
- neighbor(y-1, x-1)
28
+ def dead?
29
+ !alive?
85
30
  end
86
31
 
87
- def neighbor(r, c)
88
- raise StandardError.new("Cell::array not initialized") if CellularAutomata::Cell::array.nil?
89
- return nil if r < 0 || c < 0
90
- return CellularAutomata::Cell::array[r][c] rescue nil
32
+ def copy
33
+ self.class.new(alive: alive?, row: row, column: column)
91
34
  end
92
35
  end
@@ -0,0 +1,27 @@
1
+ class CellularAutomata::Rule
2
+ def initialize(rule_string)
3
+ @rule_hash = process_rule! rule_string
4
+ end
5
+
6
+ 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!
12
+ end
13
+
14
+ private
15
+
16
+ def process_rule!(rule_string)
17
+ rules = rule_string.scan(/[BS]\d+/)
18
+ raise ArgumentError.new('Invalid 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}
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,3 @@
1
1
  module CellularAutomata
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,7 +1,10 @@
1
+ require 'pry'
2
+ require 'byebug'
3
+ require 'pry-byebug'
1
4
  require "cellular_automata/version"
2
5
  require "cellular_automata/cell"
6
+ require "cellular_automata/rule"
3
7
  require "cellular_automata/board"
4
- require "cellular_automata/animator"
5
8
 
6
9
  module CellularAutomata
7
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cellular_automata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Forrest Fleming
@@ -44,13 +44,53 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '10.0'
47
- description: A superset of 0-player games, of which Conway's Game of Life is a member.
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.10'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.10'
61
+ - !ruby/object:Gem::Dependency
62
+ name: byebug
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '4'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '4'
75
+ - !ruby/object:Gem::Dependency
76
+ name: pry-byebug
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.1'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.1'
89
+ description: A set of 0-player games, of which Conway's Game of Life is a member.
48
90
  email:
49
91
  - ffleming@gmail.com
50
92
  executables:
51
93
  - cell
52
- - console
53
- - setup
54
94
  extensions: []
55
95
  extra_rdoc_files: []
56
96
  files:
@@ -61,13 +101,11 @@ files:
61
101
  - README.md
62
102
  - Rakefile
63
103
  - bin/cell
64
- - bin/console
65
- - bin/setup
66
104
  - cellular_automata.gemspec
67
105
  - lib/cellular_automata.rb
68
- - lib/cellular_automata/animator.rb
69
106
  - lib/cellular_automata/board.rb
70
107
  - lib/cellular_automata/cell.rb
108
+ - lib/cellular_automata/rule.rb
71
109
  - lib/cellular_automata/version.rb
72
110
  homepage: https://github.com/ffleming/cellular_automata
73
111
  licenses:
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "cellular_automata"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
data/bin/setup DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here
@@ -1,16 +0,0 @@
1
- module CellularAutomata::Animator
2
- class << self
3
- attr_accessor :board
4
- def board
5
- @board ||= CellularAutomata::Board.new(width: 120, height: 30)
6
- end
7
- def animate(steps=1000, refresh=0.1)
8
- (1..steps).each do
9
- puts "\e[H\e[2J"
10
- board.cycle!
11
- puts board.to_s
12
- sleep refresh
13
- end
14
- end
15
- end
16
- end