Files
advent-of-code-go/2018/day19/main.go
T
2020-12-05 00:45:13 -05:00

257 lines
6.3 KiB
Go

package main
import (
"flag"
"fmt"
"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)
if part == 1 {
ans := part1(util.ReadFile("./input.txt"))
fmt.Println("Output:", ans)
} else {
ans := part2(util.ReadFile("./input.txt"))
fmt.Println("Output:", ans)
}
}
func part1(input string) int {
opcodeComputer := parseInput(input)
for !opcodeComputer.tick() {
}
return opcodeComputer.registers[0]
}
func part2(input string) int {
opcodeComputer := parseInput(input)
opcodeComputer.registers[0] = 1
for !opcodeComputer.tick() {
}
return opcodeComputer.registers[0]
}
// after deeply studying how the intcode cycles, in order to optimize it and
// run in any reasonable amount of time. It's become clear that the answer is
// just the sum of all the factors of the number that is generated after a few
// steps of the opcode computer running
func part2Cheeky(input string) int {
computer := parseInput(input)
computer.registers[0] = 1
for i := 0; i < 20; i++ {
computer.tick()
}
numberToFactorize := computer.registers[2] // this index varies based on inputs
var ans int
for i := 1; i <= numberToFactorize; i++ {
if numberToFactorize%i == 0 {
ans += i
}
}
return ans
}
type opcodeComputer struct {
instructions []instruction
registers [6]int
instructionPointer int // an index the stores the index for which instruction to run
}
type instruction struct {
name string
abcValues [3]int
}
func (o *opcodeComputer) tick() (done bool) {
// custom logic for the repetitive behavior
ipValue := o.registers[o.instructionPointer]
if ipValue == 4 {
for o.registers[4] == 4 {
if o.registers[1] >= o.registers[2] {
break
}
if o.registers[5] == o.registers[2] {
o.registers[0] += o.registers[1]
}
o.registers[3]++
reg3 := o.registers[3]
if reg3 > o.registers[2] {
o.registers[1]++
// escape hatch
if o.registers[1] > o.registers[2] {
o.registers[4] *= o.registers[4]
o.registers[4]++
break
}
o.registers[3] = 1
o.registers[5] = o.registers[1]
} else if o.registers[2]%o.registers[1] == 0 {
// increase registers 5 to hit o.reg5 == o.reg2
// side of 5 = 1 x 3
o.registers[5] = o.registers[2]
o.registers[3] = o.registers[2]
} else {
o.registers[3] = o.registers[2]
}
}
}
if o.registers[o.instructionPointer] >= len(o.instructions) {
return true
}
inst := o.instructions[o.registers[o.instructionPointer]]
opcodeFunc := opcodeNamesToFuncs[inst.name]
o.registers = opcodeFunc(o.registers, inst.abcValues)
// increment value @ instructionPointer, validate that it's still in range
o.registers[o.instructionPointer]++
if o.registers[o.instructionPointer] >= len(o.instructions) {
return true
}
return false
}
func parseInput(input string) opcodeComputer {
lines := strings.Split(input, "\n")
var instructionPointer int
fmt.Sscanf(lines[0], "#ip %d", &instructionPointer)
var instructions []instruction
for _, l := range lines[1:] {
var inst instruction
fmt.Sscanf(l, "%4s %d %d %d", &inst.name, &inst.abcValues[0], &inst.abcValues[1], &inst.abcValues[2])
instructions = append(instructions, inst)
}
// for i, v := range instructions {
// fmt.Println(i, v)
// }
return opcodeComputer{
instructions: instructions,
instructionPointer: instructionPointer,
}
}
var opcodeNamesToFuncs = map[string]opcodeFunc{
"addr": addr, "addi": addi,
"mulr": mulr, "muli": muli,
"banr": banr, "bani": bani,
"borr": borr, "bori": bori,
"setr": setr, "seti": seti,
"gtir": gtir, "gtri": gtri, "gtrr": gtrr,
"eqir": eqir, "eqri": eqri, "eqrr": eqrr,
}
type opcodeFunc func([6]int, [3]int) [6]int
func addr(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] + registers[abcValues[1]]
return registers
}
func addi(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] + abcValues[1]
return registers
}
func mulr(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] * registers[abcValues[1]]
return registers
}
func muli(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] * abcValues[1]
return registers
}
func banr(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] & registers[abcValues[1]]
return registers
}
func bani(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] & abcValues[1]
return registers
}
func borr(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] | registers[abcValues[1]]
return registers
}
func bori(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]] | abcValues[1]
return registers
}
func setr(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = registers[abcValues[0]]
return registers
}
func seti(registers [6]int, abcValues [3]int) [6]int {
registers[abcValues[2]] = abcValues[0]
return registers
}
func gtir(registers [6]int, abcValues [3]int) [6]int {
if abcValues[0] > registers[abcValues[1]] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}
func gtri(registers [6]int, abcValues [3]int) [6]int {
if registers[abcValues[0]] > abcValues[1] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}
func gtrr(registers [6]int, abcValues [3]int) [6]int {
if registers[abcValues[0]] > registers[abcValues[1]] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}
func eqir(registers [6]int, abcValues [3]int) [6]int {
if abcValues[0] == registers[abcValues[1]] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}
func eqri(registers [6]int, abcValues [3]int) [6]int {
if registers[abcValues[0]] == abcValues[1] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}
func eqrr(registers [6]int, abcValues [3]int) [6]int {
if registers[abcValues[0]] == registers[abcValues[1]] {
registers[abcValues[2]] = 1
} else {
registers[abcValues[2]] = 0
}
return registers
}