Skip to content

Commit 9afe4c7

Browse files
committed
love a good ugly sweater puzzle
1 parent 80b865b commit 9afe4c7

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

2025/ruby/day07.rb

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
require_relative 'day'
2+
require_relative 'grid'
3+
require_relative 'ugly_sweater'
4+
5+
class Day07 < Day # >
6+
7+
# @example
8+
# day.part1 #=> 21
9+
def part1
10+
@tachy = TachyonManifold.new(input).parse
11+
@tachy.track_beam
12+
puts "\n" + @tachy.to_s if ENV['DEBUG']
13+
@tachy.beam_splits
14+
end
15+
16+
# @example
17+
# day.part1
18+
# day.part2 #=> 40
19+
def part2
20+
@tachy.timeline_splits
21+
end
22+
23+
EXAMPLE_INPUT = File.read("../inputs/day07-example-input.txt")
24+
end
25+
26+
class TachyonManifold < Grid
27+
include UglySweater
28+
29+
attr_reader :entrance, :splitter_coords, :splitters_by_row, :beams_by_row
30+
31+
def self.example
32+
new(Day07::EXAMPLE_INPUT).parse
33+
end
34+
35+
def initialize(input=nil)
36+
super
37+
@entrance = nil
38+
@splitter_coords = Set.new
39+
end
40+
41+
# @example
42+
# tachmani = new(Day07::EXAMPLE_INPUT)
43+
# tachmani.parse
44+
# tachmani.entrance #=> [0,7]
45+
# tachmani.splitter_coords #=> Set[[2, 7], [4, 6], [4, 8], [6, 5], [6, 7], [6, 9], [8, 4], [8, 6], [8, 10], [10, 3], [10, 5], [10, 9], [10, 11], [12, 2], [12, 6], [12, 12], [14, 1], [14, 3], [14, 5], [14, 7], [14, 9], [14, 13]]
46+
# tachmani.splitters_by_row[4] #=> Set[6,8]
47+
# tachmani.beams_by_row[0] #=> Set[7]
48+
def parse
49+
super { |coord, char|
50+
case char
51+
when "S" ; @entrance = coord
52+
when "^" ; @splitter_coords << coord
53+
else ; # keep calm and parse on
54+
end
55+
}
56+
57+
@beams_by_row = Array.new(@row_bounds.count) { Set.new }
58+
@beams_by_row[@entrance[0]] << @entrance[1]
59+
60+
@beam_density = Hash.new { 0 }
61+
@beam_density[@entrance] += 1
62+
63+
@splitters_by_row = Array.new(@row_bounds.count) { Set.new }
64+
@splitter_coords.each { |(r,c)|
65+
@splitters_by_row[r] << c
66+
}
67+
68+
@beam_splits = 0
69+
70+
self
71+
end
72+
73+
def track_beam
74+
@row_bounds.to_a[1..].each { |r|
75+
@beams_by_row[r-1].each { |c|
76+
if @splitters_by_row[r].include?(c)
77+
@beams_by_row[r] << c-1
78+
@beams_by_row[r] << c+1
79+
@beam_splits += 1
80+
@beam_density[[r,c-1]] += @beam_density[[r-1,c]]
81+
@beam_density[[r,c+1]] += @beam_density[[r-1,c]]
82+
else
83+
@beams_by_row[r] << c
84+
@beam_density[[r,c]] += @beam_density[[r-1,c]]
85+
end
86+
}
87+
}
88+
end
89+
90+
def beam_splits
91+
@beam_splits
92+
end
93+
94+
def timeline_splits
95+
@beam_density
96+
.filter_map {|(r,c), density| density if r == @row_bounds.max }
97+
.reduce(&:+)
98+
end
99+
100+
def to_s
101+
super { |(r,c), char|
102+
case
103+
when char == "S" ; char.make_it_green
104+
when @splitter_coords.include?([r,c]) ; char.make_it_red.make_it_bold
105+
when @beam_density[[r,c]] > 0 ; "|".make_it_green
106+
else ; char
107+
end
108+
}
109+
end
110+
111+
end

2025/ruby/ugly_sweater.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module UglySweater
2+
String.prepend(
3+
Module.new do
4+
def make_it_red
5+
"\e[41m#{self.delete_suffix("\e[0m")}\e[0m"
6+
end
7+
def make_it_green
8+
"\e[32m#{self.delete_suffix("\e[0m")}\e[0m"
9+
end
10+
def make_it_bold
11+
"\e[1m#{self.delete_suffix("\e[0m")}\e[0m"
12+
end
13+
end
14+
)
15+
# for use with outputs that are periods and octothorps
16+
def self.ugly_christmas_sweater(output = "")
17+
output.gsub(/#/, make_it_red("#")).gsub(/\./, make_it_green("."))
18+
end
19+
20+
def ugly_christmas_sweater(output)
21+
self.class.ugly_christmas_sweater(output)
22+
end
23+
24+
def self.make_it_red(s, bold: false)
25+
"\e[41m\e[1m#{s}\e[0m"
26+
end
27+
28+
def self.make_it_green(s)
29+
"\e[32m#{s}\e[0m"
30+
end
31+
32+
def self.clear_codes
33+
"\e[H\e[2J"
34+
end
35+
36+
def clear_codes
37+
self.class.clear_codes
38+
end
39+
end

0 commit comments

Comments
 (0)