2017-day18: ugh assembly/intcode thing

This commit is contained in:
alexchao26
2020-12-18 23:34:27 -05:00
parent 6c83ac5e5a
commit 0be8f0f018
2 changed files with 200 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
package main
import (
"flag"
"fmt"
"math"
"strconv"
"strings"
"github.com/alexchao26/advent-of-code-go/util"
)
func main() {
var part int
flag.IntVar(&part, "part", 1, "part 1 or 2")
flag.Parse()
fmt.Println("Running part", part)
var ans int
if part == 1 {
ans = part1(util.ReadFile("./input.txt"))
} else {
ans = part2(util.ReadFile("./input.txt"))
}
fmt.Println("Output:", ans)
}
func part1(input string) int {
comp := newComputerFromInput(input, 0)
// prime until it gets a valid receive command, then return last outputted num
comp.step(noInput)
return comp.output[len(comp.output)-1]
}
func part2(input string) int {
program0 := newComputerFromInput(input, 0)
program1 := newComputerFromInput(input, 1)
// prime the computers
program0.step(noInput)
program1.step(noInput)
var sentFrom1 int
for len(program0.output)+len(program1.output) > 0 {
// run outputs from program zero through program 1
for len(program0.output) > 0 {
v := program0.output[0]
program0.output = program0.output[1:]
program1.step(v)
}
// and vice versa
for len(program1.output) > 0 {
v := program1.output[0]
program1.output = program1.output[1:]
program0.step(v)
sentFrom1++
}
}
return sentFrom1
}
type computer struct {
instructions [][]string
pointer int
registers map[string]int
output []int
}
func newComputerFromInput(input string, programID int) *computer {
comp := &computer{registers: map[string]int{"p": programID}}
for _, line := range strings.Split(input, "\n") {
comp.instructions = append(comp.instructions, strings.Split(line, " "))
}
return comp
}
var noInput = math.MinInt16
func (c *computer) step(inputNum int) {
for {
inst := c.instructions[c.pointer]
valX := inst[1]
var valY int
if len(inst) == 3 && inst[2] != "" {
if val, err := strconv.Atoi(inst[2]); err != nil {
// if there is an error parsing to an integer, value at index 1 is a register
valY = c.registers[inst[2]]
} else {
valY = val
}
}
switch inst[0] {
case "snd":
c.output = append(c.output, c.registers[valX])
c.pointer++
case "set":
c.registers[valX] = valY
c.pointer++
case "add":
c.registers[valX] += valY
c.pointer++
case "mul":
c.registers[valX] *= valY
c.pointer++
case "mod":
c.registers[valX] %= valY
c.pointer++
case "rcv":
if inputNum == noInput {
return
}
c.registers[valX] = inputNum
inputNum = noInput
c.pointer++
case "jgz":
var parsedX int
if num, err := strconv.Atoi(valX); err != nil {
// err converting, not a number
parsedX = c.registers[valX]
} else {
// no error then a number was parsed
parsedX = num
}
if parsedX > 0 {
c.pointer += valY + len(c.instructions)
c.pointer %= len(c.instructions)
} else {
c.pointer++
}
default:
panic("unhandled operator " + inst[0])
}
}
}
+63
View File
@@ -0,0 +1,63 @@
package main
import (
"testing"
"github.com/alexchao26/advent-of-code-go/util"
)
var example = `set a 1
add a 2
mul a a
mod a 5
snd a
set a 0
rcv a
jgz a -1
set a 1
jgz a -2`
func Test_part1(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
{"example", example, 4},
{"actual", util.ReadFile("input.txt"), 3188},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part1(tt.input); got != tt.want {
t.Errorf("part1() = %v, want %v", got, tt.want)
}
})
}
}
// really frail example...
var example2 = `snd 1
snd 2
snd p
rcv a
rcv b
rcv c
rcv d`
func Test_part2(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
{"example", example2, 3},
{"actual", util.ReadFile("input.txt"), 7112},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part2(tt.input); got != tt.want {
t.Errorf("part2() = %v, want %v", got, tt.want)
}
})
}
}