100 lines
2 KiB
Ruby
100 lines
2 KiB
Ruby
# frozen_string_literal: true
|
|
# typed: true
|
|
|
|
require 'set'
|
|
|
|
require 'sorbet-runtime'
|
|
require 'sorbet-struct-comparable'
|
|
|
|
extend T::Sig
|
|
|
|
class Cell < T::Struct
|
|
extend T::Sig
|
|
include T::Struct::ActsAsComparable
|
|
|
|
const :r, Integer
|
|
const :c, Integer
|
|
|
|
class << self
|
|
extend T::Sig
|
|
|
|
sig { params(r: Integer, c: Integer).returns(Cell) }
|
|
def at(r, c) = Cell::new(r: r, c: c)
|
|
end
|
|
|
|
sig { returns(Cell) }
|
|
def north = Cell::at(r - 1, c)
|
|
|
|
sig { returns(Cell) }
|
|
def south = Cell::at(r + 1, c)
|
|
|
|
sig { returns(Cell) }
|
|
def west = Cell::at(r, c - 1)
|
|
|
|
sig { returns(Cell) }
|
|
def east = Cell::at(r, c + 1)
|
|
|
|
sig { returns(T::Array[Cell]) }
|
|
def neighbors = [north, south, west, east]
|
|
end
|
|
|
|
class Garden
|
|
extend T::Sig
|
|
|
|
sig { returns(Cell) }
|
|
attr_reader :start
|
|
|
|
def initialize(text)
|
|
@grid = T.let({}, T::Hash[Cell, String])
|
|
|
|
text.strip.each_line.each_with_index do |line, r|
|
|
line.strip.each_char.each_with_index do |char, c|
|
|
@grid[Cell::at(r, c)] = char
|
|
@start = Cell::at(r, c) if char == ?S
|
|
end
|
|
end
|
|
end
|
|
|
|
sig { params(cell: Cell).returns(T.nilable(String)) }
|
|
def char(cell) = @grid[cell]
|
|
|
|
sig { params(cell: Cell).returns(T::Boolean) }
|
|
def is_plot?(cell)
|
|
sym = char(cell) or return false
|
|
sym != '#'
|
|
end
|
|
end
|
|
|
|
class Gardener
|
|
extend T::Sig
|
|
|
|
sig { params(garden: Garden).void }
|
|
def initialize(garden)
|
|
@garden = garden
|
|
end
|
|
|
|
sig { params(starts: T::Set[Cell]).returns(T::Set[Cell]) }
|
|
def step_hypothetically(starts)
|
|
dests = Set::new
|
|
starts.each do |start|
|
|
dests.merge start.neighbors.select { |c| @garden.is_plot?(c) }
|
|
end
|
|
dests
|
|
end
|
|
end
|
|
|
|
sig { params(path: String).returns(Integer) }
|
|
def part1(path)
|
|
text = File.read(path)
|
|
garden = Garden::new(text)
|
|
gardener = Gardener::new(garden)
|
|
|
|
pos = Set[garden.start]
|
|
64.times do
|
|
pos = gardener.step_hypothetically(pos)
|
|
end
|
|
pos.size
|
|
end
|
|
|
|
puts part1 File.join(__dir__, 'input/test.txt')
|
|
puts part1 File.join(__dir__, 'input/day21.txt')
|