Meet Rajesh Gor

Advent of Code, 2024, Day 1 in Golang: Historian Hysteria

Introduction

Hello everyone, it’s that time of the year, Advent of Code, I will be solving this year as well with Golang. In previous years I have been doing Advent of Code but was not able to keep up with the pace and left it midway (not even halfway). This year however I am determined and want to solve all the problems as much as I can.

Let’s dive into the first day which should be and is pretty simple and straightforward. A simple list and map creation and traversal and basic math operations.

I also live-streamed the solution, you can check it out the stream on YouTube

And also a shorter video on the approach and solution in Golang.

Or you stick here and continue reading. Thank you

You can check out my solutions here on GitHub.

Part 1

Advent of code, 2024, day 1

We are given two lists here, the first part aims to find the absolute difference (distance) between each element sorted from smallest to largest.

So, in essence, we take the two lists, sort them and one by one, for each corresponding element paired up, we take the absolute difference and sum that difference up for all the numbers in the list.

3   4
4   3
2   5
1   3
3   9
3   3

So, first, we need to split the input into different lists:

  1. We first range over all the lines, initialize two empty lists of integers

  2. Then we split the line with the space as the separator, so this gives us the slice of strings as [“3”, “4”]

  3. But we need to elements as integers, so take the first number and convert it to integer, similarly we do it for the second number.

  4. Then once we have both numbers, we append them to the corresponding lists, the first number goes to the first list, and the second is appended to the second list.

  5. Then we return the two lists

NOTE: You cannot take the difference of those two numbers here itself, since we need to find the smallest number and sort the numbers in each list, so we need to get the lists populated first.

func SplitLists(lines []string) ([]int, []int) {
	listOne := []int{}
	listTwo := []int{}

	for _, line := range lines {
		// |3   4
		// ["3","4"] slice of string ([]string)
		// 3 
        // 4
        // [3,4] slice of int ([]int)
		numbers := strings.Split(line, "   ")
		numOne, err := strconv.Atoi(numbers[0])
		if err != nil {
			log.Fatal(err)
		}
		numTwo, err := strconv.Atoi(numbers[1])
		if err != nil {
			log.Fatal(err)
		}
		listOne = append(listOne, numOne)
		listTwo = append(listTwo, numTwo)
	}
	return listOne, listTwo
}

In the above code, we have initialized two empty slices of strings, we take the parameter lines which is a slice of string, indicating a line-by-line string representation of the input. I have parsed the input with these helper functions.

The ReadFileBytes and ReadFileLines, one the bytes, the other gives the line-by-line string which gives a slice of strings.

So once we have the lines, we iterate over each line and split the lines on space to get the two numbers. So, the line “3 4“ will be split into [“3”, “4”] . Now we get the first element and convert it into an integer as we need to sort and take the difference later.

So, by accessing the first and second elements in the split line as numbers[0] and numbers[1] and converting the type to integer, strconv.Atoi function, which takes in a string and gives back an integer or an error.

Now, we have two numbers as integers, we append the first element to the first element as listOne = append(listOne, numOne) and listTwo = append(listTwo, numTwo)

So, we append one by one as we iterate over the input through all the lines, so at the end of this function, we will have two lists of integers.

[3 4 2 1 3 3]
[4 3 5 3 9 3]

Then, once we have the slices of integers, we sort those lists. Then we range over the lists one by one element, since both the lists are of the same size, we can reference one by the index of the other.

Then for each difference of the two integers (one from the first list and the other from the second list), we cast it to a float64 and pass it to the math.Abs function, which is annoying as Golang doesn’t have an absolute function for intgers. We cast the integer to float for parsing it to the Abs method and cast the returned float64 value back to int. Kind of wired but fine.

We keep adding the absolute differences for each paired difference of the elements in the two lists. At the end, we will have a final score which is the score for part one.

func PartOne(lines []string) int {
	listOne, listTwo := SplitLists(lines)
	sort.Ints(listOne)
	sort.Ints(listTwo)
	totalScore := 0
	for i := range listOne {
		totalScore += int(math.Abs(float64(listOne[i] - listTwo[i]))
	}
	return totalScore
}

Part 2

For part two, we need to take all the numbers in the first list count the number of times that number has occurred in the second list, and take a product of them and add it up for all the numbers.

So in the example:

3   4
4   3
2   5
1   3
3   9
3   3

The numbers in the first list are [3,4,2,1,3,3]

We have to count the occurrences of each of them in the second list

So, in the second list [4,3,5,3,9,3], the number 3 occurs 3 times, so we do 3×3 which is 9 and then, do the same for 4 which occurs only once in the second list so, we get 4, then 2 occurs 0 times, so we get 0

We get → (3×3) + (4×1) + (2×0) + (1×0) + (3×3) + (3×3)

The first number is the element in the first list and the second number is the occurrence of that number in the second list.

which comes out to be 9+4+0+0+9+9 , so the answer is 31 for the example.

Once it is clear, what we have to do, we simply have to iterate over the second list and create a map of the frequency/occurances/number of times it appears in that list.

Solution

So, we will have to modify the SplitLists functions a bit, we need to split and also map the second list with the key as the number itself and the value as its count in the second list.

Just that change, we create an additional return value with an empty map of integers with integers. The mapTwo variable will be a map that will have a key as the number in the second list and its value as the number of times it is present in that list.

func SplitListsAndMap(lines []string) ([]int, map[int]int) {
	listOne := []int{}
	listTwoCounts := make(map[int]int)

	for _, line := range lines {
		numbers := strings.Split(line, "   ")
		numOne, err := strconv.Atoi(numbers[0])
		if err != nil {
			log.Fatal(err)
		}
		numTwo, err := strconv.Atoi(numbers[1])
		if err != nil {
			log.Fatal(err)
		}
		listOne = append(listOne, numOne)
        listTwoCounts[numTwo] += 1
	}
	return listOne, listTwoCounts
}

So, as we iterate over each line, we parse the string number into an integer and increment its count in the map.

[3 4 2 1 3 3]
map[3:3 4:1 5:1 9:1]

In the actual calculation of the score, we need to iterate over the elements of the first list and multiply the number with its count in the second list as we now have the map of it. We multiply those and add them up for each line, which becomes the final score.

func PartTwo(lines []string) int {
    similarityScore := 0

	listOne, mapTwo := SplitListsAndMap(lines)

	for _, numOne := range listOne {
		score := numOne * mapTwo[numOne]
		similarityScore += score
	}

	return similarityScore
}

So, that is how we got the final score for part two.

You can check out my solutions here on GitHub.

Conclusion

So that was it, a pretty simple problem for day 1 of the advent of code 2024 in Golang. Hope you enjoyed this walkthrough of the day one puzzle in the Advent of Code 2024 in Golang.

Thank you for reading, and I will see you tomorrow for day 2

Happy Coding :)