Files
adventofcode/2025/day07/main.go
2025-12-07 08:57:46 -06:00

139 lines
2.5 KiB
Go

package main
import (
"fmt"
"sync"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
fmt.Println()
part2(inp)
}
func part1(inp []string) {
var ret int
m := h.StringSliceToCoordByteMap(inp)
ok := true
for ok {
var splits int
splits, ok = progBeams(&m)
ret += splits
}
fmt.Println("# Part 1")
fmt.Println(ret)
}
func progBeams(m *h.CoordByteMap) (int, bool) {
var splits int
beam, err := m.FindLast('|')
if err != nil {
beam, _ = m.FindFirst('S')
}
if beam.Y == m.BRY {
return 0, false
}
beams := m.FindAllOnRow(beam.Y, '|')
if len(beams) == 0 {
beams = append(beams, beam)
}
for i := range beams {
nxt := m.Get(beams[i].South())
switch nxt {
case '.':
m.Put(beams[i].South(), '|')
case '^':
splits++
m.Put(beams[i].South().East(), '|')
m.Put(beams[i].South().West(), '|')
}
}
return splits, true
}
func part2(inp []string) {
m := h.StringSliceToCoordByteMap(inp)
fmt.Println("# Part 2")
fmt.Println(quantumRevKickoff(&m))
}
// quantumRevKickoff starts checks for each potential beam output
func quantumRevKickoff(m *h.CoordByteMap) int {
var ret int
var wg sync.WaitGroup
status := make([]byte, m.BRX)
for i := range status {
status[i] = '.'
}
track := &WorldTracker{
t: make(map[h.Coordinate]int),
}
for x := m.TLX; x < m.BRX; x++ {
c := h.Coordinate{X: x, Y: m.BRY}
wg.Go(func() {
if r, v := quantumRevCalc(m, c, track); v {
ret += r
status[c.X] = 'O'
} else {
status[c.X] = 'X'
}
})
}
wg.Wait()
return ret + 1
}
type WorldTracker struct {
t map[h.Coordinate]int
lock sync.Mutex
}
func (t *WorldTracker) Get(k h.Coordinate) (int, bool) {
t.lock.Lock()
defer t.lock.Unlock()
v, ok := t.t[k]
return v, ok
}
func (t *WorldTracker) Set(k h.Coordinate, v int) {
t.lock.Lock()
defer t.lock.Unlock()
t.t[k] = v
}
// quantumRevCalc calculates how many worlds would provide a beam at
// the given coordinate
func quantumRevCalc(m *h.CoordByteMap, c h.Coordinate, track *WorldTracker) (int, bool) {
if v, ok := track.Get(c); ok {
return v, ok
}
var ret int
var valid bool
if m.Get(c.East()) == '^' {
if r, v := quantumRevCalc(m, c.East(), track); v {
ret += r
valid = true
}
}
if m.Get(c.West()) == '^' {
if r, v := quantumRevCalc(m, c.West(), track); v {
ret += r
valid = true
}
}
if m.Get(c.North()) == '.' {
if r, v := quantumRevCalc(m, c.North(), track); v {
ret += r
valid = true
}
}
track.Set(c, ret)
if m.Get(c.North()) == 'S' {
return 1, true
}
return ret, valid
}