Day 23 solution

This one takes around a second to arrive at the first answer and around 15 seconds to arrive at the second answer. I don't know why, since I'm just running the given program as fast as possible (is my interpreter slow?). Go channels should be about as fast as we can get here. Maybe it would actually run faster if everyone stopped and processed their inputs at the same time or something? I dunno.

Part 2 was pretty simple, though I feel like my idle detection could be improved. Seems to work, though.
This commit is contained in:
2022-07-20 08:35:34 -05:00
parent 4175778d52
commit 7e4b44a3b6
3 changed files with 172 additions and 0 deletions

170
days/23.go Normal file
View File

@ -0,0 +1,170 @@
package days
import (
"fmt"
"sync"
u "parnic.com/aoc2019/utilities"
)
type day23Computer struct {
program u.IntcodeProgram
id int
packetQueue chan u.Vec2[int64]
outputStep int
nextPacketDest int
sendingPacket u.Vec2[int64]
hasQueuedPacket bool
lastReceivedPacket u.Vec2[int64]
idle bool
}
func (d Day23) makeComputer(id int) *day23Computer {
c := &day23Computer{
program: d.program.Copy(),
id: id,
packetQueue: make(chan u.Vec2[int64]),
idle: true,
}
return c
}
type Day23 struct {
program u.IntcodeProgram
}
func (d *Day23) Parse() {
d.program = u.LoadIntcodeProgram("23p")
}
func (d Day23) Num() int {
return 23
}
func (d Day23) initComputers() []*day23Computer {
computers := make([]*day23Computer, 50)
for i := range computers {
computers[i] = d.makeComputer(i)
}
return computers
}
func (d Day23) execComputers(computers []*day23Computer, nat chan u.Vec2[int64]) *sync.WaitGroup {
wg := &sync.WaitGroup{}
wg.Add(len(computers))
for _, c := range computers {
go func(c *day23Computer) {
bootedUp := false
c.program.RunIn(func(inputStep int) int64 {
if !bootedUp {
bootedUp = true
return int64(c.id)
}
if c.hasQueuedPacket {
// fmt.Printf(" %d finished processing packet %v\n", c.id, c.lastReceivedPacket)
c.hasQueuedPacket = false
return c.lastReceivedPacket.Y
}
select {
case c.lastReceivedPacket = <-c.packetQueue:
// fmt.Printf("computer %d received packet %v\n", c.id, packet)
c.hasQueuedPacket = true
return c.lastReceivedPacket.X
default:
c.idle = true
return -1
}
}, func(val int64, state u.IntcodeProgramState) {
c.idle = false
switch c.outputStep {
case 0:
c.nextPacketDest = int(val)
case 1:
c.sendingPacket.X = val
case 2:
c.sendingPacket.Y = val
if c.nextPacketDest == 255 {
// fmt.Printf("computer %d sending %v to 255\n", c.id, c.sendingPacket)
nat <- c.sendingPacket
} else {
// fmt.Printf("computer %d sending %v to computer %d\n", c.id, c.sendingPacket, c.nextPacketDest)
computers[c.nextPacketDest].packetQueue <- c.sendingPacket
}
}
c.outputStep = (c.outputStep + 1) % 3
})
wg.Done()
}(c)
}
return wg
}
func (d *Day23) Part1() string {
computers := d.initComputers()
natChan := make(chan u.Vec2[int64])
wg := d.execComputers(computers, natChan)
answer := <-natChan
for _, c := range computers {
c.program.Stop()
}
// not really necessary, but let's make sure they all shut down in case
// we're running all days at once
wg.Wait()
return fmt.Sprintf("First packet sent to 255 Y value: %s%d%s", u.TextBold, answer.Y, u.TextReset)
}
func (d *Day23) Part2() string {
computers := d.initComputers()
natChan := make(chan u.Vec2[int64])
wg := d.execComputers(computers, natChan)
answerChan := make(chan int64)
go func() {
var currVal u.Vec2[int64]
var lastVal u.Vec2[int64]
hasReceived := false
for {
select {
case currVal = <-natChan:
hasReceived = true
default:
}
allIdle := true
for _, c := range computers {
if !c.idle {
allIdle = false
break
}
}
if allIdle && hasReceived {
// fmt.Printf("all idle, sending %v to computer 0\n", currVal)
if lastVal.Y == currVal.Y {
// fmt.Printf("found answer? %d\n", currVal.Y)
answerChan <- currVal.Y
}
computers[0].packetQueue <- currVal
lastVal = currVal
}
}
}()
answer := <-answerChan
for _, c := range computers {
c.program.Stop()
}
wg.Wait()
return fmt.Sprintf("First Y value sent to the NAT twice in a row: %s%d%s", u.TextBold, answer, u.TextReset)
}

1
inputs/23p.txt Normal file

File diff suppressed because one or more lines are too long

View File

@ -56,6 +56,7 @@ var dayMap = []day{
&days.Day20{},
&days.Day21{},
&days.Day22{},
&days.Day23{},
}
func main() {