164 lines
3.4 KiB
Go
164 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"strconv"
|
|
"strings"
|
|
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
var incache []int
|
|
|
|
type Computer struct {
|
|
Address int
|
|
Program []int
|
|
Position int
|
|
Offset int
|
|
Channel chan int
|
|
}
|
|
|
|
func (c Computer) String() string {
|
|
status := "○"
|
|
if c.Position%2 == 0 {
|
|
status = "●"
|
|
}
|
|
return fmt.Sprintf("[%2d] %s {%d}", c.Address, status, c.Offset)
|
|
}
|
|
|
|
func (c *Computer) parseInstruction() (int, []int) {
|
|
inst := c.read(c.Position)
|
|
opcode := inst % 100
|
|
modes := make([]int, 4)
|
|
inst /= 100
|
|
for i := 0; inst > 0; i++ {
|
|
modes[i] = inst % 10
|
|
inst /= 10
|
|
}
|
|
return opcode, modes
|
|
}
|
|
|
|
func (c *Computer) parseParameters(modes []int, num int) []int {
|
|
params := make([]int, num)
|
|
for i := 0; i < num; i++ {
|
|
if i >= len(modes) || modes[i] == 0 {
|
|
params[i] = c.read(c.read(c.Position + i + 1))
|
|
} else if modes[i] == 1 {
|
|
params[i] = c.read(c.Position + i + 1)
|
|
} else {
|
|
params[i] = c.read(c.read(c.Position+i+1) + c.Offset)
|
|
}
|
|
}
|
|
return params
|
|
}
|
|
|
|
func (c *Computer) read(pos int) int {
|
|
if pos >= len(c.Program) {
|
|
return 0
|
|
}
|
|
return c.Program[pos]
|
|
}
|
|
|
|
func (c *Computer) write(pos, val, mode int) {
|
|
if mode == 2 {
|
|
pos += c.Offset
|
|
}
|
|
if pos >= len(c.Program) {
|
|
prog := make([]int, pos*2)
|
|
copy(prog, c.Program)
|
|
c.Program = prog
|
|
}
|
|
c.Program[pos] = val
|
|
}
|
|
|
|
func (c *Computer) run() {
|
|
for c.read(c.Position) != 99 {
|
|
inst, modes := c.parseInstruction()
|
|
switch inst {
|
|
case 1:
|
|
params := c.parseParameters(modes, 2)
|
|
c.write(c.read(c.Position+3), params[0]+params[1], modes[2])
|
|
c.Position += 4
|
|
case 2:
|
|
params := c.parseParameters(modes, 2)
|
|
c.write(c.read(c.Position+3), params[0]*params[1], modes[2])
|
|
c.Position += 4
|
|
case 3:
|
|
c.write(c.read(c.Position+1), <-c.Channel, modes[0])
|
|
c.Position += 2
|
|
case 4:
|
|
params := c.parseParameters(modes, 1)
|
|
c.Channel <- params[0]
|
|
c.Position += 2
|
|
case 5:
|
|
params := c.parseParameters(modes, 2)
|
|
if params[0] != 0 {
|
|
c.Position = params[1]
|
|
} else {
|
|
c.Position += 3
|
|
}
|
|
case 6:
|
|
params := c.parseParameters(modes, 2)
|
|
if params[0] == 0 {
|
|
c.Position = params[1]
|
|
} else {
|
|
c.Position += 3
|
|
}
|
|
case 7:
|
|
params := c.parseParameters(modes, 2)
|
|
if params[0] < params[1] {
|
|
c.write(c.read(c.Position+3), 1, modes[2])
|
|
} else {
|
|
c.write(c.read(c.Position+3), 0, modes[2])
|
|
}
|
|
c.Position += 4
|
|
case 8:
|
|
params := c.parseParameters(modes, 2)
|
|
if params[0] == params[1] {
|
|
c.write(c.read(c.Position+3), 1, modes[2])
|
|
} else {
|
|
c.write(c.read(c.Position+3), 0, modes[2])
|
|
}
|
|
c.Position += 4
|
|
case 9:
|
|
params := c.parseParameters(modes, 1)
|
|
c.Offset += params[0]
|
|
c.Position += 2
|
|
}
|
|
}
|
|
close(c.Channel)
|
|
}
|
|
|
|
func NewComputer() Computer {
|
|
var ints []int
|
|
if incache == nil {
|
|
input, _ := ioutil.ReadFile("input")
|
|
ints = make([]int, 0)
|
|
for _, v := range strings.Split(string(input), ",") {
|
|
i, _ := strconv.Atoi(v)
|
|
ints = append(ints, i)
|
|
}
|
|
incache = make([]int, len(ints))
|
|
copy(incache, ints)
|
|
} else {
|
|
ints = make([]int, len(incache))
|
|
copy(ints, incache)
|
|
}
|
|
c := Computer{Program: ints, Channel: make(chan int)}
|
|
go c.run()
|
|
return c
|
|
}
|
|
|
|
func NewNetwork() ([]Computer, [][]h.Coordinate) {
|
|
devices := make([]Computer, 50)
|
|
queue := make([][]h.Coordinate, len(devices))
|
|
for i := 0; i < len(devices); i++ {
|
|
devices[i] = NewComputer()
|
|
devices[i].Address = i
|
|
devices[i].Channel <- i
|
|
queue[i] = make([]h.Coordinate, 0)
|
|
}
|
|
return devices, queue
|
|
}
|