conway_deathmatch 0.3.2.5 → 0.3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|