aoc2025/day7/main.go

107 lines
2.2 KiB
Go
Raw Permalink Normal View History

2025-12-07 13:36:49 -05:00
package main
import (
"fmt"
"os"
"strings"
"github.com/kelindar/bitmap"
)
func readLines(filename string) []string {
raw, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
return strings.Split(string(raw), "\n")
}
func main() {
filename := "input0.txt"
if len(os.Args) > 1 {
filename = os.Args[1]
}
lines := readLines(filename)
m := parseManifold(lines)
_, splits := m.eval()
fmt.Printf("%v\n", splits)
fmt.Printf("%v\n", m.quantumEval())
}
type manifold struct {
width uint32
source bitmap.Bitmap
splitters []bitmap.Bitmap
}
func (m *manifold) eval() (bitmap.Bitmap, uint64) {
splits := uint64(0)
active := m.source.Clone(nil)
for _, splitter := range m.splitters {
activated := active.Clone(nil)
activated.And(splitter)
var produced bitmap.Bitmap
activated.Range(func(i uint32) {
splits++
produced.Set(i - 1)
produced.Set(i + 1)
})
active.AndNot(activated)
active.Or(produced)
}
return active, splits
}
// set expansion is just too slow
// instead, work like eval but use a slice of uints where the
// values are the number of timelines that produce a tachyon
// at a given position; when a tachyon is split and joins
// an existing one, we increment, not just bitwise or.
// the total is the sum of all timelines of all positions
// in the final frame.
// 3141808011 is too low
func (m *manifold) quantumEval() uint64 {
active := make([]uint64, m.width)
m.source.Range(func(i uint32) {
active[i] = 1
})
for _, frame := range m.splitters {
next := make([]uint64, m.width)
copy(next, active)
for i, t := range active {
if t == 0 {
continue
}
splitter := frame.Contains(uint32(i))
if splitter {
next[i] = 0
next[i-1] += t
next[i+1] += t
}
}
active = next
}
total := uint64(0)
for _, x := range active {
total += x
}
return total
}
func parseManifold(lines []string) *manifold {
var m manifold
m.width = uint32(len(lines[0]))
m.source.Set(uint32(strings.Index(lines[0], "S")))
for i := 1; i < len(lines); i++ {
var splitter bitmap.Bitmap
for j, c := range lines[i] {
if c == '^' {
splitter.Set(uint32(j))
}
}
m.splitters = append(m.splitters, splitter)
}
return &m
}