Skip to content

Commit 8a6fa0c

Browse files
committed
day 22, part 2
Lotsa Parallel
1 parent 70a4fe3 commit 8a6fa0c

File tree

1 file changed

+100
-9
lines changed

1 file changed

+100
-9
lines changed

2024/ruby/day22.rb

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,115 @@
22
require 'parallel'
33

44
class Day22 < Day # >
5+
attr_reader :buyers
6+
7+
def initialize(*args)
8+
super
9+
@buyers =
10+
Parallel
11+
.map(input.scan(/\d+/)) { |initial_secret_number|
12+
Buyer.new(initial_secret_number.to_i)
13+
}
14+
puts "initialized" if ENV['DEBUG']
15+
end
516

617
# @example
18+
# day = Day22.new('1 10 100 2024')
719
# day.part1 #=> 37327623
820
def part1
9-
initial_secret_numbers = input.split("\n").map(&:to_i)
10-
Parallel.map(initial_secret_numbers) { |initial_secret_number|
11-
2000.times.inject(initial_secret_number) { |secret_number, _|
12-
secret_number = ((secret_number * 64) ^ secret_number) % 16777216
13-
secret_number = ((secret_number / 32).floor ^ secret_number) % 16777216
14-
secret_number = ((secret_number * 2048) ^ secret_number) % 16777216
15-
}
16-
}.reduce(&:+)
21+
puts "starting part1" if ENV['DEBUG']
22+
23+
Parallel
24+
.map(buyers) { |buyer| buyer.secret_numbers.last }
25+
.reduce(&:+)
1726
end
1827

1928
# @example
20-
# day.part2 #=> 'how are you'
29+
# day = Day22.new('1 2 3 2024')
30+
# day.part2 #=> 23
2131
def part2
32+
puts "starting part2" if ENV['DEBUG']
33+
34+
unique_sequences =
35+
buyers
36+
.inject(Set.new) { |unique_sequences, buyer|
37+
unique_sequences.merge(buyer.price_sequence_table.keys)
38+
}
39+
40+
puts "unique_sequences: #{unique_sequences.count}" if ENV['DEBUG']
41+
42+
Parallel
43+
.map(unique_sequences) { |sequence|
44+
buyers
45+
.inject(0) { |bananas, buyer|
46+
bananas += (buyer.price_sequence_table[sequence] || 0)
47+
}
48+
}
49+
.max
2250
end
2351

2452
EXAMPLE_INPUT = File.read("../inputs/day22-example-input.txt")
2553
end
54+
55+
class Buyer
56+
attr_reader :secret_numbers, :prices, :price_sequence_table
57+
58+
# @example
59+
# buyer = Buyer.new(1)
60+
# buyer.secret_numbers.first #=> 1
61+
# buyer.secret_numbers.last #=> 8685429
62+
# buyer.prices.first #=> 1
63+
# buyer.prices.last #=> 9
64+
def initialize(initial_secret_number)
65+
@secret_numbers = [initial_secret_number]
66+
@prices = [initial_secret_number % 10]
67+
@price_sequence_table = Hash.new
68+
generate_secret_numbers
69+
generate_sequence_lookup
70+
end
71+
72+
# @example 1
73+
# buyer = Buyer.new(1)
74+
# buyer.secret_numbers.last #=> 8685429
75+
# @example 10
76+
# buyer = Buyer.new(10)
77+
# buyer.secret_numbers.last #=> 4700978
78+
# @example 100
79+
# buyer = Buyer.new(100)
80+
# buyer.secret_numbers.last #=> 15273692
81+
# @example 2024
82+
# buyer = Buyer.new(2024)
83+
# buyer.secret_numbers.last #=> 8667524
84+
def generate_secret_numbers(evolutions=2000)
85+
evolutions.times do
86+
secret_number = @secret_numbers.last
87+
secret_number = ((secret_number * 64) ^ secret_number) % 16777216
88+
secret_number = ((secret_number / 32).floor ^ secret_number) % 16777216
89+
secret_number = ((secret_number * 2048) ^ secret_number) % 16777216
90+
@secret_numbers << secret_number
91+
@prices << secret_number % 10
92+
end
93+
end
94+
95+
# @example
96+
# buyer = Buyer.new(123)
97+
# buyer.price_changes.take(9) #=> [-3, 6, -1, -1, 0, 2, -2, 0, -2]
98+
# buyer.price_changes.count #=> 2000
99+
def price_changes
100+
@prices.each_cons(2).map { |a, b| b - a }
101+
end
102+
103+
# @example
104+
# buyer = Buyer.new(1)
105+
# buyer.price_sequence_table[ [-2,1,-1,3] ] #=> 7
106+
def generate_sequence_lookup
107+
price_changes.each_cons(4).with_index do |four_deltas, i|
108+
@price_sequence_table[four_deltas] ||= @prices[i + 4]
109+
end
110+
end
111+
112+
def price_sequence_table
113+
generate_sequence_lookup if @price_sequence_table.empty?
114+
@price_sequence_table
115+
end
116+
end

0 commit comments

Comments
 (0)