Files
advent-of-code-2025/day7/main.go
2025-12-07 14:18:52 +02:00

146 lines
2.5 KiB
Go

package main
import (
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"slices"
)
func main() {
debug := flag.Bool("debug", false, "Debug.")
flag.Parse()
f := os.Stdin
if flag.NArg() > 0 && flag.Arg(0) != "-" {
var err error
f, err = os.Open(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
defer f.Close()
}
diagram, err := readDiagram(f)
if err != nil {
log.Fatal(err)
}
splits := diagram.Propagate()
var timelines int
for _, row := range slices.Backward(diagram) {
for _, c := range row {
if c.Marker != BeamMarker {
continue
}
timelines += c.WaysToReach
}
break
}
if *debug {
for _, row := range diagram {
for _, c := range row {
if c.Marker == BeamMarker {
if c.WaysToReach < 10 {
fmt.Print(c.WaysToReach)
} else {
b := 'A' + c.WaysToReach - 10
if b > 'Z' {
b = int(c.Marker)
}
fmt.Printf("%c", b)
}
} else {
fmt.Printf("%c", c.Marker)
}
}
fmt.Println()
}
}
fmt.Println("beam split", splits, "times into", timelines, "timelines")
}
type Marker byte
const (
BeamEmitterMarker Marker = 'S'
BeamMarker Marker = '|'
SplitterMarker Marker = '^'
EmptyMarker Marker = '.'
)
type Cell struct {
Marker Marker
WaysToReach int
}
type diagram [][]Cell
func (d diagram) Propagate() (splits int) {
splitoff := func(x, y, dx int) {
x1 := x + dx
if x1 < 0 || x1 >= len(d[y]) {
return // out of range
}
switch d[y][x1].Marker {
case EmptyMarker:
d[y][x1] = Cell{
Marker: BeamMarker,
WaysToReach: d[y-1][x].WaysToReach,
}
case BeamMarker:
d[y][x1].WaysToReach += d[y-1][x].WaysToReach
}
}
propagateCell := func(x, y int) {
switch d[y-1][x].Marker {
case BeamEmitterMarker:
d[y-1][x].WaysToReach = 1
case BeamMarker:
default:
return
}
// we have a beam above
switch d[y][x].Marker {
case EmptyMarker:
d[y][x] = Cell{
Marker: BeamMarker,
WaysToReach: d[y-1][x].WaysToReach,
}
case BeamMarker:
d[y][x].WaysToReach += d[y-1][x].WaysToReach
case SplitterMarker:
splitoff(x, y, -1)
splitoff(x, y, +1)
splits++
}
}
for y := 1; y < len(d); y++ {
for x := range d[y] {
propagateCell(x, y)
}
}
return splits
}
func readDiagram(r io.Reader) (diagram, error) {
var diagram diagram
sc := bufio.NewScanner(r)
for sc.Scan() {
cells := make([]Cell, 0, len(sc.Bytes()))
for _, b := range sc.Bytes() {
cells = append(cells, Cell{Marker: Marker(b)})
}
diagram = append(diagram, cells)
}
return diagram, sc.Err()
}