Skip to content

Instantly share code, notes, and snippets.

@stilist
Last active December 4, 2024 02:24
Show Gist options
  • Save stilist/5bc42309fb92a220053cd683aacb1318 to your computer and use it in GitHub Desktop.
Save stilist/5bc42309fb92a220053cd683aacb1318 to your computer and use it in GitHub Desktop.
Advent of Code 2024
File.read(File.expand_path('~/Downloads/day 1 input.txt'))
.split(/\n/)
.reduce([]) {|m,l|l.split.map(&:to_i).each_with_index.map {(m[_2]||[])<<_1}}
.map(&:sort)
.each_cons(2)
.map {_1.zip(_2)}
.flatten(1)
.map {(_1-_2).abs}
.sum
# The largest integer is 99, which fits in 7 bits (0-127)
INTEGER_BITS = 7
# @see https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
def popcount(n)
c = 0
while n > 0 do
n &= n-1
c += 1
end
c
end
# Map a line like '61 63 64 67 69 72 74 81' to an array of integers, and map the integers into a
# continuous series of bits
def to_bitmap(levels) = levels.reduce(0) {(_1<<INTEGER_BITS)|_2}
def count_invalid_levels(bitmap, member_count, window)
# Compare integer N with integer N + window by shifting a copy right INTEGER_BITS *
# window bits
delta_from_previous_sample = ((bitmap&(0b1<<INTEGER_BITS*(member_count-window))-1)-(bitmap>>INTEGER_BITS)).abs
# `...member_count-1` excludes the leftmost member--the leftmost bitmap integer is implicitly
# compared with itself and thus will never differ
#
# XOR the bits of the rightmost member (after shifting) and see if the result is all 1s--if so
# the member is all 0s, meaning it matches the previous member
unchanged = (0...member_count-1).reduce(0) {_1<<(INTEGER_BITS*_2)|(((delta_from_previous_sample>>INTEGER_BITS*_2)^0b1111111)&0b1111111==0b1111111?1:0)}
# Mask off bits 1 and 2, equivalent to decimal 0-3; ANDing with it will preserve bitmap members
# larger than 3
only_unsafe = delta_from_previous_sample&0b1111100_1111100_1111100_1111100_1111100_1111100_1111100_1111100
# `#reduce` ensures that a bit set anywhere in bits 3-7 ends up filling bit 1 so the mask
# detects it
unsafe = (1...INTEGER_BITS).reduce(only_unsafe) {_1|_1>>_2}&0b0000001_0000001_0000001_0000001_0000001_0000001_0000001_0000001
popcount(unchanged|unsafe)
end
def process(input)
input.split(/\n/)
.map {_1.split.map(&:to_i)}
.select{(to_bitmap(_1)-to_bitmap(_1.sort)==0?1:0)<<1|(to_bitmap(_1)-to_bitmap(_1.sort.reverse)==0?1:0)&0b11>0}
.map{[to_bitmap(_1),_1.count]}
.filter{count_invalid_levels(*_1, 1)==0}
.length
end
puts process(File.read(File.expand_path('~/Downloads/day 2 input.txt')))
#=> 598
puts process('7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9')
#=> 2
File.read(File.expand_path('~/Downloads/day 2 input.txt'))
.split(/\n/)
.map {_1.split.map(&:to_i)}
.filter {_1 ==_1.sort||_1 == _1.sort.reverse}
.filter {|r|r.each_cons(2).filter {(_1-_2).abs<1||(_1-_2).abs>3}.empty?}
.length
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment