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 }