mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
2018-day21: super confusing intcode solving
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
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() {
|
||||
// instruction 28 of my input is the only one that accesses register zero
|
||||
// it is comparing reg 0 to reg 5. so to break out of loops asap, set
|
||||
// reg 0 to the value found in reg 5 when 28 is hit for the first time
|
||||
if opcodeComputer.registers[opcodeComputer.instructionPointer] == 28 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return opcodeComputer.registers[5]
|
||||
}
|
||||
|
||||
func part2(input string) int {
|
||||
opcodeComputer := parseInput(input)
|
||||
|
||||
// similar idea for part 2 but now we need to find the previous state of
|
||||
// register 5 when register 5 REPEATS itself. this is a brute force solution
|
||||
// using a map to store previous reg5 values, and stores the previous reg5
|
||||
var lastReg5 int
|
||||
comparedRegister5s := map[int]bool{}
|
||||
for !opcodeComputer.tick() {
|
||||
if opcodeComputer.registers[opcodeComputer.instructionPointer] == 28 {
|
||||
reg5 := opcodeComputer.registers[5]
|
||||
if comparedRegister5s[reg5] {
|
||||
break
|
||||
}
|
||||
comparedRegister5s[reg5] = true
|
||||
lastReg5 = reg5
|
||||
}
|
||||
}
|
||||
|
||||
return lastReg5
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// literal opcode computer implementation, unoptimized
|
||||
func (o *opcodeComputer) tick() (done bool) {
|
||||
if o.registers[o.instructionPointer] >= len(o.instructions) {
|
||||
fmt.Println("Out of range instruction, terminating...")
|
||||
return true
|
||||
}
|
||||
instIndex := o.registers[o.instructionPointer]
|
||||
inst := o.instructions[instIndex]
|
||||
|
||||
// fmt.Println(strings.Repeat(" ", instIndex) + strconv.Itoa(instIndex))
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
func Test_part1(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want int
|
||||
}{
|
||||
{"actual", util.ReadFile("input.txt"), 2884703},
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_part2(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want int
|
||||
}{
|
||||
{"actual", util.ReadFile("input.txt"), 15400966},
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user