Advent of Code 2025 Day 6

Part 1

The input today is a series of columns, containing numbers until the final row, which is a mathematic operator (multiplication or addition). Each column represents a problem.

Solution

Our only data structure today is a problem, which has an operator and a slice of numbers:

const (
	OP_PRODUCT = iota
	OP_SUM
)

type Problem struct {
	operation int
	numbers   []int
}

We then need to read the input and convert it into problems. The input format is slightly inconvenient as the problems are represented as columns - if they were rows then we could simply read one line at a time and directly convert it by creating one Problem at a time. With columns, we need to find the number of columns first, create that many Problems, and then populate them. However, this is straightforward as we can count the number of columns in the first line and then use make to create a slice of Problems that is the right size.

func getProblems(input string) []Problem {
	lines := strings.Split(input, "\n")

	// Number of problems is equal to the number of columns of the first line
	firstLineColumns := strings.Fields(lines[0])

	problems := make([]Problem, len(firstLineColumns))

	for lineIndex := range lines {
		columns := strings.Fields(lines[lineIndex])

		for c := range columns {
			switch columns[c] {
			case "*":
				problems[c].operation = OP_PRODUCT
			case "+":
				problems[c].operation = OP_SUM
			default:
				number, _ := strconv.Atoi(columns[c])
				problems[c].numbers = append(problems[c].numbers, number)
			}
		}
	}

	return problems
}

Solving an individual problem is easy because the samber/lo library provides functions to calculate the sum or product of a slice of integers. All we need to do is decide which function to call based on the operator field.

func solve(problem Problem) int {
	switch problem.operation {
	case OP_PRODUCT:
		return lo.Product(problem.numbers)
	case OP_SUM:
		return lo.Sum(problem.numbers)
	default:
		return -1
	}
}

Finally the grand total is the sum of all the problem solutions. Again we can use samber/lo to do most of the work for us.

func grandTotal(problems []Problem) int {
	return lo.SumBy(problems, func(problem Problem) int {
		return solve(problem)
	})
}

Part 2

Overall thoughts

Part 1 was possibly the easiest puzzle so far, the only slighty inconvenience was having the input in columns instead of rows. Even though we used samber/lo to avoid having to write our own sum and product functions, these would have been straightforward for loops.