122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
intcode "git.bullercodeworks.com/brian/adventofcode/2019/intcode-processor"
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
type System struct {
|
|
intcode.Program
|
|
Running bool
|
|
Address int
|
|
IncomingQueue []h.Coordinate
|
|
Network *Network
|
|
}
|
|
|
|
func NewSystem(program intcode.Program, addr int, network *Network) *System {
|
|
s := System{
|
|
Program: program,
|
|
Address: addr,
|
|
Network: network,
|
|
}
|
|
go func() {
|
|
fmt.Println("Booting", s.Address, "...")
|
|
for !s.Program.NeedsInput() {
|
|
time.Sleep(1)
|
|
}
|
|
s.Program.Input(s.Address)
|
|
fmt.Println(s.Address, "booted")
|
|
// System should just continue to run now
|
|
for {
|
|
if s.NeedsOutput() {
|
|
// There should be 3 outputs, an address and a coordinate
|
|
addr, x, y := s.Output(), s.Output(), s.Output()
|
|
coord := h.Coordinate{
|
|
X: x,
|
|
Y: y,
|
|
}
|
|
s.Network.Queue(addr, coord)
|
|
} else if s.NeedsInput() {
|
|
v, err := s.Network.Retrieve(s.Address)
|
|
if err != nil {
|
|
s.Input(v.X)
|
|
for !s.NeedsInput() {
|
|
time.Sleep(1)
|
|
}
|
|
s.Input(v.Y)
|
|
} else {
|
|
s.Input(-1)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
go s.Program.Run()
|
|
return &s
|
|
}
|
|
|
|
func (s System) String() string {
|
|
status := "."
|
|
if s.Program.NeedsInput() {
|
|
status = "<"
|
|
} else if s.Program.NeedsOutput() {
|
|
status = ">"
|
|
}
|
|
return fmt.Sprintf("[%d] %s\n", s.Address, status)
|
|
}
|
|
|
|
type Network struct {
|
|
Systems []*System
|
|
Messages map[int][]h.Coordinate
|
|
CrashOverride bool
|
|
}
|
|
|
|
func StartNetwork(nic intcode.Program) *Network {
|
|
n := Network{
|
|
Messages: make(map[int][]h.Coordinate),
|
|
}
|
|
for i := 0; i < 50; i++ {
|
|
n.Systems = append(n.Systems, NewSystem(nic, i, &n))
|
|
}
|
|
return &n
|
|
}
|
|
|
|
func (n *Network) Queue(addr int, coord h.Coordinate) {
|
|
fmt.Println("Network Queue", addr, coord, len(n.Messages))
|
|
if addr == 255 {
|
|
fmt.Printf("First packet to 255: {X: %d, Y: %d}\n", coord.X, coord.Y)
|
|
n.CrashOverride = true
|
|
}
|
|
if n.CrashOverride {
|
|
return
|
|
}
|
|
fmt.Printf("Queuing Packet for %d: {X: %d, Y: %d}\n", addr, coord.X, coord.Y)
|
|
n.Messages[addr] = append(n.Messages[addr], coord)
|
|
}
|
|
|
|
func (n *Network) Retrieve(addr int) (h.Coordinate, error) {
|
|
fmt.Println("Network Retrieve", addr, len(n.Messages))
|
|
if n.CrashOverride {
|
|
return h.Coordinate{}, errors.New("Network is down")
|
|
}
|
|
var ret h.Coordinate
|
|
if len(n.Messages[addr]) > 0 {
|
|
ret, n.Messages[addr] = n.Messages[addr][0], n.Messages[addr][1:]
|
|
fmt.Printf("%d Retriving Packet: {X: %d, Y: %d}\n", addr, ret.X, ret.Y)
|
|
return ret, nil
|
|
} else {
|
|
return h.Coordinate{}, errors.New("No message")
|
|
}
|
|
}
|
|
|
|
func (n Network) String() string {
|
|
ret := fmt.Sprintf("Messages: %d\n", len(n.Messages))
|
|
for v := range n.Systems {
|
|
ret = ret + n.Systems[v].String()
|
|
}
|
|
return ret
|
|
}
|