Files
advent-of-gode/2023/16/code.go
2023-12-16 10:06:31 +02:00

221 lines
5.4 KiB
Go

package main
import (
"strings"
"github.com/jpillora/puzzler/harness/aoc"
)
func main() {
aoc.Harness(run)
}
// on code change, run will be executed 4 times:
// 1. with: false (part1), and example input
// 2. with: true (part2), and example input
// 3. with: false (part1), and user input
// 4. with: true (part2), and user input
// the return value of each run is printed to stdout
type BeamSect struct {
Direction rune
Y int
X int
}
type Beam struct {
Direction rune
Path []BeamSect
EnergizedTiles int
}
type Tile struct {
Type rune
ShineN bool
ShineE bool
ShineS bool
ShineW bool
X int
Y int
}
func calcEnergized(grid [][]Tile, start Tile) int {
tilesChanged := []Tile{start}
for len(tilesChanged) > 0 {
// Contagion
stillChanged := make([]Tile, 0)
for _, t := range tilesChanged {
if t.ShineE && t.X < len(grid[t.Y])-1 {
eX := t.X + 1
eY := t.Y
shineInto := &grid[eY][eX]
if (shineInto.Type == '.' || shineInto.Type == '-') && !shineInto.ShineE {
// Change!
shineInto.ShineE = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '|' && (!shineInto.ShineN || !shineInto.ShineS) {
shineInto.ShineN = true
shineInto.ShineS = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '/' && !shineInto.ShineN {
shineInto.ShineN = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '\\' && !shineInto.ShineS {
shineInto.ShineS = true
stillChanged = append(stillChanged, *shineInto)
}
}
if t.ShineW && t.X > 0 {
wX := t.X - 1
wY := t.Y
shineInto := &grid[wY][wX]
if (shineInto.Type == '.' || shineInto.Type == '-') && !shineInto.ShineW {
// Change!
shineInto.ShineW = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '|' && (!shineInto.ShineN || !shineInto.ShineS) {
shineInto.ShineN = true
shineInto.ShineS = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '/' && !shineInto.ShineS {
shineInto.ShineS = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '\\' && !shineInto.ShineN {
shineInto.ShineN = true
stillChanged = append(stillChanged, *shineInto)
}
}
if t.ShineN && t.Y > 0 {
nX := t.X
nY := t.Y - 1
shineInto := &grid[nY][nX]
if (shineInto.Type == '.' || shineInto.Type == '|') && !shineInto.ShineN {
// Change!
shineInto.ShineN = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '-' && (!shineInto.ShineE || !shineInto.ShineW) {
shineInto.ShineE = true
shineInto.ShineW = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '/' && !shineInto.ShineE {
shineInto.ShineE = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '\\' && !shineInto.ShineW {
shineInto.ShineW = true
stillChanged = append(stillChanged, *shineInto)
}
}
if t.ShineS && t.Y < len(grid)-1 {
sX := t.X
sY := t.Y + 1
shineInto := &grid[sY][sX]
if (shineInto.Type == '.' || shineInto.Type == '|') && !shineInto.ShineS {
// Change!
shineInto.ShineS = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '-' && (!shineInto.ShineE || !shineInto.ShineW) {
shineInto.ShineE = true
shineInto.ShineW = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '/' && !shineInto.ShineW {
shineInto.ShineW = true
stillChanged = append(stillChanged, *shineInto)
} else if shineInto.Type == '\\' && !shineInto.ShineE {
shineInto.ShineE = true
stillChanged = append(stillChanged, *shineInto)
}
}
}
tilesChanged = stillChanged
}
energized := 0
for v := range grid {
for h := range grid[v] {
if grid[v][h].ShineE || grid[v][h].ShineN || grid[v][h].ShineS || grid[v][h].ShineW {
energized += 1
}
}
}
return energized
}
func resetGrid(grid [][]Tile) {
for v := range grid {
for h := range grid[v] {
grid[h][v].ShineE = false
grid[h][v].ShineN = false
grid[h][v].ShineS = false
grid[h][v].ShineW = false
}
}
}
func run(part2 bool, input string) any {
// when you're ready to do part 2, remove this "not implemented" block
grid := make([][]Tile, 0)
for _, l := range strings.Split(input, "\n") {
if l == "" {
continue
}
gridLine := make([]Tile, 0)
for r := range l {
gridLine = append(gridLine, Tile{Type: rune(l[r]), X: len(gridLine), Y: len(grid)})
}
grid = append(grid, gridLine)
}
if part2 {
maxEnergized := -1
for v := range grid {
testE := calcEnergized(grid, Tile{ShineE: true, X: -1, Y: v})
resetGrid(grid)
if testE > maxEnergized {
maxEnergized = testE
}
testW := calcEnergized(grid, Tile{ShineW: true, X: len(grid[v]), Y: v})
resetGrid(grid)
if testW > maxEnergized {
maxEnergized = testW
}
}
for h := range grid[0] {
testN := calcEnergized(grid, Tile{ShineN: true, X: h, Y: len(grid)})
resetGrid(grid)
if testN > maxEnergized {
maxEnergized = testN
}
testS := calcEnergized(grid, Tile{ShineS: true, X: h, Y: -1})
resetGrid(grid)
if testS > maxEnergized {
maxEnergized = testS
}
}
return maxEnergized
}
// solve part 1 her
return calcEnergized(grid, Tile{ShineE: true, X: -1, Y: 0})
}