Advent of Code 2022: Day4

Back up

Stream Video

Code

package aoc

import (
	"fmt"
	"io"
	"strconv"
	"strings"

	"mono3/advent/lib/lineio"
	"mono3/common/log"
	"mono3/common/tty"
)

const maxWidth = 160 / 2

type elfAssignment struct {
	lo int
	hi int
}

func (e *elfAssignment) String() string {
	var sb strings.Builder
	for i := 1; i < maxWidth; i++ {
		if i < e.lo || i > e.hi {
			sb.WriteString("..")
		} else {
			fmt.Fprintf(&sb, "%02d", i)
		}
	}

	fmt.Fprintf(&sb, "    %d-%d", e.lo, e.hi)
	return sb.String()
}

func rangeToAssignment(v string) (*elfAssignment, error) {
	parts := strings.SplitN(v, "-", 2)
	loStr := parts[0]
	hiStr := parts[1]

	lo, err := strconv.ParseInt(loStr, 10, 64)
	if err != nil {
		return nil, fmt.Errorf("hi is bad: %w", err)
	}
	hi, err := strconv.ParseInt(hiStr, 10, 64)
	if err != nil {
		return nil, fmt.Errorf("lo is bad: %w", err)
	}

	return &elfAssignment{int(lo), int(hi)}, nil
}

func hasFullOverlap(e1, e2 *elfAssignment) (bool, int, int) {
	// check if e1 overlaps e2
	if e1.lo >= e2.lo && e1.hi <= e2.hi {
		return true, e1.lo, e1.hi
	}

	// check e2 overlaps e1
	if e2.lo >= e1.lo && e2.hi <= e1.hi {
		return true, e2.lo, e2.hi
	}

	return false, 0, 0
}

func hasAnyOverlap(e1, e2 *elfAssignment) (bool, int, int) {
	min := func(a, b int) int {
		if a < b {
			return a
		}
		return b
	}
	max := func(a, b int) int {
		if a > b {
			return a
		}
		return b
	}

	// check if e1 overlaps e2
	if (e1.lo >= e2.lo && e1.lo <= e2.hi) ||
		(e1.hi >= e2.lo && e1.hi <= e2.hi) {
		return true, max(e1.lo, e2.lo), min(e1.hi, e2.hi)
	}

	// check e2 overlaps e1
	if (e2.lo >= e1.lo && e2.lo <= e1.hi) ||
		(e2.hi >= e1.lo && e2.hi <= e1.hi) {
		return true, max(e1.lo, e2.lo), min(e1.hi, e2.hi)
	}

	return false, 0, 0
}

// Each part gets the same input with reader pointing at the start of input.
var PuzzleParts = []func(r io.Reader) error{
	PuzzlePart1,
	PuzzlePart2,
}

func PuzzlePart1(r io.Reader) error {
	return solveit(r, 1, hasFullOverlap)
}

func PuzzlePart2(r io.Reader) error {
	return solveit(r, 2, hasAnyOverlap)
}

func solveit(r io.Reader, part int, overlapFun func(e1, e2 *elfAssignment) (bool, int, int)) error {
	log.Info("Running")

	score := 0
	if err := lineio.ForEach(r, func(ln int, line string) error {
		parts := strings.SplitN(line, ",", 2)

		one, err := rangeToAssignment(parts[0])
		if err != nil {
			return fmt.Errorf("elf1 bad: %w", err)
		}
		two, err := rangeToAssignment(parts[1])
		if err != nil {
			return fmt.Errorf("elf2 bad: %w", err)
		}

		tty.Printf("%s\n", one)
		tty.Printf("%s\n", two)

		if yup, lo, hi := overlapFun(one, two); yup {
			tty.Print("%F{brightred}")
			score += 1
			for i := 1; i < maxWidth; i++ {
				if i < lo || i > hi {
					tty.Printf("  ")
				} else {
					tty.Printf("^^")
				}
			}
			tty.Printf("%%f\n")
		}

		tty.Printf("\n")

		return nil
	}); err != nil {
		return err
	}

	tty.Printf("Total score part %d: %d\n", part, score)

	return nil
}

aimeeble@blog

the blog of aimeeble


By Aimee, 2022-12-04