Skip to content

Instantly share code, notes, and snippets.

@Aneurysm9
Created December 7, 2019 05:34
Show Gist options
  • Save Aneurysm9/285111d1c44f33aefd1ee05c84f24b40 to your computer and use it in GitHub Desktop.
Save Aneurysm9/285111d1c44f33aefd1ee05c84f24b40 to your computer and use it in GitHub Desktop.
AoC 2019 Day 7
package day7
import (
"bufio"
"fmt"
"io"
"strconv"
"strings"
"sync"
)
type Runner struct{}
func (r Runner) PartA(in io.Reader) string {
return fmt.Sprint(runA(readInput(in)))
}
func (r Runner) PartB(in io.Reader) string {
return fmt.Sprint(runB(readInput(in)))
}
func readInput(in io.Reader) []int {
out := []int{}
s := bufio.NewScanner(in)
for s.Scan() {
for _, v := range strings.Split(s.Text(), ",") {
i, err := strconv.Atoi(v)
if err != nil {
panic(err)
}
out = append(out, i)
}
}
return out
}
func runA(input []int) int {
max := 0
perms := permutations([]int{0, 1, 2, 3, 4})
for _, p := range perms {
t := thruster(p)
res := t.runA(input)
if res > max {
max = res
}
}
return max
}
func runB(input []int) int {
max := 0
perms := permutations([]int{5, 6, 7, 8, 9})
for _, p := range perms {
t := thruster(p)
res := t.runB(input)
if res > max {
max = res
}
}
return max
}
func permutations(elems []int) [][]int {
perms := [][]int{}
if len(elems) == 1 {
return [][]int{elems}
}
for i := range elems {
el := append([]int(nil), elems...)
for _, perm := range permutations(append(el[0:i], el[i+1:]...)) {
perms = append(perms, append([]int{elems[i]}, perm...))
}
}
return perms
}
type thruster []int
func (t thruster) runA(input []int) int {
out := 0
for _, v := range t {
m := newVM(input)
m.write(v)
m.write(out)
m.run()
out = m.read()
}
return out
}
func (t thruster) runB(input []int) int {
amps := make([]*vm, len(t))
for i := 0; i < len(amps); i++ {
amps[i] = newVM(input)
}
last := len(t) - 1
for i := 0; i < last; i++ {
amps[i].input <- t[i]
amps[i+1].input = amps[i].output
}
amps[last].input <- t[last]
amps[0].input = amps[last].output
amps[0].input <- t[0]
amps[0].input <- 0
wg := sync.WaitGroup{}
for i := range t {
wg.Add(1)
go func(i int) {
defer wg.Done()
amps[i].run()
}(i)
}
wg.Wait()
return amps[last].lastOut
}
type vm struct {
pc int
mem []int
input chan int
output chan int
lastOut int
}
type opcode func(*vm, []mode) int
type mode int
const (
position mode = 0
immediate mode = 1
)
var opcodes = map[int]opcode{
1: func(m *vm, modes []mode) int {
m.mem[m.mem[m.pc+3]] = m.get(1, modes[0]) + m.get(2, modes[1])
return 4
},
2: func(m *vm, modes []mode) int {
m.mem[m.mem[m.pc+3]] = m.get(1, modes[0]) * m.get(2, modes[1])
return 4
},
3: func(m *vm, modes []mode) int {
m.mem[m.mem[m.pc+1]] = <-m.input
return 2
},
4: func(m *vm, modes []mode) int {
m.lastOut = m.get(1, modes[0])
m.output <- m.lastOut
return 2
},
5: func(m *vm, modes []mode) int {
if m.get(1, modes[0]) != 0 {
m.pc = m.get(2, modes[1])
return 0
}
return 3
},
6: func(m *vm, modes []mode) int {
if m.get(1, modes[0]) == 0 {
m.pc = m.get(2, modes[1])
return 0
}
return 3
},
7: func(m *vm, modes []mode) int {
res := 0
if m.get(1, modes[0]) < m.get(2, modes[1]) {
res = 1
}
m.mem[m.mem[m.pc+3]] = res
return 4
},
8: func(m *vm, modes []mode) int {
res := 0
if m.get(1, modes[0]) == m.get(2, modes[1]) {
res = 1
}
m.mem[m.mem[m.pc+3]] = res
return 4
},
}
func newVM(mem []int) *vm {
memcpy := make([]int, len(mem))
copy(memcpy, mem)
return &vm{pc: 0, mem: memcpy, input: make(chan int, 2), output: make(chan int, 2)}
}
func (m *vm) run() int {
for m.pc = 0; m.mem[m.pc] != 99; {
instr, modes := readInstr(m.mem[m.pc])
m.pc += opcodes[instr](m, modes)
}
return 0
}
func (m *vm) write(in int) {
m.input <- in
}
func (m *vm) read() int {
return <-m.output
}
func (m vm) get(offset int, md mode) int {
if md == immediate {
return m.mem[m.pc+offset]
}
return m.mem[m.mem[m.pc+offset]]
}
func readInstr(in int) (int, []mode) {
return in % 100, []mode{
mode((in % 1000) / 100),
mode((in % 10000) / 1000),
mode((in % 100000) / 10000),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment