Advent-of-Code/year25/day6.go
2025-12-08 19:13:35 +02:00

151 lines
3.0 KiB
Go

package year25
import (
"bytes"
"fmt"
"strconv"
"strings"
"git.bizdoc.ro/gabi-public/Advent-of-Code.git/aoc"
)
func Day6Part1(c aoc.Context) (int64, error) {
lines, tokens, err := day6ParseInputs(c)
if err != nil {
return 0, fmt.Errorf("error parsing inputs: %w", err)
}
var total int64
for _, t := range tokens {
calc := day6NewCalc(t.Operation)
for _, line := range lines {
valueStr := string(line[t.Start:t.End()])
v, err := strconv.Atoi(strings.TrimSpace(valueStr))
if err != nil {
return 0, fmt.Errorf("converting %s to int: %w", valueStr, err)
}
c.Printf("'%s' ", valueStr)
calc.Put(v)
}
c.Printf("'%s' %d\n", string(t.Operation), calc.Value)
total += int64(calc.Value)
}
return total, err
}
func Day6Part2(c aoc.Context) (int64, error) {
lines, tokens, err := day6ParseInputs(c)
if err != nil {
return 0, fmt.Errorf("error parsing inputs: %w", err)
}
var total int64
for _, t := range tokens {
calc := day6NewCalc(t.Operation)
mask := make([][]byte, t.Size)
for i := range t.Size {
mask[i] = make([]byte, len(lines))
}
for i := range mask {
for j := range mask[i] {
mask[i][j] = lines[j][t.Start+i]
}
}
for _, line := range mask {
v, err := strconv.Atoi(strings.TrimSpace(string(line)))
if err != nil {
return 0, fmt.Errorf("converting %s to int: %w", string(line), err)
}
c.Printf("'%s' ", string(line))
calc.Put(v)
}
c.Printf("'%s' %d\n", string(t.Operation), calc.Value)
total += int64(calc.Value)
}
return total, err
}
type day6Calc[T any] struct {
Value T
handler func(a T, b T) T
}
func (d *day6Calc[T]) Put(v T) {
d.Value = d.handler(d.Value, v)
}
func day6NewCalc(sign byte) day6Calc[int] {
switch sign {
case '+':
return day6Calc[int]{
Value: 0,
handler: func(a int, b int) int {
return a + b
},
}
case '*':
return day6Calc[int]{
Value: 1,
handler: func(a int, b int) int {
return a * b
},
}
default:
panic(fmt.Errorf("day6NewCalc: invalid sign %v", sign))
}
}
type day6Token struct {
Start, Size int
Operation byte
}
func (t day6Token) End() int {
return t.Start + t.Size
}
func day6ParseInputs(c aoc.Context) (lines [][]byte, tokens []day6Token, err error) {
s := c.Scanner()
// handle malformed input
var maxLineSize int
for i := 0; s.Scan(); i++ {
line := bytes.Clone(s.Bytes())
maxLineSize = max(maxLineSize, len(line))
lines = append(lines, line)
}
if err := s.Err(); err != nil {
return nil, nil, fmt.Errorf("error scanning input")
}
for i := range lines {
if len(lines[i]) < maxLineSize {
lines[i] = append(lines[i], strings.Repeat(" ", maxLineSize-len(lines[i]))...)
}
}
opLine := lines[len(lines)-1]
for i := bytes.IndexAny(opLine, "+*"); i < maxLineSize; i++ {
tokenLen := bytes.IndexAny(opLine[i+1:], "+*")
if tokenLen == -1 {
tokenLen = maxLineSize - i
}
tokens = append(tokens, day6Token{
Start: i,
Size: tokenLen,
Operation: opLine[i],
})
i += tokenLen
}
return lines[:len(lines)-1], tokens, nil
}