2022 Day 4

Posted on Dec 4, 2022

Part 1

Problem

Each line in the file represents a pair of assignments. Each assignment is separated by a comma, and the lower and upper bounds of the assignment are separated by a hyphen. Count the pairs where one assignment completely overlaps the other.

General solution

As all pairs are independent, we can process them as we read the file instead of converting them into a data structure.

A pair of assignments completely overlap if and only if:

a1 <= b1 AND a2 >= b2
OR
b1 <= a1 AND b2 >= a2

All we need to do is extract the lower and upper bounds for each pair of assignments and run the above comparisons, incrementing a counter if the comparisons are true.

Solution: Go

The solution is fairly straightforward as we are just reading in a file line by line and using strings.Split to break it up into components. The only thing we have to be aware of is that Go is a strongly typed language, and therefore it will compare strings as strings, e.g. “100” is less than “99”. This is not the case in some other languages such as PHP, which will implicitly convert the strings into numbers and then compare them numerically. Without this conversion, Go will return an incorrect overlap count.

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	overlapCount := 0
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		assignments := strings.Split(line, ",")
		firstAssignment := strings.Split(assignments[0], "-")
		secondAssignment := strings.Split(assignments[1], "-")

		// Convert all assignments to integers, otherwise Go will compare them as strings
		// and this will not yield the result we expect
		a1, _ := strconv.Atoi(firstAssignment[0])
		a2, _ := strconv.Atoi(firstAssignment[1])
		b1, _ := strconv.Atoi(secondAssignment[0])
		b2, _ := strconv.Atoi(secondAssignment[1])

		if (a1 <= b1 && a2 >= b2) || (b1 <= a1 && b2 >= a2) {
			overlapCount++
		}
	}

	fmt.Println(overlapCount)
}

Part 2

Problem

The same as Part 1, except we want to count assignments with any overlap, rather than a complete overlap.

General solution

The solution remains the same, except for the overlap check which becomes:

b1 < a1 AND b2 >= a1
OR
b1 >= a1 AND b1 <= a2

Solution: Go

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	overlapCount := 0
	scanner := bufio.NewScanner(os.Stdin)

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		assignments := strings.Split(line, ",")
		firstAssignment := strings.Split(assignments[0], "-")
		secondAssignment := strings.Split(assignments[1], "-")

		// Convert all assignments to integers, otherwise Go will compare them as strings
		// and this will not yield the result we expect
		a1, _ := strconv.Atoi(firstAssignment[0])
		a2, _ := strconv.Atoi(firstAssignment[1])
		b1, _ := strconv.Atoi(secondAssignment[0])
		b2, _ := strconv.Atoi(secondAssignment[1])

		if (b1 < a1 && b2 >= a1) || (b1 >= a1 && b1 <= a2) {
			overlapCount++
		}
	}

	fmt.Println(overlapCount)
}

Post-solution thoughts

There might be a way to remove the various temporary variables and split a line directly into a1, a2, b1 and b2. However, the optimiser may do this for us anyway, and as this is such a small program the cost of a few extra temporary variables is not worth worrying about.