package main import ( "bufio" _ "embed" "fmt" "iter" "slices" "sort" aoc "go.sour.is/advent-of-code" ) // var log = aoc.Log func main() { aoc.MustResult(aoc.Runner(run)) } type result struct { valuePT1 int valuePT2 int } func (r result) String() string { return fmt.Sprintf("%#v", r) } func run(scan *bufio.Scanner) (*result, error) { var ( left []int right []int ) for scan.Scan() { txt := scan.Text() var l, r int _, err := fmt.Sscanf(txt, "%d %d", &l, &r) if err != nil { return nil, err } left = append(left, l) right = append(right, r) } sort.Ints(left) sort.Ints(right) result := &result{} result.valuePT1 = aoc.Reduce(func(i int, z pair[int, int], sum int) int { return sum + aoc.ABS(z.L-z.R) }, 0, zip(slices.Values(left), slices.Values(right))) rmap := aoc.Reduce(func(i int, z int, m map[int]int) map[int]int { m[z]++ return m }, make(map[int]int), slices.Values(right)) for _, v := range left { if r, ok := rmap[v]; ok { result.valuePT2 += v*r } } return result, nil } type pair[L, R any] struct { L L R R } func zip[L, R any](l iter.Seq[L], r iter.Seq[R]) iter.Seq[pair[L,R]] { return func(yield func(pair[L, R]) bool) { pullR, stop := iter.Pull(r) defer stop() for l := range l { r, _ := pullR() if !yield(pair[L, R]{L: l, R: r}) { return } } } }