1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
require "set"
require "strscan"
def parse(line)
deltas = []
ss = StringScanner.new(line)
until ss.eos?
deltas << case
when ss.scan(/e/) then [ 1, 0]
when ss.scan(/se/) then [ 0, 1]
when ss.scan(/sw/) then [-1, 1]
when ss.scan(/w/) then [-1, 0]
when ss.scan(/nw/) then [ 0, -1]
when ss.scan(/ne/) then [ 1, -1]
else fail
end
end
deltas.inject {|c,d| c.zip(d).map {|c,d| c+d }}
end
NEIGHBORS = %w[ e se sw w nw ne ].map {|dir| parse(dir) }
def tick(tiles)
coords = Set.new(tiles.flat_map {|coord|
[
coord,
*NEIGHBORS.map {|n| coord.zip(n).map {|c,d| c+d }},
]
})
Set.new(coords.select {|coord|
live_neighbors = NEIGHBORS.map {|n| coord.zip(n).map {|c,d| c+d }}.count {|c| tiles.include?(c) }
if tiles.include?(coord)
(1..2).cover?(live_neighbors)
else
live_neighbors == 2
end
})
end
tiles = Set.new
ARGF.read.split("\n").each do |line|
tile = parse(line)
if tiles.include?(tile)
tiles.delete(tile)
else
tiles << tile
end
end
100.times do |i|
tiles = tick(tiles)
end
p tiles.size