2025 day 7

This commit is contained in:
Bill Rossi 2025-12-07 07:51:28 -05:00
parent 7708169e56
commit ca03e4367b
3 changed files with 150 additions and 0 deletions

8
ruby/2025/7/bin/problem Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env ruby
require "laboratories"
lab = Laboratories.for STDIN.read.chomp
puts "Part 1: #{lab.split_count}"
puts "Part 2: #{lab.count_tachyon_lifetimes}"

View File

@ -0,0 +1,98 @@
class Laboratories
attr_reader :layers
def initialize(layers)
@layers = layers
end
def self.for(input)
new input.split("\n").map(&Layer.method(:new))
end
def split_count
layers.reduce([layers.first.blank_beams, 0]) do |acc, layer|
out = layer.split_beams acc[0]
[out[0], out[1] + acc[1]]
end[1]
end
def count_tachyon_lifetimes
@memo = {}
count_lifetimes layers.first.line.index("S"), 0
end
def count_lifetimes(position, layer)
return @memo["#{position}/#{layer}"] if @memo.key? "#{position}/#{layer}"
lt = if layer >= layers.count
1
else
if layers[layer].line[position] == "^"
count_lifetimes(position - 1, layer + 1) + count_lifetimes(position + 1, layer + 1)
else
count_lifetimes position, layer + 1
end
end
@memo["#{position}/#{layer}"] = lt
lt
end
class Tachyon
attr_reader :lab, :position, :layer
def initialize(lab, position, layer=0)
@lab = lab
@position = position
@layer = layer
end
def count_lifetimes
if layer >= lab.layers.count
1
else
if at_splitter?
self.class.new(lab, position - 1, layer + 1).count_lifetimes +
self.class.new(lab, position + 1, layer + 1).count_lifetimes
else
self.class.new(lab, position, layer + 1).count_lifetimes
end
end
end
def at_splitter?
lab.layers[layer].line[position] == "^"
end
end
class Layer
attr_reader :line
def initialize(line)
@line = line
end
def self.for(line)
new line.split("")
end
def blank_beams
Array.new(line.length, false)
end
def split_beams(input_beams)
split_count = 0
output = 0.upto(line.length - 1).map do |i|
if line[i] == "^"
split_count += 1 if input_beams[i]
false
elsif i > 0 && line[i - 1] == "^" && input_beams[i - 1]
true
elsif i < (line.length - 1) && line[i + 1] == "^" && input_beams[i + 1]
true
elsif line[i] == "S"
true
else
input_beams[i]
end
end
[output, split_count]
end
end
end

View File

@ -0,0 +1,44 @@
require "minitest/autorun"
require "laboratories"
class TestLaboratories < Minitest::Test
def test_split_count
lab = Laboratories.for <<-END
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
END
assert_equal(21, lab.split_count)
end
end
class TestLayer < Minitest::Test
def test_split_beams
layer = Laboratories::Layer.for(".S.")
assert_equal([[false, true, false], 0], layer.split_beams([false, false, false]))
layer = Laboratories::Layer.for("..")
assert_equal([[true, false], 0], layer.split_beams([true, false]))
layer = Laboratories::Layer.for(".^.")
assert_equal([[true, false, true], 1], layer.split_beams([false, true, false]))
layer = Laboratories::Layer.for("^.^")
assert_equal([[false, true, false], 0], layer.split_beams([false, true, false]))
assert_equal([[false, true, false], 2], layer.split_beams([true, false, true]))
end
end