conway_deathmatch 0.0.0.5 → 0.0.0.6
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/bin/conway_deathmatch +4 -4
- data/lib/conway_deathmatch/board_state.rb +120 -0
- data/lib/conway_deathmatch/shapes.rb +1 -1
- data/lib/conway_deathmatch.rb +2 -120
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ae468567aa50ce8646421adb6a7265142e4db03
|
4
|
+
data.tar.gz: 2e1957b0a8026de25c82b5a1d43644b082c27fe0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3445192d199b5e6d9814214fac8133c3a7ce19ee3bedb097f3c511655720fdd54dc22f98d1573e0566cb7d9724c36d0d02dce1ef3542326b7afc3a5152571e34
|
7
|
+
data.tar.gz: b513799aaac4c91675e5cd44ed95fb9a852ed6f6f12faf13354ba864c8aa597698899e9aead38bdaadd14d8676095cf83153141c54f70681a63e295d2bd04f12
|
data/bin/conway_deathmatch
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require 'slop'
|
4
|
+
require 'conway_deathmatch'
|
5
|
+
|
3
6
|
# process cmdline options
|
4
7
|
#
|
5
|
-
require 'slop'
|
6
8
|
opts = Slop.parse(help: true,
|
7
9
|
banner: true,
|
8
10
|
strict: true,
|
@@ -21,6 +23,7 @@ opts = Slop.parse(help: true,
|
|
21
23
|
on 'two=', '[str] points for population "2"'
|
22
24
|
on 'three=', '[str] points for population "3"'
|
23
25
|
end
|
26
|
+
|
24
27
|
width = opts[:width] || 70
|
25
28
|
height = opts[:height] || 40
|
26
29
|
shapes = opts[:points] || "acorn 50 18"
|
@@ -30,9 +33,6 @@ render_continuous = (n.nil? or !opts.silent?)
|
|
30
33
|
|
31
34
|
# create game
|
32
35
|
#
|
33
|
-
require 'conway_deathmatch'
|
34
|
-
require 'conway_deathmatch/shapes'
|
35
|
-
|
36
36
|
include ConwayGame
|
37
37
|
b = BoardState.new(width, height)
|
38
38
|
if opts.multiplayer? or opts[:one] or opts[:two] or opts[:three]
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module ConwayGame; end # create namespace
|
2
|
+
|
3
|
+
# data structure for the board - 2d array
|
4
|
+
# implements standard and multiplayer evaluation
|
5
|
+
# static boundaries are treated as dead
|
6
|
+
#
|
7
|
+
class ConwayGame::BoardState
|
8
|
+
class BoundsError < RuntimeError; end
|
9
|
+
|
10
|
+
DEAD = '.'
|
11
|
+
ALIVE = '0'
|
12
|
+
|
13
|
+
def self.new_state(x_len, y_len)
|
14
|
+
state = []
|
15
|
+
x_len.times { state << Array.new(y_len, DEAD) }
|
16
|
+
state
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :multiplayer
|
20
|
+
|
21
|
+
def initialize(x_len, y_len)
|
22
|
+
# ranges, yay! (exclude_end)
|
23
|
+
@xr = (0...x_len)
|
24
|
+
@yr = (0...y_len)
|
25
|
+
@state = self.class.new_state(x_len, y_len)
|
26
|
+
@multiplayer = false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Conway's Game of Life transition rules
|
30
|
+
def next_value(x, y)
|
31
|
+
n, birthright = neighbor_stats(x, y)
|
32
|
+
if alive?(x, y)
|
33
|
+
(n == 2 or n == 3) ? birthright : DEAD
|
34
|
+
else
|
35
|
+
(n == 3) ? birthright : DEAD
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def in_bounds?(x, y)
|
40
|
+
@xr.include?(x) and @yr.include?(y)
|
41
|
+
end
|
42
|
+
|
43
|
+
def in_bounds!(x, y)
|
44
|
+
raise(BoundsError, "(#{x}, #{y}) (#{@xr}, #{@yr})") unless in_bounds?(x, y)
|
45
|
+
end
|
46
|
+
|
47
|
+
# out of bounds considered dead
|
48
|
+
def alive?(x, y)
|
49
|
+
in_bounds?(x, y) and @state[x][y] != DEAD
|
50
|
+
end
|
51
|
+
|
52
|
+
# population of each neighbor
|
53
|
+
def neighbor_population(x, y)
|
54
|
+
neighbors = Hash.new(0)
|
55
|
+
(x-1..x+1).each { |xn|
|
56
|
+
(y-1..y+1).each { |yn|
|
57
|
+
if alive?(xn, yn) and !(xn == x and yn == y) # don't count self
|
58
|
+
neighbors[@state[xn][yn]] += 1
|
59
|
+
end
|
60
|
+
}
|
61
|
+
}
|
62
|
+
neighbors
|
63
|
+
end
|
64
|
+
|
65
|
+
# multiplayer, neighbor count and birthright
|
66
|
+
def neighbor_stats(x, y)
|
67
|
+
if @multiplayer
|
68
|
+
total = 0
|
69
|
+
largest = 0
|
70
|
+
birthright = nil
|
71
|
+
neighbor_population(x, y).each { |sym, cnt|
|
72
|
+
total += cnt
|
73
|
+
if cnt > largest
|
74
|
+
largest = cnt
|
75
|
+
birthright = sym
|
76
|
+
end
|
77
|
+
}
|
78
|
+
[total, birthright]
|
79
|
+
else
|
80
|
+
[neighbor_population(x, y).values.reduce(:+), ALIVE]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# generate the next state table
|
85
|
+
def tick
|
86
|
+
new_state = self.class.new_state(@xr.last, @yr.last)
|
87
|
+
@xr.each { |x| @yr.each { |y| new_state[x][y] = next_value(x, y) } }
|
88
|
+
@state = new_state
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# set a single point, raise on OOB
|
93
|
+
def populate(x, y, val = ALIVE)
|
94
|
+
in_bounds!(x, y)
|
95
|
+
@state[x][y] = val
|
96
|
+
end
|
97
|
+
|
98
|
+
# set several points (2d array), ignore OOB
|
99
|
+
def add_points(points, x_off = 0, y_off = 0, val = ALIVE)
|
100
|
+
points.each { |point|
|
101
|
+
x = point[0] + x_off
|
102
|
+
y = point[1] + y_off
|
103
|
+
@state[x][y] = val if self.in_bounds?(x, y)
|
104
|
+
}
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
# for line-based text output, iterate over y-values first (i.e. per row)
|
109
|
+
def render_text
|
110
|
+
@state.transpose.map { |row| row.join }.join("\n")
|
111
|
+
end
|
112
|
+
alias_method :render, :render_text
|
113
|
+
|
114
|
+
# full board scan
|
115
|
+
def population
|
116
|
+
population = Hash.new(0)
|
117
|
+
@state.each { |col| col.each { |val| population[val] += 1 } }
|
118
|
+
population
|
119
|
+
end
|
120
|
+
end
|
data/lib/conway_deathmatch.rb
CHANGED
@@ -1,120 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# data structure for the board - 2d array
|
4
|
-
# implements standard and multiplayer evaluation
|
5
|
-
# static boundaries are treated as dead
|
6
|
-
#
|
7
|
-
class ConwayGame::BoardState
|
8
|
-
class BoundsError < RuntimeError; end
|
9
|
-
|
10
|
-
DEAD = '.'
|
11
|
-
ALIVE = '0'
|
12
|
-
|
13
|
-
def self.new_state(x_len, y_len)
|
14
|
-
state = []
|
15
|
-
x_len.times { state << Array.new(y_len, DEAD) }
|
16
|
-
state
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_accessor :multiplayer
|
20
|
-
|
21
|
-
def initialize(x_len, y_len)
|
22
|
-
# ranges, yay! (exclude_end)
|
23
|
-
@xr = (0...x_len)
|
24
|
-
@yr = (0...y_len)
|
25
|
-
@state = self.class.new_state(x_len, y_len)
|
26
|
-
@multiplayer = false
|
27
|
-
end
|
28
|
-
|
29
|
-
# Conway's Game of Life transition rules
|
30
|
-
def next_value(x, y)
|
31
|
-
n, birthright = neighbor_stats(x, y)
|
32
|
-
if alive?(x, y)
|
33
|
-
(n == 2 or n == 3) ? birthright : DEAD
|
34
|
-
else
|
35
|
-
(n == 3) ? birthright : DEAD
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def in_bounds?(x, y)
|
40
|
-
@xr.include?(x) and @yr.include?(y)
|
41
|
-
end
|
42
|
-
|
43
|
-
def in_bounds!(x, y)
|
44
|
-
raise(BoundsError, "(#{x}, #{y}) (#{@xr}, #{@yr})") unless in_bounds?(x, y)
|
45
|
-
end
|
46
|
-
|
47
|
-
# out of bounds considered dead
|
48
|
-
def alive?(x, y)
|
49
|
-
in_bounds?(x, y) and @state[x][y] != DEAD
|
50
|
-
end
|
51
|
-
|
52
|
-
# population of each neighbor
|
53
|
-
def neighbor_population(x, y)
|
54
|
-
neighbors = Hash.new(0)
|
55
|
-
(x-1..x+1).each { |xn|
|
56
|
-
(y-1..y+1).each { |yn|
|
57
|
-
if alive?(xn, yn) and !(xn == x and yn == y) # don't count self
|
58
|
-
neighbors[@state[xn][yn]] += 1
|
59
|
-
end
|
60
|
-
}
|
61
|
-
}
|
62
|
-
neighbors
|
63
|
-
end
|
64
|
-
|
65
|
-
# multiplayer, neighbor count and birthright
|
66
|
-
def neighbor_stats(x, y)
|
67
|
-
if @multiplayer
|
68
|
-
total = 0
|
69
|
-
largest = 0
|
70
|
-
birthright = nil
|
71
|
-
neighbor_population(x, y).each { |sym, cnt|
|
72
|
-
total += cnt
|
73
|
-
if cnt > largest
|
74
|
-
largest = cnt
|
75
|
-
birthright = sym
|
76
|
-
end
|
77
|
-
}
|
78
|
-
[total, birthright]
|
79
|
-
else
|
80
|
-
[neighbor_population(x, y).values.reduce(:+), ALIVE]
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# generate the next state table
|
85
|
-
def tick
|
86
|
-
new_state = self.class.new_state(@xr.last, @yr.last)
|
87
|
-
@xr.each { |x| @yr.each { |y| new_state[x][y] = next_value(x, y) } }
|
88
|
-
@state = new_state
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
# set a single point, raise on OOB
|
93
|
-
def populate(x, y, val = ALIVE)
|
94
|
-
in_bounds!(x, y)
|
95
|
-
@state[x][y] = val
|
96
|
-
end
|
97
|
-
|
98
|
-
# set several points (2d array), ignore OOB
|
99
|
-
def add_points(points, x_off = 0, y_off = 0, val = ALIVE)
|
100
|
-
points.each { |point|
|
101
|
-
x = point[0] + x_off
|
102
|
-
y = point[1] + y_off
|
103
|
-
@state[x][y] = val if self.in_bounds?(x, y)
|
104
|
-
}
|
105
|
-
self
|
106
|
-
end
|
107
|
-
|
108
|
-
# for line-based text output, iterate over y-values first (i.e. per row)
|
109
|
-
def render_text
|
110
|
-
@state.transpose.map { |row| row.join }.join("\n")
|
111
|
-
end
|
112
|
-
alias_method :render, :render_text
|
113
|
-
|
114
|
-
# full board scan
|
115
|
-
def population
|
116
|
-
population = Hash.new(0)
|
117
|
-
@state.each { |col| col.each { |val| population[val] += 1 } }
|
118
|
-
population
|
119
|
-
end
|
120
|
-
end
|
1
|
+
require 'conway_deathmatch/board_state'
|
2
|
+
require 'conway_deathmatch/shapes'
|
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.0.0.
|
4
|
+
version: 0.0.0.6
|
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-11-
|
11
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Deathmatch
|
14
14
|
email:
|
@@ -19,6 +19,7 @@ extra_rdoc_files: []
|
|
19
19
|
files:
|
20
20
|
- bin/conway_deathmatch
|
21
21
|
- lib/conway_deathmatch.rb
|
22
|
+
- lib/conway_deathmatch/board_state.rb
|
22
23
|
- lib/conway_deathmatch/data/shapes.yaml
|
23
24
|
- lib/conway_deathmatch/shapes.rb
|
24
25
|
homepage: https://github.com/rickhull/conway_deathmatch
|