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 }