conway_deathmatch 0.3.2.5 → 0.3.3.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 +4 -4
- data/README.md +3 -3
- data/VERSION +1 -1
- data/bin/proving_ground +173 -0
- data/conway_deathmatch.gemspec +3 -1
- data/lib/conway_deathmatch/shapes/discovered.yaml +85 -0
- data/lib/conway_deathmatch/shapes.rb +16 -6
- data/test/bench_board_state.rb +8 -0
- data/test/test_board_state.rb +1 -1
- data/test/test_shapes.rb +2 -2
- metadata +5 -3
- /data/lib/conway_deathmatch/{data/shapes.yaml → shapes/classic.yaml} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37240d180a9787a7ded00f4eaed8fb4e76ae3e39
|
4
|
+
data.tar.gz: 382b541b24dfac1f0a2cbd4ba76a576922ed7aa8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 294b292a4b0442a39e213ee17661c5247969b334da9851999f4b5a770c1a95e68f22f800702950cb5da706def0082c0358ebf34ef6d180262c27ea0261ceb3fc
|
7
|
+
data.tar.gz: 3cf35cc4f6490da0d3f6dfaf55f05ad626bc9906e8533960056a049a158801310bb9df1ccc0665107a7b9d6590ade13b27e38bfb80457370142d106b95542e97
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ for space and population.
|
|
23
23
|
This project exists not to compete with CGOLTW but as a supplementary
|
24
24
|
project for exploration and learning. My initial motivation was to make a
|
25
25
|
"proving ground" for searching for simple shapes and patterns with high birth
|
26
|
-
rates for determining successful CGOLTW strategies.
|
26
|
+
rates for determining successful CGOLTW strategies.
|
27
27
|
|
28
28
|
Usage
|
29
29
|
===
|
@@ -44,14 +44,14 @@ Demo
|
|
44
44
|
|
45
45
|
# defaults to 70x40 board and an acorn shape
|
46
46
|
conway_deathmatch
|
47
|
-
|
47
|
+
|
48
48
|
# multiplayer
|
49
49
|
conway_deathmatch --one "acorn 30 30" --two "die_hard 20 10"
|
50
50
|
|
51
51
|
Available Shapes
|
52
52
|
---
|
53
53
|
|
54
|
-
[Definitions](https://github.com/rickhull/conway_deathmatch/blob/master/lib/conway_deathmatch/
|
54
|
+
[Definitions](https://github.com/rickhull/conway_deathmatch/blob/master/lib/conway_deathmatch/shapes/classic.yaml)
|
55
55
|
|
56
56
|
* acorn
|
57
57
|
* beacon
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.3.1
|
data/bin/proving_ground
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'slop'
|
4
|
+
require 'conway_deathmatch'
|
5
|
+
|
6
|
+
# process cmdline options
|
7
|
+
#
|
8
|
+
opts = Slop.parse(help: true,
|
9
|
+
banner: true,
|
10
|
+
strict: true,
|
11
|
+
optional_arguments: true) do
|
12
|
+
banner 'Usage: proving_ground [options]'
|
13
|
+
|
14
|
+
on 'w', 'width=', '[int] Board width', as: Integer
|
15
|
+
on 'height=', '[int] Board height', as: Integer
|
16
|
+
on 'n', 'num_ticks=', '[int] Max number of ticks to generate', as: Integer
|
17
|
+
on 'silent', 'Only render the final state'
|
18
|
+
on 'p', 'num_points=', '[int] Number of points to generate', as: Integer
|
19
|
+
on 'm', 'max_collisions=', '[int] Max number of collisions', as: Integer
|
20
|
+
end
|
21
|
+
|
22
|
+
width = opts[:width] || 40
|
23
|
+
height = opts[:height] || 40
|
24
|
+
n = opts[:num_ticks] || 40
|
25
|
+
p = opts[:num_points] || 5
|
26
|
+
max_c = opts[:max_collisions] || p ** 2
|
27
|
+
|
28
|
+
# answers / output
|
29
|
+
pop_final = 0
|
30
|
+
pop_final_points = []
|
31
|
+
pop_peak = 0
|
32
|
+
pop_peak_points = []
|
33
|
+
top_score = 0
|
34
|
+
top_score_points = []
|
35
|
+
|
36
|
+
def conclude!(final, final_points,
|
37
|
+
peak, peak_points,
|
38
|
+
score, score_points,
|
39
|
+
w, h)
|
40
|
+
puts
|
41
|
+
puts "final: #{final}"
|
42
|
+
puts "final_points: #{final_points}"
|
43
|
+
puts "shape_str: #{shape_str(final_points)}"
|
44
|
+
puts
|
45
|
+
puts "peak: #{peak}"
|
46
|
+
puts "peak_points: #{peak_points}"
|
47
|
+
puts "shape_str: #{shape_str(peak_points)}"
|
48
|
+
puts
|
49
|
+
puts "score: #{score}"
|
50
|
+
puts "score_points: #{score_points}"
|
51
|
+
puts "shape_str: #{shape_str(score_points)}"
|
52
|
+
|
53
|
+
exit 0
|
54
|
+
end
|
55
|
+
|
56
|
+
# choose center point
|
57
|
+
# choose next point within 2 units randomly
|
58
|
+
def generate_points(num_points, width, height)
|
59
|
+
points = [[width / 2, height / 2]]
|
60
|
+
count = 0
|
61
|
+
while points.length < num_points
|
62
|
+
raise("sanity check failed") if count > num_points * 2
|
63
|
+
count += 1
|
64
|
+
next_p = next_point(points.sample)
|
65
|
+
if next_p[0].between?(0, width - 1) and next_p[1].between?(0, height - 1)
|
66
|
+
points << next_p unless points.include?(next_p)
|
67
|
+
else
|
68
|
+
# debug
|
69
|
+
puts "#{next_p.inspect} out of bounds"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
points
|
73
|
+
end
|
74
|
+
|
75
|
+
def next_point(prev_point)
|
76
|
+
prev_point.map { |dim| random_within(dim, 2) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def random_within(x, dist)
|
80
|
+
new_x = x - dist + rand(dist * 2)
|
81
|
+
new_x += 1 if new_x >= x
|
82
|
+
new_x
|
83
|
+
end
|
84
|
+
|
85
|
+
def shape_str(points)
|
86
|
+
points.map { |point| "p #{point[0]} #{point[1]}" }.join(' ')
|
87
|
+
end
|
88
|
+
|
89
|
+
Signal.trap("INT") do
|
90
|
+
conclude!(pop_final, pop_final_points,
|
91
|
+
pop_peak, pop_peak_points,
|
92
|
+
top_score, top_score_points,
|
93
|
+
width, height)
|
94
|
+
end
|
95
|
+
|
96
|
+
include ConwayDeathmatch
|
97
|
+
ALIVE = BoardState::ALIVE
|
98
|
+
SEEN = {}
|
99
|
+
collisions = 0
|
100
|
+
|
101
|
+
loop {
|
102
|
+
# populate new board with random points
|
103
|
+
#
|
104
|
+
b = BoardState.new(width, height)
|
105
|
+
points = generate_points(p, width, height)
|
106
|
+
|
107
|
+
# have we seen these points before?
|
108
|
+
#
|
109
|
+
if SEEN[points]
|
110
|
+
collisions += 1
|
111
|
+
puts "X" * collisions
|
112
|
+
break if collisions > max_c
|
113
|
+
next
|
114
|
+
else
|
115
|
+
SEEN[points] = true
|
116
|
+
end
|
117
|
+
b.add_points(points)
|
118
|
+
|
119
|
+
# establish vars outside block
|
120
|
+
#
|
121
|
+
pop = nil
|
122
|
+
peak = 0
|
123
|
+
static_cnt = 0
|
124
|
+
score = 0
|
125
|
+
ticks = 0
|
126
|
+
|
127
|
+
# tick and track population
|
128
|
+
#
|
129
|
+
n.times { |i|
|
130
|
+
b.tick
|
131
|
+
ticks += 1
|
132
|
+
|
133
|
+
# evaluate board
|
134
|
+
#
|
135
|
+
last_pop = pop
|
136
|
+
pop = b.population[ALIVE] || 0
|
137
|
+
score += ticks * pop
|
138
|
+
peak = pop if pop > peak
|
139
|
+
|
140
|
+
# short-circuit static or (soon-to-be) empty boards
|
141
|
+
#
|
142
|
+
break if pop < 3
|
143
|
+
static_cnt = (pop == last_pop ? static_cnt + 1 : 0)
|
144
|
+
break if static_cnt > 3
|
145
|
+
}
|
146
|
+
|
147
|
+
puts "#{pop} (#{peak}) [#{score}]"
|
148
|
+
|
149
|
+
# track the highest populators
|
150
|
+
#
|
151
|
+
if pop > pop_final
|
152
|
+
pop_final = pop
|
153
|
+
pop_final_points = points
|
154
|
+
puts "\tLargest final: #{pop_final}"
|
155
|
+
end
|
156
|
+
|
157
|
+
if peak > pop_peak
|
158
|
+
pop_peak = peak
|
159
|
+
pop_peak_points = points
|
160
|
+
puts "\tLargest peak: #{pop_peak}"
|
161
|
+
end
|
162
|
+
|
163
|
+
if score > top_score
|
164
|
+
top_score = score
|
165
|
+
top_score_points = points
|
166
|
+
puts "\tLargest score: #{top_score}"
|
167
|
+
end
|
168
|
+
}
|
169
|
+
|
170
|
+
conclude!(pop_final, pop_final_points,
|
171
|
+
pop_peak, pop_peak_points,
|
172
|
+
top_score, top_score_points,
|
173
|
+
width, height)
|
data/conway_deathmatch.gemspec
CHANGED
@@ -14,8 +14,10 @@ Gem::Specification.new do |s|
|
|
14
14
|
'lib/conway_deathmatch.rb',
|
15
15
|
'lib/conway_deathmatch/board_state.rb',
|
16
16
|
'lib/conway_deathmatch/shapes.rb',
|
17
|
-
'lib/conway_deathmatch/
|
17
|
+
'lib/conway_deathmatch/shapes/classic.yaml',
|
18
|
+
'lib/conway_deathmatch/shapes/discovered.yaml',
|
18
19
|
'bin/conway_deathmatch',
|
20
|
+
'bin/proving_ground',
|
19
21
|
'test/bench_board_state.rb',
|
20
22
|
'test/spec_helper.rb',
|
21
23
|
'test/test_board_state.rb',
|
@@ -0,0 +1,85 @@
|
|
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
|
+
a7:
|
61
|
+
- [0, 3]
|
62
|
+
- [1, 4]
|
63
|
+
- [1, 1]
|
64
|
+
- [2, 0]
|
65
|
+
- [2, 1]
|
66
|
+
- [3, 2]
|
67
|
+
- [4, 1]
|
68
|
+
|
69
|
+
b7: # rocket
|
70
|
+
- [0, 0]
|
71
|
+
- [0, 1]
|
72
|
+
- [0, 2]
|
73
|
+
- [1, 3]
|
74
|
+
- [2, 0]
|
75
|
+
- [2, 1]
|
76
|
+
- [2, 2]
|
77
|
+
|
78
|
+
c7: # urawizardarry
|
79
|
+
- [0, 0]
|
80
|
+
- [1, 1]
|
81
|
+
- [2, 2]
|
82
|
+
- [3, 2]
|
83
|
+
- [4, 3]
|
84
|
+
- [5, 4]
|
85
|
+
- [5, 5]
|
@@ -2,9 +2,18 @@ require 'conway_deathmatch/board_state'
|
|
2
2
|
require 'yaml'
|
3
3
|
|
4
4
|
module ConwayDeathmatch::Shapes
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
def self.load_yaml(filename)
|
6
|
+
YAML.load_file(File.join(__dir__, 'shapes', filename))
|
7
|
+
end
|
8
|
+
|
9
|
+
# memoize shapes/classic.yaml
|
10
|
+
def self.classic
|
11
|
+
@@classic ||= self.load_yaml('classic.yaml')
|
12
|
+
end
|
13
|
+
|
14
|
+
# memoize shapes/discovered.yaml
|
15
|
+
def self.discovered
|
16
|
+
@@disovered ||= self.load_yaml('discovered.yaml')
|
8
17
|
end
|
9
18
|
|
10
19
|
# parse a string like "acorn 12 22 block 5 0 p 1 2 p 3 4 p 56 78"
|
@@ -12,8 +21,8 @@ module ConwayDeathmatch::Shapes
|
|
12
21
|
def self.add(board, str, val = BoardState::ALIVE)
|
13
22
|
tokens = str.split
|
14
23
|
points = []
|
15
|
-
|
16
|
-
|
24
|
+
classic = self.classic
|
25
|
+
|
17
26
|
while !tokens.empty?
|
18
27
|
shape = tokens.shift.downcase
|
19
28
|
raise "no coordinates for #{shape}" if tokens.length < 2
|
@@ -23,7 +32,8 @@ module ConwayDeathmatch::Shapes
|
|
23
32
|
when 'p'
|
24
33
|
points << [x, y]
|
25
34
|
else
|
26
|
-
|
35
|
+
found = classic[shape] || self.discovered.fetch(shape)
|
36
|
+
board.add_points(found, x, y, val)
|
27
37
|
end
|
28
38
|
end
|
29
39
|
board.add_points(points, 0, 0, val)
|
data/test/bench_board_state.rb
CHANGED
@@ -28,4 +28,12 @@ describe "BoardState#tick Benchmark" do
|
|
28
28
|
Shapes.add(b, "acorn 50 18")
|
29
29
|
n.times { b.tick }
|
30
30
|
end
|
31
|
+
|
32
|
+
bench_performance_linear "multiplayer demo", BENCH_TICK_THRESH do |n|
|
33
|
+
b = BoardState.new(70, 40)
|
34
|
+
b.multiplayer = true
|
35
|
+
Shapes.add(b, "acorn 30 30", "1")
|
36
|
+
Shapes.add(b, "die_hard 20 10", "2")
|
37
|
+
n.times { b.tick }
|
38
|
+
end
|
31
39
|
end
|
data/test/test_board_state.rb
CHANGED
@@ -36,7 +36,7 @@ describe BoardState do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it "must recognize \"#{SHAPE_STR}\"" do
|
39
|
-
Shapes.
|
39
|
+
Shapes.classic.fetch(SHAPE).each { |xy_ary|
|
40
40
|
@board.value(*xy_ary).must_equal ALIVE
|
41
41
|
}
|
42
42
|
@board.population.fetch(ALIVE).must_equal POINTS_COUNT
|
data/test/test_shapes.rb
CHANGED
@@ -2,13 +2,13 @@ require_relative './spec_helper'
|
|
2
2
|
|
3
3
|
describe Shapes do
|
4
4
|
it "must recognize #{SHAPE}" do
|
5
|
-
Shapes.
|
5
|
+
Shapes.classic.fetch(SHAPE).must_be_instance_of Array
|
6
6
|
end
|
7
7
|
|
8
8
|
it "must confirm #{SHAPE} on the board" do
|
9
9
|
@board = BoardState.new(20, 20)
|
10
10
|
Shapes.add(@board, SHAPE_STR)
|
11
|
-
Shapes.
|
11
|
+
Shapes.classic.fetch(SHAPE).each { |xy_ary|
|
12
12
|
@board.value(*xy_ary).must_equal ALIVE
|
13
13
|
}
|
14
14
|
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.3.
|
4
|
+
version: 0.3.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Hull
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: buildar
|
@@ -49,11 +49,13 @@ files:
|
|
49
49
|
- Rakefile
|
50
50
|
- VERSION
|
51
51
|
- bin/conway_deathmatch
|
52
|
+
- bin/proving_ground
|
52
53
|
- conway_deathmatch.gemspec
|
53
54
|
- lib/conway_deathmatch.rb
|
54
55
|
- lib/conway_deathmatch/board_state.rb
|
55
|
-
- lib/conway_deathmatch/data/shapes.yaml
|
56
56
|
- lib/conway_deathmatch/shapes.rb
|
57
|
+
- lib/conway_deathmatch/shapes/classic.yaml
|
58
|
+
- lib/conway_deathmatch/shapes/discovered.yaml
|
57
59
|
- test/bench_board_state.rb
|
58
60
|
- test/spec_helper.rb
|
59
61
|
- test/test_board_state.rb
|
File without changes
|