You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
4.2 KiB
Go
223 lines
4.2 KiB
Go
package day16
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
|
|
)
|
|
|
|
type Move struct {
|
|
row int
|
|
col int
|
|
direction rune
|
|
}
|
|
|
|
func nextMoves(origin *Move, lines []string) []*Move {
|
|
result := []*Move{}
|
|
|
|
switch lines[origin.row][origin.col] {
|
|
case '/':
|
|
switch origin.direction {
|
|
case 'R':
|
|
result = append(result, &Move{origin.row - 1, origin.col, 'U'})
|
|
case 'L':
|
|
result = append(result, &Move{origin.row + 1, origin.col, 'D'})
|
|
case 'U':
|
|
result = append(result, &Move{origin.row, origin.col + 1, 'R'})
|
|
case 'D':
|
|
result = append(result, &Move{origin.row, origin.col - 1, 'L'})
|
|
}
|
|
case '\\':
|
|
switch origin.direction {
|
|
case 'R':
|
|
result = append(result, &Move{origin.row + 1, origin.col, 'D'})
|
|
case 'L':
|
|
result = append(result, &Move{origin.row - 1, origin.col, 'U'})
|
|
case 'U':
|
|
result = append(result, &Move{origin.row, origin.col - 1, 'L'})
|
|
case 'D':
|
|
result = append(result, &Move{origin.row, origin.col + 1, 'R'})
|
|
}
|
|
case '|':
|
|
switch origin.direction {
|
|
case 'R', 'L':
|
|
result = append(result, &Move{origin.row - 1, origin.col, 'U'})
|
|
result = append(result, &Move{origin.row + 1, origin.col, 'D'})
|
|
case 'U':
|
|
result = append(result, &Move{origin.row - 1, origin.col, 'U'})
|
|
case 'D':
|
|
result = append(result, &Move{origin.row + 1, origin.col, 'D'})
|
|
}
|
|
case '-':
|
|
switch origin.direction {
|
|
case 'R':
|
|
result = append(result, &Move{origin.row, origin.col + 1, 'R'})
|
|
case 'L':
|
|
result = append(result, &Move{origin.row, origin.col - 1, 'L'})
|
|
case 'U', 'D':
|
|
result = append(result, &Move{origin.row, origin.col - 1, 'L'})
|
|
result = append(result, &Move{origin.row, origin.col + 1, 'R'})
|
|
}
|
|
default:
|
|
switch origin.direction {
|
|
case 'R':
|
|
result = append(result, &Move{origin.row, origin.col + 1, 'R'})
|
|
case 'L':
|
|
result = append(result, &Move{origin.row, origin.col - 1, 'L'})
|
|
case 'U':
|
|
result = append(result, &Move{origin.row - 1, origin.col, 'U'})
|
|
case 'D':
|
|
result = append(result, &Move{origin.row + 1, origin.col, 'D'})
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func Part1(lines []string, startRow int, startCol int, direction rune) int {
|
|
height := len(lines)
|
|
width := len(lines[0])
|
|
cache := map[Move]bool{}
|
|
isEnergized := make([][]bool, height)
|
|
beamMoves := utils.NewStack[*Move]()
|
|
|
|
for row := range lines {
|
|
isEnergized[row] = make([]bool, width)
|
|
}
|
|
|
|
beamMoves.Push(&Move{startRow, startCol, direction})
|
|
i := 0
|
|
for beamMoves.HasElement() {
|
|
currOrigin := beamMoves.Pop()
|
|
isEnergized[currOrigin.row][currOrigin.col] = true
|
|
|
|
_, hasKey := cache[*currOrigin]
|
|
if hasKey {
|
|
continue
|
|
}
|
|
|
|
cache[*currOrigin] = true
|
|
moves := nextMoves(currOrigin, lines)
|
|
|
|
for _, move := range moves {
|
|
if move.row >= 0 && move.row < height && move.col >= 0 && move.col < width {
|
|
beamMoves.Push(move)
|
|
}
|
|
}
|
|
|
|
i++
|
|
if i > 1000000 {
|
|
fmt.Println("loop ?")
|
|
return -1
|
|
}
|
|
}
|
|
|
|
count := 0
|
|
for row := range isEnergized {
|
|
for col := range isEnergized[row] {
|
|
if isEnergized[row][col] {
|
|
count++
|
|
}
|
|
}
|
|
}
|
|
|
|
return count
|
|
}
|
|
|
|
func Part2(lines []string) int {
|
|
height := len(lines)
|
|
width := len(lines[0])
|
|
max := -1
|
|
|
|
var wgD sync.WaitGroup
|
|
chD := make(chan int, width)
|
|
|
|
for i := 0; i < width; i++ {
|
|
wgD.Add(1)
|
|
go func(col int) {
|
|
defer wgD.Done()
|
|
|
|
result := Part1(lines, 0, col, 'D')
|
|
|
|
chD <- result
|
|
}(i)
|
|
}
|
|
wgD.Wait()
|
|
close(chD)
|
|
|
|
for i := range chD {
|
|
if i > max {
|
|
max = i
|
|
}
|
|
}
|
|
|
|
var wgU sync.WaitGroup
|
|
chU := make(chan int, width)
|
|
|
|
for i := 0; i < width; i++ {
|
|
wgU.Add(1)
|
|
go func(col int) {
|
|
defer wgU.Done()
|
|
|
|
result := Part1(lines, height-1, col, 'U')
|
|
|
|
chU <- result
|
|
}(i)
|
|
}
|
|
wgU.Wait()
|
|
close(chU)
|
|
|
|
for i := range chU {
|
|
if i > max {
|
|
max = i
|
|
}
|
|
}
|
|
|
|
var wgL sync.WaitGroup
|
|
chL := make(chan int, height)
|
|
|
|
for i := 0; i < height; i++ {
|
|
wgL.Add(1)
|
|
go func(row int) {
|
|
defer wgL.Done()
|
|
|
|
result := Part1(lines, row, width-1, 'L')
|
|
|
|
chL <- result
|
|
}(i)
|
|
}
|
|
wgL.Wait()
|
|
close(chL)
|
|
|
|
for i := range chL {
|
|
if i > max {
|
|
max = i
|
|
}
|
|
}
|
|
|
|
var wgR sync.WaitGroup
|
|
chR := make(chan int, height)
|
|
|
|
for i := 0; i < height; i++ {
|
|
wgR.Add(1)
|
|
go func(row int) {
|
|
defer wgR.Done()
|
|
|
|
result := Part1(lines, row, width-1, 'L')
|
|
|
|
chR <- result
|
|
}(i)
|
|
}
|
|
wgR.Wait()
|
|
close(chR)
|
|
|
|
for i := range chR {
|
|
if i > max {
|
|
max = i
|
|
}
|
|
}
|
|
|
|
return max
|
|
}
|