Advent of Code 2025 in GO - Day 1 - Part #2

Thumbnail for Advent of Code 2025 in GO

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.


In case you prefer learning with a video, checkout my YouTube video 📺

Habibi Coding Video - Debian VS Ubuntu


Day 1: Secret Entrance Part 2

part two instrcutions


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.

Unit Testing

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

Solution part two

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.

Conclusion

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



Frequently Asked Questions

Find answers to common questions about Go and programming challenges

How do you reverse a string in Go?

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.

What is the difference between slices and arrays in Go?

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.

How do you implement a binary search in Go?

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
}

How do you handle errors in Go?

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.

What is the purpose of the 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.

How would you implement a circular buffer in Go?

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
}

Want to buy me a coffee?