Files
2019/days/07.go
Parnic f0be3f9f98 Day 15 solution
I wanted to use something like a right-hand wall solver, but the fact that you don't know the maze ahead of time and you can't see what something is without trying to move into it made that difficult. This semi-brute-force approach works well enough. I originally stopped as soon as I found the oxygen system and figured out the shortest path, but once I submitted that answer and saw that part 2 wanted the full map explored, I figured I might as well just fill the map all at once.

I think I would have been stuck on part 1 longer if my input set didn't happen to find the goal system fairly easily (or maybe my debug drawing helped me work through it with that input set specifically, I'm not sure) since a different input set required some tweaking to the max-visited threshold in order to find things that my first input set found with a lower setting.

Regardless, I'm pretty excited that I came to Trémaux's algorithm, more or less, on my own. I went to Wikipedia to see if I was on the right track and lo and behold, I had come to a version of it myself.

Part 2 turned out easier than I originally thought. I suspected this solution would work, but wasn't completely confident. It can only work for the type of maze used by this problem (where there are no loops of open areas). I'm just glad I didn't need A* or anything.

Oh, and this `stringer` command that allows debug printing of enums can be installed with `go install golang.org/x/tools/cmd/stringer@latest`
2022-06-29 08:11:33 -05:00

117 lines
2.6 KiB
Go

package days
import (
"fmt"
"sync"
"parnic.com/aoc2019/utilities"
)
type Day07 struct {
program utilities.IntcodeProgram
amps []utilities.IntcodeProgram
}
func (d *Day07) Parse() {
d.program = utilities.LoadIntcodeProgram("07p")
d.amps = make([]utilities.IntcodeProgram, 5)
for i := range d.amps {
d.amps[i] = d.program.Copy()
}
}
func (d Day07) Num() int {
return 7
}
func (d *Day07) Part1() string {
var highestVal int64
var highestSequence []int64
allSequences := utilities.GetPermutations([]int64{0, 1, 2, 3, 4}...)
for _, sequence := range allSequences {
if len(sequence) != len(d.amps) {
panic("input sequence does not match up to number of amplifiers")
}
input := int64(0)
var output int64
for i, amp := range d.amps {
amp.RunIn(func(step int) int64 {
if step == 1 {
return sequence[i]
} else if step == 2 {
return input
}
panic("hit more input instructions than expected")
}, func(val int64, state utilities.IntcodeProgramState) {
output = val
})
input = output
}
if output > highestVal {
highestVal = output
if highestSequence == nil {
highestSequence = make([]int64, len(sequence))
}
copy(highestSequence, sequence)
}
}
return fmt.Sprintf("Max thruster signal: %s%d%s (produced by %v)", utilities.TextBold, highestVal, utilities.TextReset, highestSequence)
}
func (d *Day07) Part2() string {
var highestVal int64
var highestSequence []int64
allSequences := utilities.GetPermutations([]int64{5, 6, 7, 8, 9}...)
for _, sequence := range allSequences {
if len(sequence) != len(d.amps) {
panic("input sequence does not match up to number of amplifiers")
}
inputs := make([]chan int64, len(d.amps))
for i := range d.amps {
d.amps[i].Reset()
inputs[i] = make(chan int64, 1)
inputs[i] <- sequence[i]
}
var finalOutput int64
var wg sync.WaitGroup
for i := range d.amps {
wg.Add(1)
go func(idx int) {
d.amps[idx].RunIn(func(step int) int64 {
input := <-inputs[idx]
return input
}, func(val int64, state utilities.IntcodeProgramState) {
finalOutput = val
inputIdx := idx + 1
if inputIdx == len(inputs) {
inputIdx = 0
}
inputs[inputIdx] <- val
})
wg.Done()
}(i)
}
inputs[0] <- 0
wg.Wait()
if finalOutput > highestVal {
highestVal = finalOutput
if highestSequence == nil {
highestSequence = make([]int64, len(sequence))
}
copy(highestSequence, sequence)
}
}
return fmt.Sprintf("Max thruster signal: %s%d%s (produced by %v)", utilities.TextBold, highestVal, utilities.TextReset, highestSequence)
}