cellular_automata 0.1.0 → 0.1.1

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: 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