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:

  1. Opens a file at the given path
  2. Reads it line by line
  3. 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:

  1. Takes a string that contains numbers (like “123 456 -789”)
  2. Finds all the numbers in that string
  3. Returns them as a slice of integers
  4. 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:

  1. First, we read our input file:
input := aoc.ReadFileLineByLine("input.txt")
  1. Then we get the numbers from each line:
intArrays := getNumArrayFromColumns(input)
  1. 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.