Contents
Recipe Notes
Introduction
Today, I tackled Day 1 of Advent of Code 2024, titled “Historian Hysteria.” The puzzle involves comparing two lists of numbers. Let’s look at how we can solve this using Go, breaking down each part to make it easy to understand.
The AOC Library
First, let’s look at the helper functions I created to make working with input files easier. These functions handle common tasks that we’ll need throughout the Advent of Code challenges.
Reading Files
func ReadFileLineByLine(path string) []string {
file, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
defer file.Close()
var output []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
output = append(output, scanner.Text())
}
return output
}
This function does three simple things:
- Opens a file at the given path
- Reads it line by line
- Returns all lines as a slice of strings
Getting Numbers from Text
func FetchSliceOfIntsInString(line string) []int {
nums := []int{}
var build strings.Builder
isNegative := false
for _, char := range line {
// If we find a digit, add it to our number
if unicode.IsDigit(char) {
build.WriteRune(char)
}
// Check for negative numbers
if char == '-' {
isNegative = true
}
// When we hit a space or comma, convert what we've built into a number
if (char == ' ' || char == ',' || char == '~') && build.Len() != 0 {
localNum, err := strconv.ParseInt(build.String(), 10, 64)
if err != nil {
panic(err)
}
if isNegative {
localNum *= -1
}
nums = append(nums, int(localNum))
build.Reset()
isNegative = false
}
}
// Handle the last number if there is one
if build.Len() != 0 {
localNum, err := strconv.ParseInt(build.String(), 10, 64)
if err != nil {
panic(err)
}
if isNegative {
localNum *= -1
}
nums = append(nums, int(localNum))
}
return nums
}
This function:
- Takes a string that contains numbers (like “123 456 -789”)
- Finds all the numbers in that string
- Returns them as a slice of integers
- Handles negative numbers and different separators (spaces, commas)
Working with Grids
func Get2DGrid(input []string) (grid [][]string) {
for _, line := range input {
grid = append(grid, strings.Split(line, ""))
}
return
}
This function converts a list of strings into a grid (2D array). For example, it would turn:
abc
def
into:
[["a", "b", "c"], ["d", "e", "f"]]
Breaking Up Strings
func SplitStringAfter(input string, length int) (output []string) {
startIndex := 0
for startIndex < len(input) {
output = append(output, input[startIndex:startIndex+length])
startIndex += length
}
return
}
This function breaks a long string into smaller pieces of a specified length.
[Previous solution sections remain the same…]
Using the Library
Here’s how we use these functions in our Day 1 solution:
- First, we read our input file:
input := aoc.ReadFileLineByLine("input.txt")
- Then we get the numbers from each line:
intArrays := getNumArrayFromColumns(input)
- This gives us two lists of numbers that we can work with to solve the puzzle.
Conclusion
These helper functions make it easier to focus on solving the actual puzzle instead of worrying about how to read files or convert strings to numbers. They’re designed to be reusable across different Advent of Code challenges.
You can find the complete code in my GitHub repository. If you’re learning Go, feel free to use these functions in your own solutions!
Tip: When solving programming puzzles, it’s helpful to create reusable functions for common tasks. This lets you focus on the interesting parts of each new challenge.