Skip to content

Commit

Permalink
Mostly working implementation of 23b
Browse files Browse the repository at this point in the history
There is some manual sleeeping that I'm still not happy with and it's
not 100% consistent but is good enough for now. I may revisit this one
in the future.
  • Loading branch information
nlowe committed Dec 31, 2019
1 parent 2fc56dc commit b2f8625
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 13 deletions.
10 changes: 7 additions & 3 deletions challenge/day23/a.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const (
)

func a(challenge *challenge.Input) int {
inputs, outputs := bootNetwork(challenge)
return <-NewRouter(inputs, outputs).RouteTraffic()
}

func bootNetwork(challenge *challenge.Input) ([]chan int, []<-chan int) {
program := <-challenge.Lines()
computers := make([]*intcode.CPU, networkSize)
inputs := make([]chan int, networkSize)
Expand All @@ -37,14 +42,13 @@ func a(challenge *challenge.Input) int {

go func(i int) {
// Boot the nic and assign the ID
fmt.Printf("[%2d] booting...\n", i)
fmt.Printf("[%3d] booting...\n", i)
go computers[i].Run()
inputs[i] <- i
startup.Done()
}(i)
}

startup.Wait()

return <-NewRouter(inputs, outputs).RouteTraffic()
return inputs, outputs
}
24 changes: 24 additions & 0 deletions challenge/day23/b.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package day23

import (
"fmt"

"github.com/nlowe/aoc2019/challenge"
"github.com/spf13/cobra"
)

var B = &cobra.Command{
Use: "23b",
Short: "Day 23, Problem B",
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf("Answer: %d\n", b(challenge.FromFile()))
},
}

func b(challenge *challenge.Input) int {
inputs, outputs := bootNetwork(challenge)
r := NewRouter(inputs, outputs)
r.trackNat = true

return <-r.RouteTraffic()
}
73 changes: 65 additions & 8 deletions challenge/day23/router.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package day23

import (
"context"
"fmt"
"reflect"
"runtime"
"time"

"golang.org/x/sync/semaphore"
)

const (
addressAnswer = 255
addressNAT = 255
routerBufferSize = 16
)

Expand All @@ -21,7 +26,11 @@ type router struct {
ins []chan int
outs []<-chan int

bufs []chan packet
bufs []chan packet
idleTracker *semaphore.Weighted

trackNat bool
lastNATPacket packet
}

func NewRouter(in []chan int, out []<-chan int) *router {
Expand All @@ -34,13 +43,18 @@ func NewRouter(in []chan int, out []<-chan int) *router {
ins: in,
outs: out,
bufs: bufs,

idleTracker: semaphore.NewWeighted(int64(len(in))),
}
}

func (r *router) RouteTraffic() <-chan int {
answer := make(chan int)
go r.runPacketAggregator(answer)
go r.runTransmitter()
if r.trackNat {
go r.runNATHandler(answer)
}

return answer
}
Expand All @@ -61,13 +75,22 @@ func (r *router) runPacketAggregator(answer chan int) {
x := <-r.outs[sender]
y := <-r.outs[sender]

if dst == addressAnswer {
answer <- y
return
parsed := packet{sender, dst, x, y}

if dst == addressNAT {
if !r.trackNat {
fmt.Printf("[NAT] write answer (non-tracking): %d\n", y)
answer <- y
return
}

r.lastNATPacket = parsed
fmt.Printf("[NAT] intercept {%d,%d} from %d\n", x, y, sender)
continue
}

fmt.Printf("[%2d] send {%d,%d} to %d\n", sender, x, y, dst)
r.bufs[dst] <- packet{sender, dst, x, y}
fmt.Printf("[%3d] send {%d,%d} to %d\n", sender, x, y, dst)
r.bufs[dst] <- parsed
}
}

Expand All @@ -86,9 +109,43 @@ func (r *router) runTransmitterFor(id int) {
select {
case in <- -1:
case p := <-packets:
fmt.Printf("[%2d] got {%d,%d} from %d\n", id, p.x, p.y, p.from)
_ = r.idleTracker.Acquire(context.Background(), 1)
fmt.Printf("[%3d] got {%d,%d} from %d\n", id, p.x, p.y, p.from)
in <- p.x
in <- p.y
r.idleTracker.Release(1)
}

// Give other goroutines some time to run
runtime.Gosched()
}
}

func (r *router) runNATHandler(answer chan int) {
last := -1
for {
// Give the adapters some time to send some traffic, especially if we just
// kick-started node 0
time.Sleep(50 * time.Millisecond)

if r.lastNATPacket.to != addressNAT || !r.idleTracker.TryAcquire(int64(len(r.ins))) {
// Yield back to the scheduler
runtime.Gosched()
continue
}

if r.lastNATPacket.y == last {
fmt.Printf("[NAT] write answer (tracking) %d\n", last)
answer <- r.lastNATPacket.y
return
}

fmt.Printf("[NAT] network idle enough, sending {%d,%d} from %d to [ 0]\n", r.lastNATPacket.x, r.lastNATPacket.y, r.lastNATPacket.from)
r.bufs[0] <- r.lastNATPacket
last = r.lastNATPacket.y

// Don't try to immediately steal the semaphore back
r.idleTracker.Release(int64(len(r.ins)))
runtime.Gosched()
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/stretchr/testify v1.4.0
github.com/zalando/go-keyring v0.0.0-20191212171435-ac5f1d08068b // indirect
github.com/zellyn/kooky v0.0.0-20190514172626-f2bb24889ec7
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/yaml.v2 v2.2.7 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
2 changes: 1 addition & 1 deletion intcode/cpu.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (c *CPU) write(mode, offset, value int) {

func (c *CPU) debugState() string {
view := strings.Builder{}
view.WriteString("...")
view.WriteString("... ")

for i := c.pc - 10; i < c.pc+10; i++ {
if i == c.pc {
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func init() {
day20.A, day20.B,
day21.A, day21.B,
day22.A, day22.B,
day23.A,
day23.A, day23.B,
)

flags := rootCmd.PersistentFlags()
Expand Down

0 comments on commit b2f8625

Please sign in to comment.