Skip to content

Commit f26fe41

Browse files
authored
Merge pull request #93 from dalurness/jesse/2025-08
Add janka102 day 8, 2025
2 parents c392a23 + 91e146c commit f26fe41

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

src/content/communitySolutions/07/janka102.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ descriptions: ["ruby"]
44

55
## 2025
66

7+
One interesting thing I learned about Ruby is that the Hash class uses value equality for keys via `.hash` and `.eql?`. So for example two arrays with the same numbers in them can be used to check for the presense of the other (as apposed to only that _exact_ array). This was useful for me since I was using arrays for [x, y] coordinates and could then store those directly in the visits hash map.
8+
79
```ruby
810
require 'optparse'
911

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
descriptions: ["ruby"]
3+
---
4+
5+
## 2025
6+
7+
I used a recursive approach filling in smaller and smaller sleigh sizes as presents are added. This gets very slow very quickly with a naive implementation. One trick is of course classic memoization! The trick to that trick is that you need to have a separate entry for each sleigh size _and previous present size_. Since present sizes can't repeat, then for example a remaining sleigh size of 5 can hold different amounts depending on what the previous present was (including no previous present).
8+
9+
```
10+
1: 1
11+
...
12+
10: 123
13+
...
14+
100: 638760883391635670992582
15+
...
16+
1000: 9.849739E+240
17+
...
18+
10000: 7.486669E+2412
19+
________________________________________________________
20+
Executed in 1.01 secs
21+
```
22+
23+
```ruby
24+
require 'optparse'
25+
26+
class Dayd08
27+
def initialize
28+
@memo = {}
29+
end
30+
31+
def solve(challenge)
32+
if challenge
33+
(1..).each do |size|
34+
arrangements = fill_sleigh(size, nil)
35+
# the numbers get very large, so format in 3.141592E+65 format
36+
if size > 100
37+
digits = Math.log10(arrangements)
38+
sig_figs = 10**(digits % 1)
39+
exponent = digits.floor
40+
puts "#{size}: #{format('%.6fE+%d', sig_figs, exponent)}"
41+
else
42+
puts "#{size}: #{arrangements}"
43+
end
44+
end
45+
else
46+
size = 30
47+
puts "#{size}: #{fill_sleigh(size, nil)}"
48+
end
49+
end
50+
51+
# Given a sleigh size, try to fit one of each size present
52+
# then add up how many presents can fit in the new smaller sleigh
53+
def fill_sleigh(size, prev)
54+
return @memo[[size, prev]] if @memo.include?([size, prev])
55+
56+
total = 0
57+
58+
# order is important, check small to big
59+
(1..9).each do |present|
60+
# don't allow two presents of the same size next to each other
61+
next if present == prev
62+
63+
remaining = size - present
64+
65+
# if there is the exact space required for this present then we found a solution
66+
total += 1 if remaining.zero?
67+
68+
# if no more space then we can break early and skip checking even bigger presents
69+
break if remaining <= 0
70+
71+
sub = fill_sleigh(remaining, present)
72+
total += sub if sub.positive?
73+
end
74+
75+
@memo[[size, prev]] = total
76+
77+
total
78+
end
79+
end
80+
81+
if __FILE__ == $PROGRAM_NAME
82+
options = {}
83+
OptionParser.new do |parser|
84+
parser.banner = "Usage: #{$PROGRAM_NAME} [options]"
85+
86+
parser.on('-c', '--challenge', 'Solve for ever increasing sleigh sizes')
87+
end.parse!(into: options)
88+
89+
challenge = Dayd08.new
90+
challenge.solve(options[:challenge])
91+
end
92+
```

0 commit comments

Comments
 (0)