mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
257 lines
6.3 KiB
Go
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
|
|
}
|