In my previous blog post part 1 I showed one way to solve the first part of day 1. Now let us continue with part two of day 1. As always with Advent of Code challenges the second part of the challenge is much harder to solve. Sometimes I even had to rethink my challenge one solution.
Okay now the big difference is we always also count when 0 is passed and also when the
dial stops at 0. I had to rethink my whole solution for part one here is what I came up
with:
func countDialPointsAndPassedZero(rotations []Rotator) int {
dialPos := 50
counter := 0
for _, rotator := range rotations {
if rotator.direction == "R" {
counter += (dialPos + rotator.steps) / allHundredPos
dialPos = (dialPos + rotator.steps) % allHundredPos
} else {
// If we start at 0, we only hit 0 again after a full 100 steps
startPos := dialPos
if dialPos == zeroPos {
startPos = allHundredPos
}
// Check if we move far enough to reach or pass the '0' mark.
// Note: if we start at 0, 'startPos' is 100, meaning we only hit zero again if we complete a full rotation.
if rotator.steps >= startPos {
// We count 1 for the first time we hit or pass zero.
// Then add 1 for every full 100-step rotation thereafter.
counter += moveOneStep + (rotator.steps-startPos)/allHundredPos
}
// Update the dial position:
// Use (steps % 100) to find the relative movement, subtract it from the current position.
// Add 100 before taking the modulo again to ensure the result is always a positive index between 0 and 99.
dialPos = (dialPos - (rotator.steps % allHundredPos) + allHundredPos) % allHundredPos
}
}
return counter
}
Initialization: The dial starts at position 50.
Right Rotations ("R"): For each right rotation, it calculates how many full 100-step
rotations occur
(adding to the counter) and updates the dial position using modulo arithmetic.
Left Rotations (not "R"): For left rotations, it checks if the movement is enough to reach or
pass "0" from the current
position. If so, it increments the counter for each full rotation and updates the dial position,
ensuring it stays within 0–99.
Return Value: The total count of times the dial passed or landed on "0" during all
rotations.
Now, open again secret_entrance_test.go and let us again start with a table-driven test
for the core logic:
func TestCountDialPointsAndPassedZero(t *testing.T) {
tests := []struct {
name string
input []Rotator
want int
}{
{
name: "multiple instructions",
input: []Rotator{
{"L", 68},
{"L", 30},
{"R", 48},
{"L", 5},
{"R", 60},
{"L", 55},
{"L", 1},
{"L", 99},
{"R", 14},
{"L", 82},
},
want: 6,
},
{
name: "zero instructions",
input: []Rotator{},
want: 0,
},
{
name: "single instruction",
input: []Rotator{
{"R", 1000},
},
want: 10,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := countDialPointsAndPassedZero(test.input)
if got != test.want {
t.Errorf("%s: countDialPointsAndPassedZero() = %d; want %d", test.name, got, test.want)
}
})
}
}
For this test I simply added the sample input of rotations which was given from the instructions.
Now, if you run go test ./... from your Terminal in the root directory you should see:
ok advent-of-code-2025-blog/internal/util 0.502s
Open again main.go add these lines:
package main
import (
"advent-of-code-2025-blog/internal/util"
"fmt"
"log"
)
func main() {
input, err := util.ReadInput("../advent-of-code-2025/cmd/day01/input1.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println("The password for Part1 is: ", countDialPointsZero(generateInstructions(input)))
fmt.Println("The password for Part2 is: ", countDialPointsAndPassedZero(generateInstructions(input)))
}
Then run the code and see copy the output.
This Go implementation for day 1 part 2 should solve the challenge efficiently as possible. If you had problems to follow along for part one and two just checkout my: GitHub Repo
Here is the link to Part 1
Find answers to common questions about Go and programming challenges
In Go, you can reverse a string by converting it to a slice of runes, then iterating from the end to the start. Here's a simple example:
func reverseString(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
This approach handles Unicode characters correctly.
In Go, arrays are fixed-length sequences of elements of a particular type, while slices are dynamically-sized, flexible views into arrays. Arrays are value types, so assigning an array to a new variable copies all its elements. Slices are reference types and are much more commonly used due to their flexibility.
Binary search is an efficient algorithm for finding an item in a sorted slice. Here's a basic implementation:
func binarySearch(arr []int, target int) int {
low, high := 0, len(arr)-1
for low <= high {
mid := low + (high-low)/2
if arr[mid] == target {
return mid
} else if arr[mid] < target {
low = mid + 1
} else {
high = mid - 1
}
}
return -1
}
Go uses explicit error handling. Functions return an error as their last return value, and it's idiomatic to check errors immediately. For example:
file, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
Go does not use exceptions; errors are values, making error handling predictable and explicit.
defer statement in Go?
The defer statement postpones the execution of a function until the surrounding function
returns.
It's commonly used for cleanup tasks, such as closing files or releasing resources, ensuring they run
even if an error occurs.
Deferred calls are executed in LIFO (last-in, first-out) order.
A circular buffer (or ring buffer) is a fixed-size data structure that overwrites the oldest data when full. Here's a basic implementation:
type CircularBuffer struct {
buffer []int
size int
head int
tail int
count int
}
func NewCircularBuffer(size int) *CircularBuffer {
return &CircularBuffer{buffer: make([]int, size), size: size}
}
func (cb *CircularBuffer) Enqueue(item int) {
if cb.count == cb.size {
// Buffer full, overwrite oldest
cb.buffer[cb.tail] = item
cb.tail = (cb.tail + 1) % cb.size
cb.head = (cb.head + 1) % cb.size
} else {
cb.buffer[cb.head] = item
cb.head = (cb.head + 1) % cb.size
cb.count++
}
}
func (cb *CircularBuffer) Dequeue() (int, error) {
if cb.count == 0 {
return 0, errors.New("buffer is empty")
}
item := cb.buffer[cb.tail]
cb.tail = (cb.tail + 1) % cb.size
cb.count--
return item, nil
}