parent
b5bfbcff0b
commit
95a6798f7f
@ -0,0 +1,104 @@
|
||||
require "forwardable"
|
||||
|
||||
DIR_DELTAS = {
|
||||
N: [-1, 0],
|
||||
W: [ 0, -1],
|
||||
E: [ 0, 1],
|
||||
S: [ 1, 0],
|
||||
}
|
||||
TILE_NEIGHBOR_DELTAS = {
|
||||
?| => "NS",
|
||||
?- => "EW",
|
||||
?L => "NE",
|
||||
?J => "NW",
|
||||
?7 => "SW",
|
||||
?F => "SE",
|
||||
?S => "NEWS",
|
||||
}.transform_values {|dirs| dirs.chars.map { DIR_DELTAS.fetch(_1.to_sym) }}
|
||||
|
||||
Tiles = Data.define(:tiles) do
|
||||
extend Forwardable
|
||||
def_delegator :tiles, :key
|
||||
def_delegator :tiles, :fetch
|
||||
def_delegator :tiles, :size
|
||||
|
||||
def neighbors(coord)
|
||||
TILE_NEIGHBOR_DELTAS.fetch(self.fetch(coord))
|
||||
.map {|delta| coord.zip(delta).map { _1 + _2 }}
|
||||
.select { tiles.has_key?(_1) }
|
||||
end
|
||||
|
||||
def to_s
|
||||
coords = tiles.keys
|
||||
y_range, x_range = *extents
|
||||
y_range.map {|y|
|
||||
x_range.map {|x| tiles.fetch([y,x], ?.) }.join
|
||||
}.join("\n")
|
||||
end
|
||||
|
||||
def extents
|
||||
y_range = Range.new(*tiles.keys.map(&:first).minmax)
|
||||
x_range = Range.new(*tiles.keys.map(&:last).minmax)
|
||||
[y_range, x_range]
|
||||
end
|
||||
end
|
||||
|
||||
tiles = ARGF.readlines(chomp: true).each.with_index.inject({}) {|tiles, (row, y)|
|
||||
tiles.merge(
|
||||
row.chars.each.with_index
|
||||
.reject {|tile,_| tile == ?. }
|
||||
.to_h {|tile,x| [[y,x], tile] }
|
||||
)
|
||||
}
|
||||
tiles = Tiles.new(tiles)
|
||||
|
||||
start = tiles.key(?S)
|
||||
seed = tiles.neighbors(start)
|
||||
.find {|candidate|
|
||||
tiles.neighbors(candidate).any? { tiles.fetch(_1) == ?S }
|
||||
}
|
||||
|
||||
loop_ = [seed]
|
||||
until loop_.last == start
|
||||
cur = loop_.last
|
||||
loop_ << tiles.neighbors(cur)
|
||||
.reject { _1 == loop_[-2] }
|
||||
.first
|
||||
end
|
||||
|
||||
# fix the start tile
|
||||
start_dirs = [seed, loop_[-2]].map {|coord| start.zip(coord).map { _2 - _1 }}
|
||||
tile = TILE_NEIGHBOR_DELTAS.find { _2.sort == start_dirs.sort }[0]
|
||||
tiles.tiles[start] = tile
|
||||
|
||||
loop_ = Tiles.new(loop_.to_h { [_1, tiles.fetch(_1)] })
|
||||
# puts loop_
|
||||
|
||||
# part one
|
||||
p loop_.size / 2
|
||||
|
||||
# part two
|
||||
y_range, x_range = *loop_.extents
|
||||
p y_range.map {|y|
|
||||
x_range.chunk_while {|x_a, x_b|
|
||||
a = loop_.fetch([y, x_a], nil)
|
||||
b = loop_.fetch([y, x_b], nil)
|
||||
|
||||
(a.nil? && b.nil?) || (a && TILE_NEIGHBOR_DELTAS.fetch(a).include?([0,1]))
|
||||
}.select {|chunk|
|
||||
# keep empty tiles
|
||||
end_tiles = chunk.values_at(0, -1).map {|x| loop_.fetch([y,x], nil) }
|
||||
next true if end_tiles.all?(&:nil?)
|
||||
|
||||
# only keep pipes that cross the horizontal axis
|
||||
deltas = end_tiles.flat_map {|tile| TILE_NEIGHBOR_DELTAS.fetch(tile) }
|
||||
[[-1,0], [1,0]].all? {|dy| deltas.include?(dy) }
|
||||
}.inject([false, 0]) {|(enclosed, count), chunk|
|
||||
start_tile = loop_.fetch([y,chunk[0]], nil)
|
||||
if start_tile.nil?
|
||||
[enclosed, count + (enclosed ? chunk.size : 0)]
|
||||
else
|
||||
[!enclosed, count]
|
||||
end
|
||||
}
|
||||
}.sum(&:last)
|
Loading…
Reference in new issue