Skip to content

Commit 62e002c

Browse files
alexandruCopilot
andauthored
Add blog post for day 03 / 2025 (#866)
* Document puzzle day03 with Scala solutions Added detailed explanations and Scala solutions for both parts of the puzzle, including input examples and algorithm descriptions. * Refine explanations * Re-adds some comments * Update docs/2025/puzzles/day03.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update docs/2025/puzzles/day03.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add author --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 95c5cf6 commit 62e002c

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

docs/2025/puzzles/day03.md

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,123 @@ import Solver from "../../../../../website/src/components/Solver.js"
22

33
# Day 3: Lobby
44

5+
by [@alexandru](https://github.com/alexandru)
6+
57
## Puzzle description
68

79
https://adventofcode.com/2025/day/3
810

11+
Input is made of lines with digits, like:
12+
13+
```
14+
987654321111111
15+
811111111111119
16+
234234234234278
17+
818181911112111
18+
```
19+
20+
## Part 1
21+
22+
Part 1 is about extracting, for each line, the largest 2-digit number made from individual digits picked from that line, while maintaining their original order:
23+
24+
- **98**7654321111111: `98`
25+
- **8**1111111111111**9**: `89`
26+
- 2342342342342**78**: `78`
27+
- 818181**9**1111**2**111: `92`
28+
29+
To find the maximum 2-digit number for each line, we use a nested loop approach with `O(n²)` time complexity per line. After parsing the input, the solution for part 1 becomes:
30+
31+
```scala
32+
def part1(input: String): Long = {
33+
input
34+
// Split input into lines (separated by newline)
35+
.split("\\s*\\n\\s*")
36+
.view
37+
// Trim and filter out non-empty strings (just a precaution)
38+
.map(_.trim)
39+
.filter(_.nonEmpty)
40+
// For each line, calculate its maximum
41+
.map { line =>
42+
// Loop in loop for getting that 2-char max
43+
(0 until line.length - 1)
44+
.view
45+
.map { i =>
46+
// Second loop picking the second char (loop-in-loop)
47+
(i + 1 until line.length)
48+
// Concatenate the two chars
49+
.map(j => s"${line.charAt(i)}${line.charAt(j)}".toLong)
50+
// Calculate the maximum
51+
.max
52+
}
53+
.max
54+
}
55+
// Sum them all
56+
.sum
57+
}
58+
```
59+
60+
## Part 2
61+
62+
Part 2 extends the problem by asking for 12-digit numbers (instead of 2-digit numbers).
63+
64+
```scala
65+
def max(line: String, remaining: Int): String = {
66+
// Select the index of the largest digit from our `line`.
67+
// We must not search beyond `line.length - remaining + 1`
68+
// to ensure we have enough characters left for the remaining digits.
69+
val maxIdx = (0 until line.length - remaining + 1)
70+
.maxBy(i => line.charAt(i))
71+
// Build the remaining digits by recursively processing
72+
// the substring after our selected character
73+
val rest =
74+
if remaining > 1 then
75+
// recursive call, unsafe!
76+
max(line.substring(maxIdx + 1), remaining - 1)
77+
else
78+
""
79+
// We concatenate the found char (at `maxIdx`) with the `rest`
80+
s"${line.charAt(maxIdx)}$rest"
81+
}
82+
```
83+
84+
To give an example of how this would work in practice, for a line like "23**4**2**34234234278**", we have these steps executed via recursive calls, which will produce `434234234278`:
85+
86+
```scala
87+
"4" + max(line0.substring(3), 11)
88+
"3" + max(line1.substring(2), 10)
89+
"4" + max(line2.substring(1), 9)
90+
"2" + max(line3.substring(1), 8)
91+
"3" + max(line4.substring(1), 7)
92+
"4" + max(line5.substring(1), 6)
93+
"2" + max(line6.substring(1), 5)
94+
"3" + max(line7.substring(1), 4)
95+
"4" + max(line8.substring(1), 3)
96+
"2" + max(line9.substring(1), 2)
97+
"7" + max(line10.substring(1), 1)
98+
"8" + ""
99+
```
100+
101+
We can now create a unified function that handles both parts by parameterizing the number of digits:
102+
103+
```scala
104+
def process(charsCount: Int)(input: String): Long =
105+
// Splits input by newlines
106+
input.split("\\s*\\n\\s*")
107+
.view
108+
// Trim and filter out empty lines
109+
.map(_.trim)
110+
.filter(_.nonEmpty)
111+
// For each line, calculate its max
112+
.map { line =>
113+
max(line, charsCount).toLong
114+
}
115+
// sum them all up
116+
.sum
117+
118+
def part1(input: String): Long = process(2)(input)
119+
def part2(input: String): Long = process(12)(input)
120+
```
121+
9122
## Solutions from the community
10123

11124
Share your solution to the Scala community by editing this page.

0 commit comments

Comments
 (0)