conway_deathmatch 0.6.0.1 → 0.6.2.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
- SHA1:
3
- metadata.gz: e231c26991bcf255abd1bf05004d79183d025dc8
4
- data.tar.gz: 5d96b4380756b46bd477e4e0baadeae27a9a36d3
2
+ SHA256:
3
+ metadata.gz: d20c966d1ffe3ac886d2315514779065ff4e17a3fd8c3927401eae066642bdba
4
+ data.tar.gz: de732dcf01de06570287852844cd87a6d629b448c27a73b111e4c4cc2cdcdad8
5
5
  SHA512:
6
- metadata.gz: e11495b48f8611b99287e3a77c14d2fe4fdd966c97833d1af41983694642e81729ac3740b9fcf3be1c3b60742f3f922b2562fed8276cef7ef9be367dc24edb84
7
- data.tar.gz: f4fb473dc800d24f7f82bd03af235007dd2f00db3c122e861277b8065f053cafa8852177e0167e0bc4597b582c804a92f8b2ccaffe3e39afab08c38c43bdf634
6
+ metadata.gz: 81dbf4124a1cc0a97410221405f52aad977a378f455f38eddc49896f387891731d32f37d45e0d9bf686cd8453faa6441363e20deb99affdb64c2ed8d4d372743
7
+ data.tar.gz: cce9be6dd2fb3a4dc2b047d39ec56dc14dbc81f2eb3301e4e8822ba11fefd5d3c291d187ede915fac6cf12d547fecfab4a565d88cbe3fc03cb7a7eadebd965e3
data/README.md CHANGED
@@ -1,8 +1,5 @@
1
- [![Build Status](https://travis-ci.org/rickhull/conway_deathmatch.svg?branch=master)](https://travis-ci.org/rickhull/conway_deathmatch)
1
+ [![CI Status](https://github.com/rickhull/conway_deathmatch/actions/workflows/ci.yaml/badge.svg)](https://github.com/rickhull/conway_deathmatch/actions/workflows/ci.yaml)
2
2
  [![Gem Version](https://badge.fury.io/rb/conway_deathmatch.svg)](http://badge.fury.io/rb/conway_deathmatch)
3
- [![Code Climate](https://codeclimate.com/github/rickhull/conway_deathmatch/badges/gpa.svg)](https://codeclimate.com/github/rickhull/conway_deathmatch)
4
- [![Dependency Status](https://gemnasium.com/rickhull/conway_deathmatch.svg)](https://gemnasium.com/rickhull/conway_deathmatch)
5
- [![Security Status](https://hakiri.io/github/rickhull/conway_deathmatch/master.svg)](https://hakiri.io/github/rickhull/conway_deathmatch/master)
6
3
 
7
4
  Introduction
8
5
  ===
data/Rakefile CHANGED
@@ -1,20 +1,20 @@
1
1
  require 'rake/testtask'
2
+
2
3
  desc "Run tests"
3
4
  Rake::TestTask.new do |t|
4
5
  t.name = "test"
5
- t.pattern = "test/test_*.rb"
6
- # t.warning = true
6
+ t.pattern = "test/*.rb"
7
+ t.warning = true
7
8
  end
8
9
 
9
10
  desc "Run benchmarks"
10
11
  Rake::TestTask.new do |t|
11
12
  t.name = "bench"
12
- t.pattern = "test/bench_*.rb"
13
- # t.warning = true
13
+ t.pattern = "test/bench/*.rb"
14
+ t.warning = true
14
15
  end
15
16
 
16
- task default: %w[test bench]
17
-
17
+ task default: :test
18
18
 
19
19
  #
20
20
  # METRICS
@@ -37,8 +37,8 @@ end
37
37
  begin
38
38
  require 'flay_task'
39
39
  FlayTask.new do |t|
40
- t.verbose = true
41
40
  t.dirs = ['lib']
41
+ t.verbose = true
42
42
  end
43
43
  metrics_tasks << :flay
44
44
  rescue LoadError
@@ -58,7 +58,7 @@ task code_metrics: metrics_tasks
58
58
 
59
59
 
60
60
  #
61
- # PROFILING TASKS
61
+ # PROFILING
62
62
  #
63
63
 
64
64
  desc "Show current system load"
@@ -66,29 +66,34 @@ task "loadavg" do
66
66
  puts File.read "/proc/loadavg"
67
67
  end
68
68
 
69
- rubylib = "RUBYLIB=lib"
70
- rubyprof = "ruby-prof -m1"
71
- scriptname = "bin/conway_deathmatch"
72
- scriptargs = "-n 100 -s 0 --renderfinal"
69
+ def lib_sh(cmd)
70
+ sh "RUBYLIB=lib #{cmd}"
71
+ end
72
+
73
+ def rprof_sh(script, args, rprof_args = '')
74
+ lib_sh ['ruby-prof', rprof_args, script, '--', args].join(' ')
75
+ end
76
+
77
+ rprof_args = "-m1"
78
+ xname = "bin/conway_deathmatch"
79
+ xargs = "-n 100 -s 0 --renderfinal"
73
80
 
74
81
  desc "Run ruby-prof on bin/conway_deathmatch (100 ticks)"
75
82
  task "ruby-prof" => "loadavg" do
76
- sh [rubylib, rubyprof, scriptname, '--', scriptargs].join(' ')
83
+ rprof_sh xname, xargs, rprof_args
77
84
  end
78
85
 
79
86
  desc "Run ruby-prof with --exclude-common-cycles"
80
87
  task "ruby-prof-exclude" => "ruby-prof" do
81
- sh [rubylib,
82
- rubyprof, '--exclude-common-cycles', scriptname, '--',
83
- scriptargs].join(' ')
88
+ rprof_sh xname, xargs, "#{rprof_args} --exclude-common-cycles"
84
89
  end
85
90
 
86
91
  task "no-prof" do
87
- sh [rubylib, scriptname, scriptargs].join(' ')
92
+ lib_sh [xname, xargs].join(' ')
88
93
  end
89
94
 
90
95
  #
91
- # GEM BUILD / PUBLISH TASKS
96
+ # GEM BUILD / PUBLISH
92
97
  #
93
98
 
94
99
  begin
@@ -109,4 +114,4 @@ end
109
114
  #
110
115
 
111
116
  desc "Rake tasks for travis to run"
112
- task travis: %w[test bench no-prof]
117
+ task travis: %w[test no-prof]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0.1
1
+ 0.6.2.1
@@ -1,37 +1,19 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'conway_deathmatch'
3
- s.version = File.read(File.join(__dir__, 'VERSION')).chomp
4
- s.summary = "Conway's Game of Life"
5
- s.description = "Deathmatch"
3
+ s.summary = "Conway's Game of Life, Deathmatch Edition (tm)"
4
+ s.description = "Several distinct populations competing for survival"
6
5
  s.authors = ["Rick Hull"]
7
6
  s.homepage = 'https://github.com/rickhull/conway_deathmatch'
8
7
  s.license = 'GPL'
9
- s.files = [
10
- 'conway_deathmatch.gemspec',
11
- 'VERSION',
12
- 'Rakefile',
13
- 'README.md',
14
- 'lib/conway_deathmatch.rb',
15
- 'lib/conway_deathmatch/shapes.rb',
16
- 'lib/conway_deathmatch/shapes/classic.yaml',
17
- 'lib/conway_deathmatch/shapes/discovered.yaml',
18
- 'bin/conway_deathmatch',
19
- 'bin/proving_ground',
20
- 'test/bench_grid.rb',
21
- 'test/spec_helper.rb',
22
- 'test/test_grid.rb',
23
- 'test/test_shapes.rb',
24
- ]
8
+
9
+ s.required_ruby_version = ">= 2"
10
+ s.version = File.read(File.join(__dir__, 'VERSION')).chomp
11
+
12
+ s.files = %w[conway_deathmatch.gemspec VERSION Rakefile README.md]
13
+ s.files += Dir['lib/**/*.rb']
14
+ s.files += Dir['test/**/*.rb']
15
+ s.files += Dir['bin/**/*.rb']
25
16
  s.executables = ['conway_deathmatch']
26
- s.add_runtime_dependency "slop", "~> 4.0"
27
- s.add_development_dependency "buildar", "~> 3"
28
- s.add_development_dependency "minitest", "~> 5"
29
- s.add_development_dependency "ruby-prof", "~> 0"
30
- s.add_development_dependency "flog", "~> 4.0"
31
- s.add_development_dependency "flay", "~> 2.0"
32
- s.add_development_dependency "roodi", ">= 4", "< 6"
33
17
 
34
- # uncomment and set ENV['CODE_COVERAGE']
35
- # s.add_development_dependency "simplecov", "~> 0.9.0"
36
- s.required_ruby_version = "~> 2"
18
+ s.add_runtime_dependency "slop", "~> 4.0"
37
19
  end
@@ -1,15 +1,8 @@
1
- #require 'conway_deathmatch/shapes'
2
- #require 'lager'
3
-
4
1
  # Provides a 2d array for the grid
5
2
  # Implements standard and deathmatch evaluation rules
6
3
  # Boundaries are toroidal: they wrap in each direction
7
4
  #
8
5
  class ConwayDeathmatch
9
- #extend Lager
10
- #log_to $stderr
11
- class BoundsError < RuntimeError; end
12
-
13
6
  DEAD = '.'
14
7
  ALIVE = '0'
15
8
 
@@ -27,7 +20,6 @@ class ConwayDeathmatch
27
20
  @height = height
28
21
  @grid = self.class.new_grid(width, height)
29
22
  @deathmatch = deathmatch
30
- #@lager = self.class.lager
31
23
  end
32
24
 
33
25
  # Conway's Game of Life transition rules
File without changes
data/test/grid.rb ADDED
@@ -0,0 +1,127 @@
1
+ require_relative 'helper'
2
+ require 'conway_deathmatch'
3
+
4
+ describe ConwayDeathmatch do
5
+ before do
6
+ @alive = ConwayDeathmatch::ALIVE
7
+ @dead = ConwayDeathmatch::DEAD
8
+ end
9
+
10
+ describe "an empty grid" do
11
+ before do
12
+ @x = 5
13
+ @y = 5
14
+ @grid = ConwayDeathmatch.new(@x, @y)
15
+ end
16
+
17
+ it "consists entirely of dead cells" do
18
+ expect(@grid.population[@dead]).must_equal @x * @y
19
+ expect(@grid.population.keys.length).must_equal 1
20
+ end
21
+
22
+ it "stays dead after a tick" do
23
+ expect(@grid.tick.population[@dead]).must_equal @x*@y
24
+ expect(@grid.population.keys.length).must_equal 1
25
+ end
26
+
27
+ it "can be populated by a 2x2 block" do
28
+ @grid.populate 1,1
29
+ @grid.populate 1,2
30
+ @grid.populate 2,1
31
+ @grid.populate 2,2
32
+
33
+ expect(@grid.population[@dead]).must_equal @x * @y - 4
34
+ expect(@grid.population[@alive]).must_equal 4
35
+
36
+ 0.upto(4) { |x|
37
+ 0.upto(4) { |y|
38
+ if x.between?(1, 2) and y.between?(1, 2)
39
+ expect(@grid.value(x, y)).must_equal @alive
40
+ else
41
+ expect(@grid.value(x, y)).must_equal @dead
42
+ end
43
+ }
44
+ }
45
+ end
46
+ end
47
+
48
+ describe "aggressive deathmatch" do
49
+ it "allows survivors to switch sides" do
50
+ # don't risk an infinite loop if a bug is present
51
+ 99.times {
52
+ @grid = ConwayDeathmatch.new(5, 3, :aggressive)
53
+ @grid.populate(1, 1, :team) # friendly
54
+ @grid.populate(2, 1, :team) # friendly; eventual survivor
55
+ @grid.populate(3, 1, :hostile) # enemy
56
+
57
+ @grid.tick
58
+
59
+ # exit the loop when the survivor switches sides
60
+ break if @grid.value(2, 1) == :hostile
61
+ }
62
+
63
+ # expect to fail once per 2^99 runs
64
+ expect(@grid.population.fetch(:team)).must_equal 2
65
+ expect(@grid.population.fetch(:hostile)).must_equal 1
66
+
67
+ # survivors
68
+ team = [[2, 0], [2, 2]]
69
+ hostile = [[2, 1]]
70
+
71
+ 0.upto(4) { |x|
72
+ 0.upto(2) { |y|
73
+ val = team.include?([x, y]) ? :team :
74
+ (hostile.include?([x, y]) ? :hostile : @dead)
75
+ expect(@grid.value(x, y)).must_equal(val)
76
+ }
77
+ }
78
+ end
79
+ end
80
+
81
+ describe "defensive deathmatch" do
82
+ it "won't allow survivors to switch sides" do
83
+ 16.times {
84
+ @grid = ConwayDeathmatch.new(5, 3, :defensive)
85
+ @grid.populate(1, 1, :team) # friendly
86
+ @grid.populate(2, 1, :team) # survivor
87
+ @grid.populate(3, 1, :hostile) # enemy
88
+ @grid.tick
89
+
90
+ expect(@grid.population.fetch(:team)).must_equal 3
91
+ 0.upto(4) { |x|
92
+ 0.upto(2) { |y|
93
+ if x == 2 and y.between?(0, 2)
94
+ expect(@grid.value(x, y)).must_equal :team
95
+ else
96
+ expect(@grid.value(x, y)).must_equal @dead
97
+ end
98
+ }
99
+ }
100
+ }
101
+ end
102
+ end
103
+
104
+ describe "friendly deathmatch" do
105
+ it "allows survivors even with excess hostiles nearby" do
106
+ @grid = ConwayDeathmatch.new(5, 5, :friendly)
107
+ @grid.populate(1, 2, :team) # friendly
108
+ @grid.populate(2, 2, :team) # friendly, eventual survivor
109
+ @grid.populate(3, 2, :team) # friendly
110
+ @grid.populate(2, 1, :hostile) # enemy
111
+ @grid.populate(2, 3, :hostile) # enemy
112
+ expect(@grid.population.fetch(:team)).must_equal 3
113
+ expect(@grid.population.fetch(:hostile)).must_equal 2
114
+
115
+ @grid.tick
116
+
117
+ # (2,2) alive despite 4 neighbors (2 friendly); now all else @dead
118
+ expect(@grid.population.fetch(:team)).must_equal 1
119
+ 0.upto(4) { |x|
120
+ 0.upto(4) { |y|
121
+ expect(@grid.value(x, y)).
122
+ must_equal(x == 2 && y == 2 ? :team : @dead)
123
+ }
124
+ }
125
+ end
126
+ end
127
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,50 @@
1
+ if ENV['CODE_COVERAGE'] and
2
+ !%w[false no].include?(ENV['CODE_COVERAGE'].downcase)
3
+
4
+ require 'simplecov'
5
+ require "simplecov_json_formatter"
6
+
7
+ class SimpleCov::Formatter::TextFormatter
8
+ FILENAME = 'metrics/coverage'
9
+
10
+ def format(result)
11
+ tot = result.files
12
+ rpt = ["Coverage: %0.1f%%" % tot.covered_percent,
13
+ "Strength: %0.2f" % tot.covered_strength,
14
+ " Lines: %i" % tot.lines_of_code,
15
+ " Covered: %i" % tot.covered_lines,
16
+ " N/A: %i" % tot.never_lines,
17
+ ]
18
+ if tot.missed_lines > 0
19
+ rpt << "Missed: %i" % tot.missed_lines
20
+ end
21
+ if tot.skipped_lines > 0
22
+ rpt << "Skipped: %i" % tot.skipped_lines
23
+ end
24
+ rpt << result.files.map { |sfile|
25
+ "%i%% (%i/%i)\t%s" % [sfile.covered_percent,
26
+ sfile.covered_lines.length,
27
+ sfile.lines_of_code,
28
+ sfile.filename]
29
+ }.join("\n")
30
+ rpt = rpt.join("\n")
31
+
32
+ puts
33
+ puts rpt
34
+ if File.writable?(FILENAME)
35
+ File.open(FILENAME, 'w') { |f|
36
+ f.write(rpt + "\n")
37
+ }
38
+ puts "wrote #{FILENAME}"
39
+ end
40
+ end
41
+ end
42
+
43
+ SimpleCov.formatters = [
44
+ SimpleCov::Formatter::TextFormatter,
45
+ SimpleCov::Formatter::JSONFormatter,
46
+ ]
47
+
48
+ SimpleCov.start
49
+ end
50
+ require 'minitest/autorun'
data/test/shapes.rb ADDED
@@ -0,0 +1,9 @@
1
+ require_relative 'helper'
2
+ require 'conway_deathmatch/shapes'
3
+
4
+ describe ConwayDeathmatch::Shapes do
5
+ it "recognizes acorn" do
6
+ expect(ConwayDeathmatch::Shapes.classic.fetch("acorn")).
7
+ must_be_instance_of Array
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ require_relative 'helper'
2
+ require 'conway_deathmatch'
3
+ require 'conway_deathmatch/shapes'
4
+
5
+ describe "Shapes on the grid" do
6
+ before do
7
+ @alive = ConwayDeathmatch::ALIVE
8
+ @grid = ConwayDeathmatch.new(20, 20)
9
+ ConwayDeathmatch::Shapes.add(@grid, "acorn 0 0")
10
+ end
11
+
12
+ it "recognizes \"acorn 0 0\"" do
13
+ ConwayDeathmatch::Shapes.classic.fetch("acorn").each { |xy_ary|
14
+ expect(@grid.value(*xy_ary)).must_equal @alive
15
+ }
16
+ expect(@grid.population.fetch(@alive)).must_equal 7
17
+ end
18
+
19
+ it "ticks correctly" do
20
+ @grid.tick
21
+ new_points = [
22
+ [0, 1],
23
+ [1, 1],
24
+ [2, 1],
25
+ [4, 1],
26
+ [4, 2],
27
+ [5, 1],
28
+ [5, 2],
29
+ [5, 3],
30
+ ].each { |xy_ary|
31
+ expect(@grid.value(*xy_ary)).must_equal @alive
32
+ }
33
+ expect(@grid.population.fetch(@alive)).must_equal new_points.length
34
+ end
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conway_deathmatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.1
4
+ version: 0.6.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-11 00:00:00.000000000 Z
11
+ date: 1980-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -24,98 +24,8 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
- - !ruby/object:Gem::Dependency
28
- name: buildar
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '3'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '3'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '5'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '5'
55
- - !ruby/object:Gem::Dependency
56
- name: ruby-prof
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: flog
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '4.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '4.0'
83
- - !ruby/object:Gem::Dependency
84
- name: flay
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '2.0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '2.0'
97
- - !ruby/object:Gem::Dependency
98
- name: roodi
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '4'
104
- - - "<"
105
- - !ruby/object:Gem::Version
106
- version: '6'
107
- type: :development
108
- prerelease: false
109
- version_requirements: !ruby/object:Gem::Requirement
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- version: '4'
114
- - - "<"
115
- - !ruby/object:Gem::Version
116
- version: '6'
117
- description: Deathmatch
118
- email:
27
+ description: Several distinct populations competing for survival
28
+ email:
119
29
  executables:
120
30
  - conway_deathmatch
121
31
  extensions: []
@@ -125,27 +35,25 @@ files:
125
35
  - Rakefile
126
36
  - VERSION
127
37
  - bin/conway_deathmatch
128
- - bin/proving_ground
129
38
  - conway_deathmatch.gemspec
130
39
  - lib/conway_deathmatch.rb
131
40
  - lib/conway_deathmatch/shapes.rb
132
- - lib/conway_deathmatch/shapes/classic.yaml
133
- - lib/conway_deathmatch/shapes/discovered.yaml
134
- - test/bench_grid.rb
135
- - test/spec_helper.rb
136
- - test/test_grid.rb
137
- - test/test_shapes.rb
41
+ - test/bench/grid.rb
42
+ - test/grid.rb
43
+ - test/helper.rb
44
+ - test/shapes.rb
45
+ - test/shapes_on_grid.rb
138
46
  homepage: https://github.com/rickhull/conway_deathmatch
139
47
  licenses:
140
48
  - GPL
141
49
  metadata: {}
142
- post_install_message:
50
+ post_install_message:
143
51
  rdoc_options: []
144
52
  require_paths:
145
53
  - lib
146
54
  required_ruby_version: !ruby/object:Gem::Requirement
147
55
  requirements:
148
- - - "~>"
56
+ - - ">="
149
57
  - !ruby/object:Gem::Version
150
58
  version: '2'
151
59
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -154,9 +62,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
62
  - !ruby/object:Gem::Version
155
63
  version: '0'
156
64
  requirements: []
157
- rubyforge_project:
158
- rubygems_version: 2.6.8
159
- signing_key:
65
+ rubygems_version: 3.4.4
66
+ signing_key:
160
67
  specification_version: 4
161
- summary: Conway's Game of Life
68
+ summary: Conway's Game of Life, Deathmatch Edition (tm)
162
69
  test_files: []
data/bin/proving_ground DELETED
@@ -1,136 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'set'
4
- require 'slop'
5
- require 'conway_deathmatch'
6
- require 'conway_deathmatch/shapes'
7
-
8
- # process cmdline options
9
- #
10
- opts = Slop.parse do |o|
11
- o.banner = "Usage: proving_ground [options]"
12
- o.int '-w', '--width', 'Grid width'
13
- o.int '--height', 'Grid height'
14
- o.int '-n', '--num_ticks', 'Max number of ticks to generate'
15
- o.int '-p', '--num_points', 'Number of points to generate'
16
- o.int '-m', '--max_collisions', 'Max number of generation collisions'
17
- o.on '-h', '--help' do
18
- puts o
19
- exit
20
- end
21
- end
22
-
23
- num_points = opts[:num_points] || 5
24
- width = opts[:width] || num_points * 5
25
- height = opts[:height] || num_points * 5
26
- num_ticks = opts[:num_ticks] || num_points * 5
27
- max_c = opts[:max_collisions] || num_points ** 2
28
-
29
- # choose center point
30
- # choose next point within 2 units randomly
31
- def generate_points(num_points, width, height)
32
- points = [[width / 2, height / 2]]
33
- count = 0
34
- while points.length < num_points
35
- raise("sanity check failed") if count > num_points * 2
36
- count += 1
37
- next_p = next_point(points.sample)
38
- if next_p[0].between?(0, width - 1) and next_p[1].between?(0, height - 1)
39
- points << next_p unless points.include?(next_p)
40
- else
41
- # debug
42
- puts "#{next_p.inspect} out of bounds"
43
- end
44
- end
45
- points
46
- end
47
-
48
- def next_point(prev_point)
49
- prev_point.map { |dim| random_within(dim, 2) }
50
- end
51
-
52
- def random_within(x, dist)
53
- new_x = x - dist + rand(dist * 2)
54
- new_x += 1 if new_x >= x
55
- new_x
56
- end
57
-
58
- def shape_str(points)
59
- points.map { |point| "p #{point[0]} #{point[1]}" }.join(' ')
60
- end
61
-
62
- def conclude!(results, w, h)
63
- results.each { |k, res|
64
- puts "#{k} population: #{res[0]}"
65
- puts "shape_str: #{shape_str(res[1])}"
66
- puts
67
- }
68
- puts "Grid: #{w}x#{h}"
69
-
70
- exit 0
71
- end
72
-
73
- results = { final: [0, []], peak: [0, []], score: [0, []], }
74
- seen = Set.new
75
- collisions = 0
76
-
77
- Signal.trap("INT") { conclude!(results, width, height) }
78
-
79
- loop {
80
- # generate a random shape
81
- points = generate_points(num_points, width, height)
82
-
83
- # have we seen these points before?
84
- hsh = points.hash
85
- if seen.member? hsh
86
- collisions += 1
87
- puts "X" * collisions
88
- break if collisions > max_c # exit the loop, stop generating points
89
- next
90
- end
91
- seen << hsh
92
-
93
- # initialize grid with generated shape
94
- b = ConwayDeathmatch.new(width, height)
95
- b.add_points(points)
96
-
97
- current = peak = score = 0 # track population (results)
98
- static_count = 0 # detect a stabilized grid
99
-
100
- # iterate the game of life
101
- num_ticks.times { |i|
102
- b.tick
103
-
104
- # evaluate grid
105
- last = current
106
- current = b.population[ConwayDeathmatch::ALIVE]
107
- peak = current if current > peak
108
- score += current * i
109
-
110
- # cease ticks for static or (soon-to-be) empty grids
111
- break if current < 3
112
- static_count = (current == last ? static_count + 1 : 0)
113
- break if static_count > 3
114
- }
115
-
116
- puts "#{current} (#{peak}) [#{score}]"
117
-
118
- # track the highest populators
119
- #
120
- if current > results[:final][0]
121
- results[:final] = [current, points]
122
- puts "\tLargest final: #{current}"
123
- end
124
-
125
- if peak > results[:peak][0]
126
- results[:peak] = [peak, points]
127
- puts "\tLargest peak: #{peak}"
128
- end
129
-
130
- if score > results[:score][0]
131
- results[:score] = [score, points]
132
- puts "\tLargest score: #{score}"
133
- end
134
- }
135
-
136
- conclude!(results, width, height)
@@ -1,175 +0,0 @@
1
- acorn:
2
- - [0, 2]
3
- - [1, 0]
4
- - [1, 2]
5
- - [3, 1]
6
- - [4, 2]
7
- - [5, 2]
8
- - [6, 2]
9
-
10
- beacon:
11
- - [0, 0]
12
- - [0, 1]
13
- - [1, 0]
14
- - [2, 3]
15
- - [3, 2]
16
- - [3, 3]
17
-
18
- beehive:
19
- - [0, 1]
20
- - [1, 0]
21
- - [1, 2]
22
- - [2, 0]
23
- - [2, 2]
24
- - [3, 1]
25
-
26
- blinker:
27
- - [0, 1]
28
- - [1, 1]
29
- - [2, 1]
30
-
31
- block:
32
- - [0, 0]
33
- - [0, 1]
34
- - [1, 0]
35
- - [1, 1]
36
-
37
- block_engine_count:
38
- - [0, 5]
39
- - [2, 4]
40
- - [2, 5]
41
- - [4, 1]
42
- - [4, 2]
43
- - [4, 3]
44
- - [6, 0]
45
- - [6, 1]
46
- - [6, 2]
47
- - [7, 1]
48
-
49
- block_engine_space:
50
- - [0, 0]
51
- - [0, 1]
52
- - [1, 0]
53
- - [1, 3]
54
- - [2, 0]
55
- - [2, 3]
56
- - [2, 4]
57
- - [3, 2]
58
- - [4, 0]
59
- - [4, 2]
60
- - [4, 3]
61
- - [4, 4]
62
-
63
- block_engine_stripe:
64
- - [0, 0]
65
- - [1, 0]
66
- - [2, 0]
67
- - [3, 0]
68
- - [4, 0]
69
- - [5, 0]
70
- - [6, 0]
71
- - [7, 0]
72
- - [9, 0]
73
- - [10, 0]
74
- - [11, 0]
75
- - [12, 0]
76
- - [13, 0]
77
- - [17, 0]
78
- - [18, 0]
79
- - [19, 0]
80
- - [26, 0]
81
- - [27, 0]
82
- - [28, 0]
83
- - [29, 0]
84
- - [30, 0]
85
- - [31, 0]
86
- - [32, 0]
87
- - [34, 0]
88
- - [35, 0]
89
- - [36, 0]
90
- - [37, 0]
91
- - [38, 0]
92
-
93
- boat:
94
- - [0, 0]
95
- - [0, 1]
96
- - [1, 0]
97
- - [1, 2]
98
- - [2, 1]
99
-
100
- diehard:
101
- - [0, 1]
102
- - [1, 1]
103
- - [1, 2]
104
- - [5, 2]
105
- - [6, 0]
106
- - [6, 2]
107
- - [7, 2]
108
-
109
- glider:
110
- - [0, 2]
111
- - [1, 0]
112
- - [1, 2]
113
- - [2, 1]
114
- - [2, 2]
115
-
116
- loaf:
117
- - [0, 1]
118
- - [1, 0]
119
- - [1, 2]
120
- - [2, 0]
121
- - [2, 3]
122
- - [3, 1]
123
- - [3, 2]
124
-
125
- lwss:
126
- - [0, 1]
127
- - [0, 3]
128
- - [1, 0]
129
- - [2, 0]
130
- - [3, 0]
131
- - [3, 3]
132
- - [4, 0]
133
- - [4, 1]
134
- - [4, 2]
135
-
136
- rpent:
137
- - [0, 1]
138
- - [1, 0]
139
- - [1, 1]
140
- - [1, 2]
141
- - [2, 0]
142
-
143
- swastika:
144
- - [0, 0]
145
- - [0, 1]
146
- - [0, 2]
147
- - [0, 3]
148
- - [0, 6]
149
- - [1, 3]
150
- - [1, 6]
151
- - [2, 3]
152
- - [2, 6]
153
- - [3, 0]
154
- - [3, 1]
155
- - [3, 2]
156
- - [3, 4]
157
- - [3, 5]
158
- - [3, 6]
159
- - [4, 0]
160
- - [4, 3]
161
- - [5, 0]
162
- - [5, 3]
163
- - [6, 0]
164
- - [6, 3]
165
- - [6, 4]
166
- - [6, 5]
167
- - [6, 6]
168
-
169
- toad:
170
- - [0, 1]
171
- - [0, 2]
172
- - [1, 3]
173
- - [2, 0]
174
- - [3, 1]
175
- - [3, 2]
@@ -1,112 +0,0 @@
1
- # discovered via proving_ground
2
- a4: # boner
3
- - [0, 2]
4
- - [1, 0]
5
- - [1, 1]
6
- - [2, 2]
7
-
8
- a5:
9
- - [0, 1]
10
- - [1, 3]
11
- - [2, 2]
12
- - [3, 0]
13
- - [3, 2]
14
-
15
- b5:
16
- - [0, 0]
17
- - [1, 0]
18
- - [1, 1]
19
- - [1, 2]
20
- - [2, 1]
21
-
22
- c5:
23
- - [0, 1]
24
- - [1, 0]
25
- - [1, 2]
26
- - [2, 2]
27
- - [3, 3]
28
-
29
- d5: # peace
30
- - [0, 2]
31
- - [1, 0]
32
- - [1, 1]
33
- - [2, 1]
34
- - [3, 0]
35
-
36
-
37
- e5: # cross (peace + 1)
38
- - [0, 1]
39
- - [1, 0]
40
- - [1, 1]
41
- - [1, 2]
42
- - [2, 1]
43
-
44
- a6: # zed
45
- - [0, 2]
46
- - [1, 0]
47
- - [1, 1]
48
- - [2, 3]
49
- - [2, 4]
50
- - [3, 2]
51
-
52
- b6: # trinary
53
- - [0, 2]
54
- - [1, 1]
55
- - [2, 2]
56
- - [2, 3]
57
- - [3, 2]
58
- - [4, 0]
59
-
60
- c6: # cardioid
61
- - [0, 0]
62
- - [0, 1]
63
- - [1, 1]
64
- - [1, 2]
65
- - [2, 0]
66
- - [2, 1]
67
-
68
- a7:
69
- - [0, 3]
70
- - [1, 4]
71
- - [1, 1]
72
- - [2, 0]
73
- - [2, 1]
74
- - [3, 2]
75
- - [4, 1]
76
-
77
- b7: # rocket
78
- - [0, 0]
79
- - [0, 1]
80
- - [0, 2]
81
- - [1, 3]
82
- - [2, 0]
83
- - [2, 1]
84
- - [2, 2]
85
-
86
- c7: # urawizardarry
87
- - [0, 0]
88
- - [1, 1]
89
- - [2, 2]
90
- - [3, 2]
91
- - [4, 3]
92
- - [5, 4]
93
- - [5, 5]
94
-
95
- d7: # A
96
- - [0, 2]
97
- - [1, 1]
98
- - [1, 3]
99
- - [2, 0]
100
- - [2, 1]
101
- - [2, 3]
102
- - [2, 4]
103
-
104
- a8: # A
105
- - [0, 2]
106
- - [1, 1]
107
- - [1, 2]
108
- - [2, 0]
109
- - [2, 1]
110
- - [3, 1]
111
- - [3, 2]
112
- - [4, 2]
data/test/spec_helper.rb DELETED
@@ -1,12 +0,0 @@
1
- if ENV['CODE_COVERAGE']
2
- require 'simplecov'
3
- SimpleCov.start
4
- end
5
-
6
- require 'minitest/autorun'
7
- require 'conway_deathmatch'
8
- require 'conway_deathmatch/shapes'
9
-
10
- ALIVE = ConwayDeathmatch::ALIVE
11
- DEAD = ConwayDeathmatch::DEAD
12
- Shapes = ConwayDeathmatch::Shapes
data/test/test_grid.rb DELETED
@@ -1,141 +0,0 @@
1
- require_relative './spec_helper'
2
-
3
- describe ConwayDeathmatch do
4
- describe "an empty grid" do
5
- before do
6
- @x = 5
7
- @y = 5
8
- @grid = ConwayDeathmatch.new(@x, @y)
9
- end
10
-
11
- it "must have dead population" do
12
- @grid.population[DEAD].must_equal @x * @y
13
- @grid.population.keys.length.must_equal 1
14
- end
15
-
16
- it "must still be dead after a tick" do
17
- @grid.tick.population[DEAD].must_equal @x*@y
18
- @grid.population.keys.length.must_equal 1
19
- end
20
-
21
- it "must accept a block" do
22
- @grid.populate 1,1
23
- @grid.populate 1,2
24
- @grid.populate 2,1
25
- @grid.populate 2,2
26
-
27
- @grid.population[DEAD].must_equal @x * @y - 4
28
- @grid.population[ALIVE].must_equal 4
29
-
30
- 0.upto(4) { |x|
31
- 0.upto(4) { |y|
32
- if x.between?(1, 2) and y.between?(1, 2)
33
- @grid.value(x, y).must_equal ALIVE
34
- else
35
- @grid.value(x, y).must_equal DEAD
36
- end
37
- }
38
- }
39
- end
40
- end
41
-
42
- describe "adding shapes" do
43
- before do
44
- @grid = ConwayDeathmatch.new(40, 40)
45
- Shapes.add(@grid, "acorn 0 0")
46
- end
47
-
48
- it "must recognize \"acorn 0 0\"" do
49
- Shapes.classic.fetch("acorn").each { |xy_ary|
50
- @grid.value(*xy_ary).must_equal ALIVE
51
- }
52
- @grid.population.fetch(ALIVE).must_equal 7
53
- end
54
-
55
- it "must tick correctly" do
56
- @grid.tick
57
- new_points = [
58
- [0, 1],
59
- [1, 1],
60
- [2, 1],
61
- [4, 1],
62
- [4, 2],
63
- [5, 1],
64
- [5, 2],
65
- [5, 3],
66
- ].each { |xy_ary|
67
- @grid.value(*xy_ary).must_equal ALIVE
68
- }
69
- @grid.population.fetch(ALIVE).must_equal new_points.length
70
- end
71
- end
72
-
73
- describe "aggressive deathmatch" do
74
- it "must allow survivors to switch sides" do
75
- 32.times {
76
- @grid = ConwayDeathmatch.new(5, 3, :aggressive)
77
- @grid.populate(1, 1, '1') # friendly
78
- @grid.populate(2, 1, '1') # survivor
79
- @grid.populate(3, 1, '2') # enemy
80
-
81
- @grid.tick
82
- break if @grid.value(2, 1) == '2'
83
- }
84
-
85
- @grid.population.fetch('1').must_equal 2
86
- @grid.population.fetch('2').must_equal 1
87
- 0.upto(4) { |x|
88
- 0.upto(2) { |y|
89
- if x == 2 and y.between?(0, 2)
90
- @grid.value(x, y).must_equal(y == 1 ? '2' : '1')
91
- else
92
- @grid.value(x, y).must_equal DEAD
93
- end
94
- }
95
- }
96
- end
97
- end
98
-
99
- describe "defensive deathmatch" do
100
- it "must not allow survivors to switch sides" do
101
- 16.times {
102
- @grid = ConwayDeathmatch.new(5, 3, :defensive)
103
- @grid.populate(1, 1, '1') # friendly
104
- @grid.populate(2, 1, '1') # survivor
105
- @grid.populate(3, 1, '2') # enemy
106
- @grid.tick
107
-
108
- @grid.population.fetch('1').must_equal 3
109
- 0.upto(4) { |x|
110
- 0.upto(2) { |y|
111
- if x == 2 and y.between?(0, 2)
112
- @grid.value(x, y).must_equal '1'
113
- else
114
- @grid.value(x, y).must_equal DEAD
115
- end
116
- }
117
- }
118
- }
119
- end
120
- end
121
-
122
- describe "friendly deathmatch" do
123
- it "must allow survivors with excess hostiles nearby" do
124
- @grid = ConwayDeathmatch.new(5, 5, :friendly)
125
- @grid.populate(1, 2, '1') # friendly
126
- @grid.populate(2, 2, '1') # survivor
127
- @grid.populate(3, 2, '1') # friendly
128
- @grid.populate(2, 1, '2') # enemy
129
- @grid.populate(2, 3, '2') # enemy
130
- @grid.tick
131
-
132
- @grid.population.fetch('1').must_equal 1
133
- # (2,2) alive despite 4 neighbors, only 2 friendly; all else DEAD
134
- 0.upto(4) { |x|
135
- 0.upto(4) { |y|
136
- @grid.value(x, y).must_equal (x == 2 && y == 2 ? '1' : DEAD)
137
- }
138
- }
139
- end
140
- end
141
- end
data/test/test_shapes.rb DELETED
@@ -1,15 +0,0 @@
1
- require_relative './spec_helper'
2
-
3
- describe Shapes do
4
- it "must recognize acorn" do
5
- Shapes.classic.fetch("acorn").must_be_instance_of Array
6
- end
7
-
8
- it "must confirm acorn on the grid" do
9
- @grid = ConwayDeathmatch.new(20, 20)
10
- Shapes.add(@grid, "acorn 0 0")
11
- Shapes.classic.fetch("acorn").each { |xy_ary|
12
- @grid.value(*xy_ary).must_equal ALIVE
13
- }
14
- end
15
- end