advent_of_ruby 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of advent_of_ruby might be problematic. Click here for more details.

Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/data/solutions/github/ZogStriP/2024/01_1.yml +1 -0
  3. data/data/solutions/github/ZogStriP/2024/01_2.yml +7 -0
  4. data/data/solutions/github/ZogStriP/2024/02_1.yml +1 -0
  5. data/data/solutions/github/ZogStriP/2024/02_2.yml +9 -0
  6. data/data/solutions/github/ZogStriP/2024/03_1.yml +1 -0
  7. data/data/solutions/github/ZogStriP/2024/03_2.yml +7 -0
  8. data/data/solutions/github/ZogStriP/2024/04_1.yml +1 -0
  9. data/data/solutions/github/ZogStriP/2024/04_2.yml +15 -0
  10. data/data/solutions/github/ZogStriP/2024/05_1.yml +1 -0
  11. data/data/solutions/github/ZogStriP/2024/05_2.yml +16 -0
  12. data/data/solutions/github/ZogStriP/2024/06_1.yml +1 -0
  13. data/data/solutions/github/ZogStriP/2024/06_2.yml +38 -0
  14. data/data/solutions/github/ZogStriP/2024/07_1.yml +1 -0
  15. data/data/solutions/github/ZogStriP/2024/07_2.yml +9 -0
  16. data/data/solutions/github/ZogStriP/2024/08_1.yml +1 -0
  17. data/data/solutions/github/ZogStriP/2024/08_2.yml +27 -0
  18. data/data/solutions/github/ZogStriP/2024/09_1.yml +1 -0
  19. data/data/solutions/github/ZogStriP/2024/09_2.yml +1 -0
  20. data/data/solutions/github/ZogStriP/2024/10_1.yml +1 -0
  21. data/data/solutions/github/ZogStriP/2024/10_2.yml +1 -0
  22. data/data/solutions/github/ZogStriP/2024/11_1.yml +1 -0
  23. data/data/solutions/github/ZogStriP/2024/11_2.yml +1 -0
  24. data/data/solutions/github/ZogStriP/2024/12_1.yml +1 -0
  25. data/data/solutions/github/ZogStriP/2024/12_2.yml +1 -0
  26. data/data/solutions/github/ZogStriP/2024/13_1.yml +1 -0
  27. data/data/solutions/github/ZogStriP/2024/13_2.yml +1 -0
  28. data/data/solutions/github/ZogStriP/2024/14_1.yml +1 -0
  29. data/data/solutions/github/ZogStriP/2024/14_2.yml +1 -0
  30. data/data/solutions/github/ZogStriP/2024/15_1.yml +1 -0
  31. data/data/solutions/github/ZogStriP/2024/15_2.yml +1 -0
  32. data/data/solutions/github/ZogStriP/2024/16_1.yml +1 -0
  33. data/data/solutions/github/ZogStriP/2024/16_2.yml +1 -0
  34. data/data/solutions/github/ZogStriP/2024/17_1.yml +1 -0
  35. data/data/solutions/github/ZogStriP/2024/17_2.yml +1 -0
  36. data/data/solutions/github/ZogStriP/2024/18_1.yml +1 -0
  37. data/data/solutions/github/ZogStriP/2024/18_2.yml +1 -0
  38. data/data/solutions/github/ZogStriP/2024/19_1.yml +1 -0
  39. data/data/solutions/github/ZogStriP/2024/19_2.yml +1 -0
  40. data/data/solutions/github/ZogStriP/2024/20_1.yml +1 -0
  41. data/data/solutions/github/ZogStriP/2024/20_2.yml +1 -0
  42. data/data/solutions/github/ZogStriP/2024/21_1.yml +1 -0
  43. data/data/solutions/github/ZogStriP/2024/21_2.yml +1 -0
  44. data/data/solutions/github/ZogStriP/2024/22_1.yml +1 -0
  45. data/data/solutions/github/ZogStriP/2024/22_2.yml +1 -0
  46. data/data/solutions/github/ZogStriP/2024/23_1.yml +1 -0
  47. data/data/solutions/github/ZogStriP/2024/23_2.yml +1 -0
  48. data/data/solutions/github/ZogStriP/2024/24_1.yml +1 -0
  49. data/data/solutions/github/ZogStriP/2024/24_2.yml +1 -0
  50. data/data/solutions/github/ZogStriP/2024/25_1.yml +1 -0
  51. data/data/solutions/github/ZogStriP/2025/01_1.yml +1 -0
  52. data/data/solutions/github/ZogStriP/2025/01_2.yml +1 -0
  53. data/data/solutions/github/ZogStriP/2025/02_1.yml +1 -0
  54. data/data/solutions/github/ZogStriP/2025/02_2.yml +1 -0
  55. data/data/solutions/github/ZogStriP/2025/03_1.yml +1 -0
  56. data/data/solutions/github/ZogStriP/2025/03_2.yml +1 -0
  57. data/data/solutions/github/ZogStriP/2025/04_1.yml +1 -0
  58. data/data/solutions/github/ZogStriP/2025/04_2.yml +1 -0
  59. data/data/solutions/github/ZogStriP/2025/05_1.yml +1 -0
  60. data/data/solutions/github/ZogStriP/2025/05_2.yml +1 -0
  61. data/data/solutions/github/ZogStriP/2025/06_1.yml +1 -0
  62. data/data/solutions/github/ZogStriP/2025/06_2.yml +1 -0
  63. data/data/solutions/github/ZogStriP/2025/07_1.yml +1 -0
  64. data/data/solutions/github/ZogStriP/2025/07_2.yml +1 -0
  65. data/data/solutions/github/ZogStriP/2025/08_1.yml +1 -0
  66. data/data/solutions/github/ZogStriP/2025/08_2.yml +1 -0
  67. data/data/solutions/github/ZogStriP/2025/09_1.yml +1 -0
  68. data/data/solutions/github/ZogStriP/2025/09_2.yml +1 -0
  69. data/data/solutions/github/ZogStriP/2025/10_1.yml +1 -0
  70. data/data/solutions/github/ZogStriP/2025/10_2.yml +1 -0
  71. data/data/solutions/github/ZogStriP/2025/11_1.yml +1 -0
  72. data/data/solutions/github/ZogStriP/2025/11_2.yml +1 -0
  73. data/data/solutions/github/ZogStriP/2025/12_1.yml +1 -0
  74. data/data/solutions/github/ZogStriP/2025/12_2.yml +1 -0
  75. data/data/solutions/github/ahorner/2025/01_1.yml +1 -0
  76. data/data/solutions/github/ahorner/2025/01_2.yml +37 -0
  77. data/data/solutions/github/ahorner/2025/02_1.yml +1 -0
  78. data/data/solutions/github/ahorner/2025/02_2.yml +41 -0
  79. data/data/solutions/github/ahorner/2025/03_1.yml +1 -0
  80. data/data/solutions/github/ahorner/2025/03_2.yml +24 -0
  81. data/data/solutions/github/ahorner/2025/04_1.yml +1 -0
  82. data/data/solutions/github/ahorner/2025/04_2.yml +39 -0
  83. data/data/solutions/github/ahorner/2025/05_1.yml +1 -0
  84. data/data/solutions/github/ahorner/2025/05_2.yml +48 -0
  85. data/data/solutions/github/ahorner/2025/06_1.yml +1 -0
  86. data/data/solutions/github/ahorner/2025/06_2.yml +44 -0
  87. data/data/solutions/github/ahorner/2025/07_1.yml +1 -0
  88. data/data/solutions/github/ahorner/2025/07_2.yml +56 -0
  89. data/data/solutions/github/ahorner/2025/08_1.yml +1 -0
  90. data/data/solutions/github/ahorner/2025/08_2.yml +59 -0
  91. data/data/solutions/github/ahorner/2025/09_1.yml +1 -0
  92. data/data/solutions/github/ahorner/2025/09_2.yml +101 -0
  93. data/data/solutions/github/ahorner/2025/10_1.yml +1 -0
  94. data/data/solutions/github/ahorner/2025/10_2.yml +72 -0
  95. data/data/solutions/github/ahorner/2025/11_1.yml +1 -0
  96. data/data/solutions/github/ahorner/2025/11_2.yml +45 -0
  97. data/data/solutions/github/ahorner/2025/12_1.yml +1 -0
  98. data/data/solutions/github/eregon/2025/01_1.yml +17 -0
  99. data/data/solutions/github/eregon/2025/01_2.yml +14 -0
  100. data/data/solutions/github/eregon/2025/02_1.yml +22 -0
  101. data/data/solutions/github/eregon/2025/02_2.yml +58 -0
  102. data/data/solutions/github/eregon/2025/03_1.yml +13 -0
  103. data/data/solutions/github/eregon/2025/03_2.yml +13 -0
  104. data/data/solutions/github/eregon/2025/04_1.yml +14 -0
  105. data/data/solutions/github/eregon/2025/04_2.yml +16 -0
  106. data/data/solutions/github/eregon/2025/05_1.yml +1 -0
  107. data/data/solutions/github/eregon/2025/05_2.yml +1 -0
  108. data/data/solutions/github/eregon/2025/06_1.yml +1 -0
  109. data/data/solutions/github/eregon/2025/06_2.yml +1 -0
  110. data/data/solutions/github/eregon/2025/07_1.yml +1 -0
  111. data/data/solutions/github/eregon/2025/07_2.yml +1 -0
  112. data/data/solutions/github/eregon/2025/08_1.yml +1 -0
  113. data/data/solutions/github/eregon/2025/08_2.yml +1 -0
  114. data/data/solutions/github/eregon/2025/09_1.yml +1 -0
  115. data/data/solutions/github/eregon/2025/09_2.yml +1 -0
  116. data/data/solutions/github/eregon/2025/10_1.yml +1 -0
  117. data/data/solutions/github/eregon/2025/10_2.yml +1 -0
  118. data/data/solutions/github/eregon/2025/11_1.yml +1 -0
  119. data/data/solutions/github/eregon/2025/11_2.yml +1 -0
  120. data/data/solutions/github/eregon/2025/12_1.yml +1 -0
  121. data/data/solutions/github/erikw/2025/01_1.yml +1 -0
  122. data/data/solutions/github/erikw/2025/01_2.yml +1 -0
  123. data/data/solutions/github/erikw/2025/02_1.yml +1 -0
  124. data/data/solutions/github/erikw/2025/02_2.yml +1 -0
  125. data/data/solutions/github/erikw/2025/03_1.yml +1 -0
  126. data/data/solutions/github/erikw/2025/03_2.yml +1 -0
  127. data/data/solutions/github/erikw/2025/04_1.yml +1 -0
  128. data/data/solutions/github/erikw/2025/04_2.yml +1 -0
  129. data/data/solutions/github/erikw/2025/05_1.yml +1 -0
  130. data/data/solutions/github/erikw/2025/05_2.yml +1 -0
  131. data/data/solutions/github/erikw/2025/06_1.yml +1 -0
  132. data/data/solutions/github/erikw/2025/06_2.yml +1 -0
  133. data/data/solutions/github/erikw/2025/07_1.yml +1 -0
  134. data/data/solutions/github/erikw/2025/07_2.yml +1 -0
  135. data/data/solutions/github/erikw/2025/08_1.yml +1 -0
  136. data/data/solutions/github/erikw/2025/08_2.yml +1 -0
  137. data/data/solutions/github/erikw/2025/09_1.yml +1 -0
  138. data/data/solutions/github/erikw/2025/09_2.yml +1 -0
  139. data/data/solutions/github/erikw/2025/10_1.yml +1 -0
  140. data/data/solutions/github/erikw/2025/10_2.yml +1 -0
  141. data/data/solutions/github/erikw/2025/11_1.yml +1 -0
  142. data/data/solutions/github/erikw/2025/11_2.yml +1 -0
  143. data/data/solutions/github/erikw/2025/12_1.yml +1 -0
  144. data/data/solutions/github/erikw/2025/12_2.yml +1 -0
  145. data/data/solutions/github/gchan/2025/01_1.yml +25 -0
  146. data/data/solutions/github/gchan/2025/01_2.yml +32 -0
  147. data/data/solutions/github/gchan/2025/02_1.yml +18 -0
  148. data/data/solutions/github/gchan/2025/02_2.yml +21 -0
  149. data/data/solutions/github/gchan/2025/03_1.yml +15 -0
  150. data/data/solutions/github/gchan/2025/03_2.yml +23 -0
  151. data/data/solutions/github/gchan/2025/04_1.yml +27 -0
  152. data/data/solutions/github/gchan/2025/04_2.yml +40 -0
  153. data/data/solutions/github/gchan/2025/05_1.yml +20 -0
  154. data/data/solutions/github/gchan/2025/05_2.yml +36 -0
  155. data/data/solutions/github/gchan/2025/06_1.yml +11 -0
  156. data/data/solutions/github/gchan/2025/06_2.yml +28 -0
  157. data/data/solutions/github/gchan/2025/07_1.yml +33 -0
  158. data/data/solutions/github/gchan/2025/07_2.yml +29 -0
  159. data/data/solutions/github/gchan/2025/08_1.yml +48 -0
  160. data/data/solutions/github/gchan/2025/08_2.yml +48 -0
  161. data/data/solutions/github/gchan/2025/09_1.yml +16 -0
  162. data/data/solutions/github/gchan/2025/09_2.yml +60 -0
  163. data/data/solutions/github/gchan/2025/10_1.yml +49 -0
  164. data/data/solutions/github/gchan/2025/10_2.yml +154 -0
  165. data/data/solutions/github/gchan/2025/11_1.yml +43 -0
  166. data/data/solutions/github/gchan/2025/11_2.yml +33 -0
  167. data/data/solutions/github/gchan/2025/12_1.yml +51 -0
  168. data/data/solutions/reddit/ruby/2017/06.yml +0 -2
  169. data/data/solutions/reddit/ruby/2020/02.yml +0 -1
  170. data/data/solutions/reddit/ruby/2024/02.yml +0 -1
  171. data/data/solutions/reddit/ruby/2025/01.yml +187 -0
  172. data/data/solutions/reddit/ruby/2025/02.yml +185 -0
  173. data/data/solutions/reddit/ruby/2025/03.yml +369 -0
  174. data/data/solutions/reddit/ruby/2025/04.yml +217 -0
  175. data/data/solutions/reddit/ruby/2025/05.yml +324 -0
  176. data/data/solutions/reddit/ruby/2025/06.yml +246 -0
  177. data/data/solutions/reddit/ruby/2025/07.yml +213 -0
  178. data/data/solutions/reddit/ruby/2025/08.yml +73 -0
  179. data/data/solutions/reddit/ruby/2025/09.yml +26 -0
  180. data/data/solutions/reddit/ruby/2025/10.yml +73 -0
  181. data/data/solutions/reddit/ruby/2025/11.yml +69 -0
  182. data/data/solutions/reddit/ruby/2025/12.yml +1 -0
  183. data/lib/arb/arb.rb +0 -5
  184. data/lib/arb/cli/bootstrap.rb +1 -1
  185. data/lib/arb/cli/commit.rb +1 -1
  186. data/lib/arb/cli/progress.rb +4 -8
  187. data/lib/arb/cli/run.rb +1 -1
  188. data/lib/arb/cli/shared/git.rb +3 -4
  189. data/lib/arb/cli/shared/year_day_validator.rb +3 -8
  190. data/lib/arb/files/spec.rb +2 -2
  191. data/lib/arb/util.rb +58 -0
  192. data/lib/arb/version.rb +1 -1
  193. metadata +184 -23
  194. data/lib/download_solutions/api/github/repos.rb +0 -54
  195. data/lib/download_solutions/api/github.rb +0 -164
  196. data/lib/download_solutions/api/reddit/add_missing_replies.rb +0 -43
  197. data/lib/download_solutions/api/reddit/clean_bodies.rb +0 -64
  198. data/lib/download_solutions/api/reddit/filter_by_language.rb +0 -32
  199. data/lib/download_solutions/api/reddit/get_initial_response.rb +0 -30
  200. data/lib/download_solutions/api/reddit/get_serial_comments.rb +0 -145
  201. data/lib/download_solutions/api/reddit/megathread_ids.rb +0 -19
  202. data/lib/download_solutions/api/reddit/params.rb +0 -40
  203. data/lib/download_solutions/api/reddit/reject_unwanted_replies.rb +0 -31
  204. data/lib/download_solutions/api/reddit/remove_ids.rb +0 -26
  205. data/lib/download_solutions/api/reddit/remove_language_tags.rb +0 -29
  206. data/lib/download_solutions/api/reddit.rb +0 -101
  207. data/lib/download_solutions/cli/cli/shared.rb +0 -35
  208. data/lib/download_solutions/cli/github.rb +0 -107
  209. data/lib/download_solutions/cli/reddit.rb +0 -64
  210. data/lib/download_solutions/download_solutions.rb +0 -18
  211. data/lib/download_solutions/reverse_markdown/converters/br.rb +0 -15
  212. data/lib/download_solutions/reverse_markdown/converters/pre.rb +0 -46
@@ -0,0 +1,154 @@
1
+ ---
2
+ - :name: day-10-part-2.rb
3
+ :url: https://github.com/gchan/advent-of-code-ruby/blob/main/2025/day-10
4
+ :solution: |-
5
+ machines = input.split("\n").map { _1.split(/(?<=\]) | (?=\{)/) }
6
+ .map! { |_lights, buttons, joltage|
7
+ joltage = joltage[1...-1].split(",").map(&:to_i)
8
+
9
+ buttons = buttons
10
+ .scan(/
11
+ \( # Opening parenthesis
12
+ (\d+(?:,\d+)*) # One or more digits separated by commas
13
+ \) # Closing parenthesis
14
+ /x)
15
+ .flatten
16
+ .map { _1.split(",").map(&:to_i) }
17
+
18
+ [joltage, buttons]
19
+ }
20
+
21
+ @cache = {}
22
+ def generate_selections(n, k)
23
+ return @cache[[n, k]] if @cache.key?([n, k])
24
+ result = []
25
+
26
+ distribute = ->(i, remaining, counts) do
27
+ if i == n - 1
28
+ counts[i] = remaining
29
+ result << counts
30
+ return
31
+ end
32
+
33
+ (0..remaining).each do |count|
34
+ counts[i] = count
35
+ distribute.call(i + 1, remaining - count, counts.dup)
36
+ end
37
+ end
38
+
39
+ distribute.call(0, k, Array.new(n, 0))
40
+ result = result.sort!.reverse!
41
+ @cache[[n, k]] = result
42
+ result
43
+ end
44
+
45
+ machines
46
+ .map.with_index { |(joltage, buttons), line|
47
+ # # puts [joltage, buttons].inspect
48
+ puts line
49
+
50
+ # Create button mapping (which buttons affect which positions)
51
+ button_map = Array.new(joltage.size) { [] }
52
+ buttons.each_with_index do |button, idx|
53
+ button.each { |pos| button_map[pos] << idx }
54
+ end
55
+
56
+ # Sort by button size (largest first) for better pruning
57
+ button_map.map! { |idxs| idxs.sort_by { |i| -buttons[i].size } }
58
+
59
+
60
+ queue = [[joltage.clone, 0, Array.new(buttons.size, 0)]]
61
+ visited = Hash.new(Float::INFINITY) # state -> min_presses to reach that state
62
+ count = nil
63
+ max_button_size = buttons.map(&:size).max
64
+
65
+ while queue.any?
66
+ state, presses, skip_buttons = queue.shift
67
+
68
+ # Skip if we've reached this state with fewer presses before
69
+ next if visited[state] <= presses
70
+ visited[state] = presses
71
+
72
+ puts "----------------------------------------"
73
+ puts "line #{line}:"
74
+ puts "Queue size: #{queue.size}"
75
+ puts "Current state: #{state.inspect}"
76
+ puts "Buttons: #{buttons.inspect}"
77
+ puts "skip_buttons: #{skip_buttons.inspect}"
78
+ puts "skip_buttons: #{skip_buttons.map.with_index { buttons[_2] if _1 == 1 }.compact.inspect}"
79
+
80
+ # puts button_map.inspect
81
+ button_to_press = button_map.each.with_index.min_by { |idxs, (btn)|
82
+ available_idxs = idxs.reject { |idx| skip_buttons[idx] == 1 }
83
+
84
+ size = available_idxs.size.zero? ? Float::INFINITY : available_idxs.size
85
+
86
+ #size
87
+ [size, -state[btn]]
88
+ }.last
89
+
90
+ # puts "Button to press: #{button_to_press}"
91
+ potential_buttons = button_map[button_to_press]
92
+ .reject { |idx| skip_buttons[idx] != 0 }
93
+ .sort_by { -buttons[_1].size }
94
+
95
+ next if potential_buttons.empty?
96
+
97
+ puts "Number of potential buttons: #{potential_buttons.size}"
98
+
99
+ puts "Presses so far: #{presses}"
100
+ required_presses = state[button_to_press]
101
+ puts "Required presses: #{required_presses}"
102
+
103
+ # Prune if this path would exceed current best solution
104
+ next if count && presses + required_presses >= count
105
+
106
+ selections = generate_selections(potential_buttons.size, required_presses)
107
+
108
+ selections.each do |selection|
109
+ # Early exit if we've found a solution that's as good as this path
110
+ break if count && presses + required_presses >= count
111
+
112
+ new_state = state.dup
113
+
114
+ selection.each_with_index do |press, idx|
115
+ buttons[potential_buttons[idx]].each { |pos| new_state[pos] -= press }
116
+ end
117
+
118
+ next if new_state.any? { _1 < 0 }
119
+
120
+ # Calculate lower bound: minimum presses needed to reach solution from new_state
121
+ remaining_sum = new_state.sum
122
+ lower_bound = (remaining_sum.to_f / max_button_size).ceil
123
+ next if count && presses + required_presses + lower_bound >= count
124
+
125
+ next if visited[new_state] <= presses + required_presses
126
+
127
+ if new_state.all? { _1 == 0 }
128
+ count = [count, presses + required_presses].compact.min
129
+ puts "Found solution with #{count} presses"
130
+ break
131
+ end
132
+
133
+ # puts new_state.inspect
134
+ new_skip_buttons = skip_buttons.dup
135
+
136
+ potential_buttons.each do |idx|
137
+ new_skip_buttons[idx] = 1
138
+ end
139
+
140
+ queue.unshift [new_state, presses + required_presses, new_skip_buttons]
141
+ #queue = [] if count
142
+ end
143
+
144
+ #puts state.inspect
145
+ #puts
146
+ end
147
+
148
+ # puts
149
+
150
+ raise if count.nil?
151
+ count
152
+ }
153
+ .sum
154
+ .tap { puts _1 }
@@ -0,0 +1,43 @@
1
+ ---
2
+ - :name: day-11-part-1.rb
3
+ :url: https://github.com/gchan/advent-of-code-ruby/blob/main/2025/day-11
4
+ :solution: |-
5
+ devices = input
6
+ .split("\n")
7
+ .map {
8
+ src, *dest = _1.split(/: | /)
9
+
10
+ [src, dest]
11
+ }
12
+ .to_h
13
+
14
+ count = 0
15
+ queue = [["you"]]
16
+
17
+ while queue.any?
18
+ path = queue.shift
19
+ current = path.last
20
+
21
+ devices[current].each do |neighbour|
22
+ new_path = path + [neighbour]
23
+
24
+ if neighbour == "out"
25
+ count += 1
26
+ else
27
+ queue << new_path
28
+ end
29
+ end
30
+ end
31
+
32
+ puts count
33
+
34
+ # Recursive DFS solution
35
+ def dfs(input, devices)
36
+ return 1 if input == "out"
37
+
38
+ devices[input].sum do |output|
39
+ dfs(output, devices)
40
+ end
41
+ end
42
+
43
+ puts dfs("you", devices)
@@ -0,0 +1,33 @@
1
+ ---
2
+ - :name: day-11-part-2.rb
3
+ :url: https://github.com/gchan/advent-of-code-ruby/blob/main/2025/day-11
4
+ :solution: |-
5
+ devices = input
6
+ .split("\n")
7
+ .map {
8
+ src, *dest = _1.split(/: | /)
9
+
10
+ [src, dest]
11
+ }
12
+ .to_h
13
+
14
+ def dfs(devices:, input:, memo: {}, dac: false, fft: false)
15
+ if input == "out"
16
+ return 1 if dac && fft
17
+ return 0
18
+ end
19
+
20
+ devices[input].sum do |output|
21
+ key = [output, dac, fft]
22
+
23
+ memo[key] ||= dfs(
24
+ devices:,
25
+ input: output,
26
+ memo:,
27
+ dac: dac || output == "dac",
28
+ fft: fft || output == "fft"
29
+ )
30
+ end
31
+ end
32
+
33
+ puts dfs(devices:, input: "svr")
@@ -0,0 +1,51 @@
1
+ ---
2
+ - :name: day-12-part-1.rb
3
+ :url: https://github.com/gchan/advent-of-code-ruby/blob/main/2025/day-12
4
+ :solution: |-
5
+ shapes = input.split("\n\n")
6
+
7
+ regions = shapes.pop.split("\n")
8
+ .map {
9
+ size, shape_qty = _1.split(?:)
10
+
11
+ [
12
+ size.split(?x).map(&:to_i),
13
+ shape_qty.split.map(&:to_i)
14
+ ]
15
+ }
16
+
17
+ shapes.map! {
18
+ _, *shape = _1.split(?\n)
19
+
20
+ shape.join
21
+ }
22
+
23
+ # Cheeky solution - just compare areas
24
+ # Only works with the input provided and not the sample input
25
+ shape_areas = shapes.map.with_index { |shape, idx|
26
+ shape.chars.count { _1 == ?# }
27
+ }
28
+
29
+ regions
30
+ .count { |(size_x, size_y), shape_qty|
31
+ total_area = size_x * size_y
32
+
33
+ shape_area = shape_qty.each_with_index.sum do |qty, idx|
34
+ shape_areas[idx] * shape_qty[idx]
35
+ end
36
+
37
+ shape_area <= total_area
38
+ }
39
+ .tap { puts _1 }
40
+
41
+ # Another cheeky solution - check if there is 9 spaces for each shape
42
+ regions
43
+ .count { |(size_x, size_y), shape_qty|
44
+ total_spaces = size_x * size_y / 9
45
+
46
+ shape_spaces = shape_qty.sum
47
+ shape_spaces <= total_spaces
48
+ }
49
+ .tap { puts _1 }
50
+
51
+ # TODO - Proper solution for the sample input
@@ -142,7 +142,6 @@
142
142
  **Ruby** simply using mem-string(join) instead of array of mem-arrays as comparison made it fast enough.
143
143
 
144
144
  ```ruby
145
-
146
145
  data = input.split("\t").strip.map(&:to_i)
147
146
  results = []
148
147
 
@@ -173,7 +172,6 @@
173
172
  cycles += 1
174
173
  end
175
174
  puts 'part2 -------', cycles, '----------'
176
-
177
175
  ```
178
176
  :replies:
179
177
  - :author: jschulenklopper
@@ -640,7 +640,6 @@
640
640
  Ruby
641
641
 
642
642
  ```ruby
643
-
644
643
  """
645
644
  password-philosophy.rb: from day_2.txt find out how many passwords are valid according to their policies; solve puzzle at https://adventofcode.com/2020/day/2
646
645
  2 December 2020
@@ -262,7 +262,6 @@
262
262
  :url: https://www.reddit.com/r/adventofcode/comments/1h4ncyr/2024_day_2_solutions/m02ns7r
263
263
  :body: |-
264
264
  ```ruby
265
-
266
265
  puts File.read('input.txt').split("\\n").map { |line| line.split.map(&:to\_i) }.then { |data| safe = ->(r) { (r.each\_cons(2).all? { |a, b| a < b } || r.each\_cons(2).all? { |a, b| a > b }) && r.each\_cons(2).all? { |a, b| (1..3).cover?((a - b).abs) } }; "#{data.count { |r| safe\[r\] }} #{data.count { |r| safe\[r\] || (0...r.length).any? { |i| safe\[r\[0...i\] + r\[(i+1)..-1\]\] } }}"}
267
266
  ```
268
267
  :replies: []
@@ -0,0 +1,187 @@
1
+ ---
2
+ - :author: StillFast7545
3
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nsku8t6
4
+ :body: |-
5
+ Part 1: [https://github.com/MarioPerac/AdventOfCode2025/blob/main/day\_1/secret\_entrance\_part\_1.rb](https://github.com/MarioPerac/AdventOfCode2025/blob/main/day_1/secret_entrance_part_1.rb)
6
+
7
+ Part 2: [https://github.com/MarioPerac/AdventOfCode2025/blob/main/day\_1/secret\_entrance\_part\_2.rb](https://github.com/MarioPerac/AdventOfCode2025/blob/main/day_1/secret_entrance_part_2.rb)
8
+
9
+ Puzzle solved with a circular linked list.
10
+ :replies: []
11
+ - :author: Few-Orchid-8393
12
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/ns61umj
13
+ :body: |-
14
+ part two in 9 lines (at a comfy and traditional 80-char width):
15
+
16
+ ```ruby
17
+ position = 50
18
+ password = 0
19
+ ARGF.each_line do |instruction|
20
+ rotation = instruction.sub(/^L/, "-").sub(/^R/, "").to_i
21
+ direction = rotation <=> 0
22
+ password += ((direction * rotation) + ((direction * position) % 100)) / 100
23
+ position = (position + rotation) % 100
24
+ end
25
+ puts password
26
+ ```
27
+
28
+ I chose Ruby because it's an elegant language, and I've been doing a little scripting in it recently. It's not as popular as it deserves to be, imo.
29
+
30
+ Since I stripped the comments from this rendition, here's the whole idea: because integer division with negatives is a little weird, for password computation purposes I render "negative" (leftward) rotation as "positive) (rightward) rotation. To do that I want to flip the sign on the rotation if it's positive, and flip the sign on the position (before restoring it to Zmod100, no negatives allowed).
31
+
32
+ By computing the sign of the rotation, I get to do this without any `if` expressions, which is pretty cool. When the direction is rightward, all the extra computation in the `password +=` expression does nothing; it's the same as `(position + rotation) / 100`. But when the direction is leftward, that formula inverts both the original position and the rotation, treating it as rightward rotation from the equivalent complementary position on the dial.
33
+ :replies: []
34
+ - :author: Nnnes
35
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nro9mh3
36
+ :body: |-
37
+ Not very many half-punchcard solutions yet (and an unfortunate number of oversized solutions in comments). Here's one for both parts including an attempt at descriptive comments:
38
+
39
+ ```ruby
40
+ puts STDIN.readlines.reduce([50, 0, 0]) { |a, x| # [Initial position, P1, P2]
41
+ n = a[0] + x.tr('LR', '-+').to_i # Current dial position (not mod 100 yet)
42
+ z = n % 100 == 0 ? 1 : 0 # Is it set to zero now?
43
+ [n % 100, a[1] + z, a[2] + n.abs / 100 + (a[0] > 0 && n <= 0 ? 1 : 0)]
44
+ }[1, 2] # ^P1 , ^P2: ^Count spins, ^Add 1 if it decreased to/past 0
45
+ ```
46
+
47
+ For parsing, `L`s and `R`s are simply turned into `-`s and `+`s before the string is parsed as an integer.
48
+
49
+ For Part 2's edge case handling, I initially used a multiply-by-zero trick `(a[0] * (n - 1) < 0 ? 1 : 0)`, but that's the same length as the much clearer version above.
50
+
51
+ Results are added up using a simple `.reduce()` accumulator (the `a`).
52
+ :replies:
53
+ - :author: riffraff
54
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nroeeh5
55
+ :body: the `tr`usage is very clever, love it!
56
+ :replies: []
57
+ - :author: SleepingInsomniac
58
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nrqu8i5
59
+ :body: |-
60
+ ## Part 1
61
+
62
+ ```ruby
63
+ def solve(input)
64
+ pointer = 50
65
+ zeros = 0
66
+
67
+ until input.eof?
68
+ rotation = input.readline&.chomp
69
+ dist = rotation.gsub('L', '-').gsub('R', '').to_i
70
+ pointer = (pointer + dist) % 100
71
+ zeros += 1 if pointer == 0
72
+ end
73
+
74
+ zeros
75
+ end
76
+ ```
77
+
78
+ ## Part 2
79
+
80
+ ```ruby
81
+ def solve(input, size = 100)
82
+ pointer = 50
83
+ zeros = 0
84
+
85
+ while rotation = input.readline&.chomp
86
+ dist = rotation.gsub('L', '-').gsub('R', '').to_i
87
+ prev_pointer = pointer
88
+ pointer += dist
89
+ crossings, pointer = pointer.divmod(size)
90
+ crossings = crossings.abs
91
+
92
+ crossings -= 1 if pointer == 0 && dist.positive?
93
+ crossings -= 1 if prev_pointer == 0 && dist.negative?
94
+ crossings += 1 if pointer == 0
95
+
96
+ zeros += crossings
97
+
98
+ break if input.eof?
99
+ end
100
+
101
+ zeros
102
+ end
103
+ ```
104
+ :replies: []
105
+ - :author: riffraff
106
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nroeoal
107
+ :body: |-
108
+ straightforward but verbose, there are better solutions
109
+
110
+ ```ruby
111
+ def solve_easy(lines)
112
+ res = 0
113
+ pos = 50
114
+ lines.each do |line|
115
+ move = line[0] == 'L' ? -1 : 1
116
+ num = line[1..].to_i
117
+ pos = (pos + move * num) % 100
118
+ res += 1 if pos == 0
119
+ end
120
+ res
121
+ end
122
+
123
+ def solve_hard(lines)
124
+ res = 0
125
+ pos = 50
126
+ lines.each do |line|
127
+ move = line[0] == 'L' ? -1 : 1
128
+ num = line[1..].to_i
129
+ num.times do
130
+ pos = (pos + move) % 100
131
+ res += 1 if pos == 0
132
+ end
133
+ end
134
+ res
135
+ end
136
+ ```
137
+ :replies: []
138
+ - :author: im_sofi
139
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nrow8a0
140
+ :body: |-
141
+ Couldn't wrap my head around Day 1 part 2 for the longest of times, but with some tests made it quite trivial to implement without using counting.
142
+
143
+ https://codeberg.org/soupglasses/advent-of-code/src/branch/main/2025/day\_01.rb
144
+ :replies: []
145
+ - :author: onyx_and_iris
146
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nroyuzs
147
+ :body: "[https://git.onyxandiris.online/onyx\\_online/aoc2025/src/branch/main/day\\_01](https://git.onyxandiris.online/onyx_online/aoc2025/src/branch/main/day_01)"
148
+ :replies: []
149
+ - :author: justjarvo
150
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nrq9co3
151
+ :body: |-
152
+ Initially did both parts with floor/modulo but kept getting off-by-one errors for part 2 so I just stepped through like a heathen
153
+
154
+ ```ruby
155
+ dial, p1, p2 = 50, 0, 0
156
+
157
+ input.each do |ins|
158
+ ins[1..].to_i.times do
159
+ dial += ins[0] == "R" ? 1 : -1
160
+ dial = 99 if dial == -1
161
+ dial = 0 if dial == 100
162
+ p2 += 1 if dial == 0
163
+ end
164
+ p1 += 1 if dial == 0
165
+ end
166
+
167
+ p [p1, p2]
168
+ ```
169
+ :replies:
170
+ - :author: kronn
171
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nrqr5md
172
+ :body: I was equally frustrated and came to the same low as you did.
173
+ :replies: []
174
+ - :author: srugh
175
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nrs0rxs
176
+ :body: |-
177
+ Part 1 (solve\_part\_1) and Part 2 (solve\_part\_2) each individually solved in a single file with a shared parsing function (parse\_input):
178
+
179
+ [GitHub 2025/Day-01.rb](https://github.com/srugh/AdventOfCode/blob/main/2025/day-01.rb)
180
+ :replies: []
181
+ - :author: Sharparam
182
+ :url: https://www.reddit.com/r/adventofcode/comments/1pb3y8p/2025_day_1_solutions/nro151z
183
+ :body: |-
184
+ [GitHub](https://github.com/Sharparam/advent-of-code/blob/main/src/y2025/d01/solve.rb)
185
+
186
+ In my sleep deprived state I can't come up with a cleaner version for now, maybe I'll come back later™ and make it nicer.
187
+ :replies: []
@@ -0,0 +1,185 @@
1
+ ---
2
+ - :author: StillFast7545
3
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nskv362
4
+ :body: |-
5
+ Part 1: [https://github.com/MarioPerac/AdventOfCode2025/blob/main/day\_2/gift\_shop\_part\_1.rb](https://github.com/MarioPerac/AdventOfCode2025/blob/main/day_2/gift_shop_part_1.rb)
6
+
7
+ Part 2: [https://github.com/MarioPerac/AdventOfCode2025/blob/main/day\_2/gift\_shop\_part\_2.rb](https://github.com/MarioPerac/AdventOfCode2025/blob/main/day_2/gift_shop_part_2.rb)
8
+ :replies: []
9
+ - :author: justjarvo
10
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrupo4w
11
+ :body: ". I am not good at math, so string manipulation it is \U0001F605 I wouldn't mind being pointed to some material to help me figure out how to approach this without all the string work.\n\n```ruby\ndef p1_invalid?(str)\n n = str.size\n n.even? && str[0, n/2] == str[n/2, n/2]\nend\n\ndef p2_invalid?(str)\n n = str.size\n\n (1...n).each do |m|\n next unless n % m == 0\n return true if str == str[0, m] * (n / m)\n end\n\n false\nend\n\ninput = File.read(\"input/d02.txt\").split(\",\")\np1, p2 = 0, 0\ninput.each do |range|\n Range.new(*range.split(\"-\").map(&:to_i)).each do |num|\n p1 += num if p1_invalid?(num.to_s)\n p2 += num if p2_invalid?(num.to_s)\n end\nend\n\np [p1, p2]\n```"
12
+ :replies: []
13
+ - :author: srugh
14
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrxw6zq
15
+ :body: |-
16
+ Shared parsing, other wise part 1 (compare halves of string) and part 2 (compare chunks to full string) both independently solved.
17
+
18
+ [GitHub: Day-02 parts 1 and 2](https://github.com/srugh/AdventOfCode/blob/main/2025/day-02.rb)
19
+ :replies: []
20
+ - :author: pedantic_git
21
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nruo72g
22
+ :body: |-
23
+ It's brute force, sure, but I'm really happy with how elegant my solution is, thanks to regexps. It could be terser still but I wanted it to still be readable!
24
+
25
+ ```ruby
26
+ #!/usr/bin/env ruby
27
+
28
+ acc1, acc2 = 0, 0
29
+
30
+ ARGF.read.scan(/(\d+)-(\d+)/) do |l,r|
31
+ (l.to_i).upto(r.to_i) do
32
+ acc1 += it if /\A(.+)\1\Z/ =~ it.to_s
33
+ acc2 += it if /\A(.+)\1+\Z/ =~ it.to_s
34
+ end
35
+ end
36
+
37
+ puts acc1, acc2
38
+ ```
39
+ :replies:
40
+ - :author: _tfa
41
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nruokq9
42
+ :body: Nice. To make it even shorter you could use strings in the upto-loop and only call to\_i when adding "it" to the accumulators.
43
+ :replies:
44
+ - :author: pedantic_git
45
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrur3dt
46
+ :body: Ooh - it feels dirty using `upto` on a string, like it's going to sort them asciibetically or something, but it does seem to work!
47
+ :replies: []
48
+ - :author: SleepingInsomniac
49
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrwuvy2
50
+ :body: |-
51
+ ## Part 1
52
+
53
+ ```ruby
54
+ class IDRange
55
+ def self.parse(file)
56
+ return nil if file.eof?
57
+ IDRange.new(*file.gets(',').gsub(/,$/, '').split('-'))
58
+ end
59
+
60
+ def initialize(start, stop)
61
+ @start, @stop = start.to_i, stop.to_i
62
+ end
63
+
64
+ def range = (@start..@stop)
65
+ def invalid_ids = range.select { |n| n.to_s =~ /^(\d+)\1$/ }
66
+ end
67
+
68
+ def solve(input)
69
+ total = 0
70
+ while range = IDRange.parse(input)
71
+ total += range.invalid_ids.sum
72
+ end
73
+ total
74
+ end
75
+ ```
76
+
77
+ ## Part 2
78
+
79
+ ```ruby
80
+ ...
81
+ def invalid_ids = range.select { |n| n.to_s =~ /^(\d+)\1+$/ }
82
+ ...
83
+ ```
84
+ :replies: []
85
+ - :author: im_sofi
86
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrxps5w
87
+ :body: |-
88
+ Absolutely got stuck on an assumption that 1-9 was valid numbers for part 2.
89
+
90
+ Part 1 and 2 are done by enforcing each rule and picking the lowest next number. Regex is only used for parsing. :)
91
+
92
+ https://codeberg.org/soupglasses/advent-of-code/src/branch/main/2025/day\_02.rb
93
+ :replies: []
94
+ - :author: riffraff
95
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nruhu7c
96
+ :body: |-
97
+ The simplest thing I could think of, tho it is quite slow since it creates a ton of garbage, but it works. Fun fact: `Integer#digits` gives the numbers ordered from the least significant to the most, but it seems to work anyway.
98
+
99
+ ```ruby
100
+ def parse(io)
101
+ io.read.scan(/(\d+)-(\d+)/).map { |a, b| (a.to_i)..(b.to_i) }.to_a
102
+ end
103
+
104
+ def same_subarray?(array, length)
105
+ parts = array.each_slice(length)
106
+ parts.uniq.length == 1
107
+ end
108
+
109
+ def invalid?(digits)
110
+ return false if digits.length.odd?
111
+ same_subarray?(digits, digits.length / 2)
112
+ end
113
+
114
+ def invalid_hard?(digits)
115
+ 1.upto(digits.length / 2).any? { |len| same_subarray?(digits, len) }
116
+ end
117
+
118
+ def solve(ranges, &block)
119
+ ranges.sum do |r|
120
+ r.sum do |number|
121
+ block.call(number.digits) ? number : 0
122
+ end
123
+ end
124
+ end
125
+
126
+ def solve_easy(ranges)
127
+ solve(ranges) { |number| invalid?(number) }
128
+ end
129
+
130
+ def solve_hard(ranges)
131
+ solve(ranges) { |number| invalid_hard?(number) }
132
+ end
133
+ ```
134
+ :replies:
135
+ - :author: riffraff
136
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nruiioj
137
+ :body: btw, this works with ranges of strings too, as you can do `'1'..'20'` and get `"1","2","3",..,"20"` but I never trust that :)
138
+ :replies: []
139
+ - :author: systemnate
140
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrwmy2f
141
+ :body: |-
142
+ ```ruby
143
+ data = data.split(",")
144
+ .map { |range| range.split("-") }
145
+ .map { |first, last| (first.to_i..last.to_i) }
146
+
147
+ class Product
148
+ def self.invalid?(product_id)
149
+ product_id = product_id.to_s
150
+ middle_point = product_id.length / 2
151
+ product_id.chars[0...middle_point] == product_id.chars[middle_point..]
152
+ end
153
+
154
+ def self.really_invalid?(product_id)
155
+ product_id = product_id.to_s
156
+
157
+ (1..product_id.length / 2).each do |length|
158
+ pattern = product_id[0...length]
159
+
160
+ return true if pattern * (product_id.length / length) == product_id
161
+ end
162
+
163
+ false
164
+ end
165
+ end
166
+
167
+ # part 1
168
+ invalid_numbers = data.each_with_object([]) do |range, invalids|
169
+ invalids << range.select { |n| Product.invalid?(n) }
170
+ end.flatten.compact
171
+
172
+ puts invalid_numbers.sum
173
+
174
+ # part 2
175
+ invalid_numbers = data.each_with_object([]) do |range, invalids|
176
+ invalids << range.select { |n| Product.really_invalid?(n) }
177
+ end.flatten.compact
178
+
179
+ puts invalid_numbers.sum
180
+ ```
181
+ :replies: []
182
+ - :author: onyx_and_iris
183
+ :url: https://www.reddit.com/r/adventofcode/comments/1pbzqcx/2025_day_2_solutions/nrukvww
184
+ :body: "[https://git.onyxandiris.online/onyx\\_online/aoc2025/src/branch/main/day\\_02](https://git.onyxandiris.online/onyx_online/aoc2025/src/branch/main/day_02)"
185
+ :replies: []