Skip to content

Commit d6ff846

Browse files
committed
catch-up commit dump
a lot has happened
1 parent 14256da commit d6ff846

File tree

15 files changed

+1190
-114
lines changed

15 files changed

+1190
-114
lines changed

2024/ruby/Gemfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ source "https://rubygems.org"
44

55
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
66

7+
gem "priority_queue_cxx"
8+
gem "parallel"
9+
gem "matrix"
10+
711
gem "rake"
812
gem "pry"
913
gem "minitest", "= 5.25.1" # 5.25.2 causes yard-doctest's anon class to appear in test names :(
1014
gem "yard-doctest"
1115
gem "mutex_m" # yard-doctest uses this, but it'll be yoinked from default gems in Ruby 3.4
1216
gem "rspec"
13-
1417
gem "debug"
15-
gem "ruby-lsp", group: :development
18+
gem "ruby-lsp"

2024/ruby/Gemfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ GEM
1313
reline (>= 0.4.2)
1414
language_server-protocol (3.17.0.3)
1515
logger (1.6.2)
16+
matrix (0.4.2)
1617
method_source (1.1.0)
1718
minitest (5.25.1)
1819
mutex_m (0.3.0)
20+
parallel (1.26.3)
21+
priority_queue_cxx (0.3.7)
1922
prism (1.2.0)
2023
pry (0.15.0)
2124
coderay (~> 1.1)
@@ -61,8 +64,11 @@ PLATFORMS
6164

6265
DEPENDENCIES
6366
debug
67+
matrix
6468
minitest (= 5.25.1)
6569
mutex_m
70+
parallel
71+
priority_queue_cxx
6672
pry
6773
rake
6874
rspec

2024/ruby/day04.rb

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class Day04 < Day # >
88
def part1
99
exes = []
1010
word_search =
11-
Grid.new(input, raise_on_out_of_bounds: false)
11+
Grid.new(input)
1212
.parse do |coords, char|
1313
exes << coords if char == 'X'
1414
end
@@ -41,13 +41,18 @@ def part2
4141
ays << coords if char == 'A'
4242
end
4343

44+
expected = Set.new(["M", "S"])
4445
ays
4546
.keep_if { |a_location|
4647
begin
47-
["M", "S"] == [ word_search.at(step_in_direction(a_location, [-1,-1])),
48-
word_search.at(step_in_direction(a_location, [ 1, 1])) ].sort &&
49-
["M", "S"] == [ word_search.at(step_in_direction(a_location, [-1, 1])),
50-
word_search.at(step_in_direction(a_location, [ 1,-1])) ].sort
48+
expected == Set.new(
49+
[ word_search.at(step_in_direction(a_location, [-1,-1])),
50+
word_search.at(step_in_direction(a_location, [ 1, 1])) ]
51+
) &&
52+
expected == Set.new(
53+
[ word_search.at(step_in_direction(a_location, [-1, 1])),
54+
word_search.at(step_in_direction(a_location, [ 1,-1])) ]
55+
)
5156
rescue Grid::OutOfBounds
5257
false
5358
end

2024/ruby/day06.rb

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
require_relative 'day'
2+
require_relative 'grid'
3+
require 'set'
4+
5+
class Day06 < Day # >
6+
attr_accessor :guard
7+
8+
# @example
9+
# day.part1 #=> 41
10+
def part1
11+
@start = nil
12+
@lab_map =
13+
Grid
14+
.new(input)
15+
.parse do |coord, char|
16+
@start = coord if char == '^'
17+
end
18+
19+
predict_path(@lab_map, @start)
20+
.count
21+
end
22+
23+
# @example
24+
# day.part1
25+
# day.part2 #=> 6
26+
def part2
27+
predict_path(@lab_map, @start)
28+
.map { |location|
29+
predict_path(@lab_map, @start, new_obstruction: location)
30+
}
31+
.map(&:first)
32+
.count
33+
end
34+
35+
def predict_path(map, start, new_obstruction: nil)
36+
guard = Guard.new(start, '^')
37+
38+
map.set(new_obstruction, 'O') if new_obstruction
39+
loop do
40+
case map.at(guard.next_step)
41+
when '.','^' ; guard.step_forward!
42+
when '#','O' ; guard.turn_right!
43+
when :out_of_bounds
44+
break
45+
end
46+
end
47+
48+
guard.visited
49+
# rescue LoopDetected
50+
# return :loop_detected
51+
ensure
52+
map.set(new_obstruction, '.') if new_obstruction
53+
end
54+
55+
EXAMPLE_INPUT = File.read("../inputs/day06-example-input.txt")
56+
57+
class Guard
58+
attr_accessor :position, :facing
59+
attr_reader :visited
60+
61+
DIRECTIONS = {
62+
'^' => 0,
63+
'>' => 90,
64+
'v' => 180,
65+
'<' => 270,
66+
}
67+
68+
def initialize(position, facing)
69+
@position = position
70+
@facing = DIRECTIONS.fetch(facing)
71+
@visited = Set.new.add([@position, @facing])
72+
end
73+
74+
def next_step
75+
case facing
76+
when 0 ; [ position[0] -1, position[1] ]
77+
when 90 ; [ position[0] , position[1] +1 ]
78+
when 180 ; [ position[0] +1, position[1] ]
79+
when 270 ; [ position[0] , position[1] -1 ]
80+
else
81+
raise "lolwut: weird facing direction #{facing}"
82+
end
83+
end
84+
85+
class LoopDetected < RuntimeError; end
86+
87+
def step_forward!
88+
@position = next_step
89+
@visited.add?([@position, @facing]) or raise LoopDetected
90+
end
91+
92+
def turn_right!
93+
@facing = (facing + 90).modulo(360)
94+
end
95+
end
96+
end
97+
98+
require 'rspec'
99+
100+
describe 'Day06' do
101+
let(:day) { Day06.new(Day06::EXAMPLE_INPUT) }
102+
it 'answers part 1' do
103+
expect(day.part1).to eq(41)
104+
end
105+
106+
it 'answers part 2' do
107+
day.part1 # part 2 depends on state determined from part 1
108+
# expect(day.part2).to eq(6)
109+
expect(day.part2).to eq([[6,3], [7,6], [7,8], [8,1], [8,3], [9,7]])
110+
end
111+
112+
describe 'Guard' do
113+
subject { Day06::Guard.new([4,5], '^') }
114+
115+
it "knows their next step" do
116+
expect(subject.next_step).to eq([3,5])
117+
end
118+
119+
it "can step forward" do
120+
subject.step_forward!
121+
expect(subject.position).to eq([3,5])
122+
end
123+
124+
it "can turn right" do
125+
subject.turn_right!
126+
expect(subject.facing).to eq(90)
127+
128+
subject.turn_right!
129+
subject.turn_right!
130+
expect(subject.facing).to eq(270)
131+
end
132+
end
133+
end

2024/ruby/day08.rb

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
require_relative 'day'
2+
require_relative 'grid'
3+
require 'matrix'
4+
5+
class Day08 < Day # >
6+
attr_reader :map, :antenna_locations
7+
8+
def initialize(*args)
9+
super
10+
11+
@antenna_locations = Hash.new { |hash, frequency|
12+
hash[frequency] = [] # the future home of list of grid locations
13+
}
14+
15+
@map =
16+
Grid
17+
.new(input)
18+
.parse do |coords, char|
19+
if %r{\w}.match? char # antenna frequencies are word characters
20+
antenna_locations[char] << Vector.elements(coords)
21+
end
22+
end
23+
end
24+
25+
# @example
26+
# day.part1 #=> 14
27+
# @example two antennas
28+
# day = new(EXAMPLE_TWO_ANTENNAS)
29+
# day.part1 #=> 2
30+
# @example three antennas
31+
# day = new(EXAMPLE_THREE_ANTENNAS)
32+
# day.part1 #=> 4
33+
def part1
34+
antinodes =
35+
antenna_locations
36+
.map {|frequency, locations|
37+
locations
38+
.combination(2)
39+
.flat_map {|a,b|
40+
diff = a - b
41+
[ a + diff, b - diff ]
42+
}
43+
.uniq
44+
.select { |antinode| map.cover? antinode.to_a }
45+
}
46+
.flatten
47+
.uniq
48+
.map(&:to_a)
49+
50+
if ENV['DEBUG']
51+
puts "\n" + map.to_s { |coords, value|
52+
if antinodes.include?(coords)
53+
value == '.' ? "\e[41m\e[1m#\e[0m" : "\e[41m\e[1m#{value}\e[0m"
54+
else
55+
"\e[32m#{value}\e[0m"
56+
end
57+
}
58+
end
59+
60+
antinodes.count
61+
end
62+
63+
# @example
64+
# day.part2 #=> 34
65+
# @example resonant harmonics
66+
# day = new(EXAMPLE_RESONANT_HARMONICS)
67+
# day.part2 #=> 9
68+
def part2
69+
antinodes =
70+
antenna_locations
71+
.flat_map {|frequency, locations|
72+
locations
73+
.combination(2)
74+
.flat_map {|a,b|
75+
puts [a,b].inspect if ENV['DEBUG']
76+
diff = a - b
77+
puts diff.inspect if ENV['DEBUG']
78+
upwards = Enumerator.produce(a) {|antinode| antinode + diff }
79+
downwards = Enumerator.produce(b) {|antinode| antinode - diff }
80+
81+
upwards.take_while { map.cover?(_1) } +
82+
downwards.take_while { map.cover?(_1) }
83+
}
84+
.uniq
85+
}
86+
.uniq
87+
.map(&:to_a)
88+
89+
if ENV['DEBUG']
90+
puts "\n" + map.to_s { |coords, value|
91+
if antinodes.include?(coords)
92+
value == '.' ? "\e[41m\e[1m#\e[0m" : "\e[41m\e[1m#{value}\e[0m"
93+
else
94+
"\e[32m#{value}\e[0m"
95+
end
96+
}
97+
end
98+
99+
antinodes.count
100+
end
101+
102+
EXAMPLE_INPUT = File.read("../inputs/day08-example-input.txt")
103+
104+
EXAMPLE_TWO_ANTENNAS = <<~EXAMPLE
105+
..........
106+
...#......
107+
..........
108+
....a.....
109+
..........
110+
.....a....
111+
..........
112+
......#...
113+
..........
114+
..........
115+
EXAMPLE
116+
117+
EXAMPLE_THREE_ANTENNAS = <<~EXAMPLE
118+
..........
119+
...#......
120+
#.........
121+
....a.....
122+
........a.
123+
.....a....
124+
..#.......
125+
......#...
126+
..........
127+
..........
128+
EXAMPLE
129+
130+
EXAMPLE_RESONANT_HARMONICS = <<~EXAMPLE
131+
T....#....
132+
...T......
133+
.T....#...
134+
.........#
135+
..#.......
136+
..........
137+
...#......
138+
..........
139+
....#.....
140+
..........
141+
EXAMPLE
142+
end

0 commit comments

Comments
 (0)