adventofcode/2020/day08.go

102 lines
1.9 KiB
Go

package main
import (
"fmt"
"log"
"os"
"strconv"
"strings"
"git.annabunch.es/annabunches/adventofcode/2020/lib/util"
)
type Instruction struct {
Operation string
Operand int
}
func parseInstruction(input string) Instruction {
data := strings.Split(input, " ")
op := data[0]
operand, err := strconv.Atoi(strings.TrimPrefix(data[1], "+"))
if err != nil {
log.Panicf(err.Error())
}
return Instruction{
Operation: op,
Operand: operand,
}
}
func executeInstruction(ins Instruction, ip, acc *int, history map[int]bool) {
history[*ip] = true
switch ins.Operation {
case "acc":
*acc += ins.Operand
*ip++
case "jmp":
*ip += ins.Operand
case "nop":
*ip++
}
}
func executeProgram(instructions []Instruction) (int, bool) {
ip := 0
acc := 0
history := make(map[int]bool)
for ip < len(instructions) {
if _, found := history[ip]; found {
// detect infinite loop and return
return acc, true
}
executeInstruction(instructions[ip], &ip, &acc, history)
}
return acc, false
}
func main() {
step := os.Args[1]
values := util.InputParserStrings(os.Args[2])
instructions := make([]Instruction, 0)
for _, line := range values {
if line == "" {
continue
}
ins := parseInstruction(line)
instructions = append(instructions, ins)
}
switch step {
case "1":
ret, loop := executeProgram(instructions)
if loop {
fmt.Println("Loop detected. Last ACC value:", ret)
}
case "2":
for i, ins := range instructions {
if ins.Operation == "jmp" || ins.Operation == "nop" {
newInstructions := make([]Instruction, len(instructions))
copy(newInstructions, instructions)
switch ins.Operation {
case "jmp":
newInstructions[i].Operation = "nop"
case "nop":
newInstructions[i].Operation = "jmp"
}
ret, loop := executeProgram(newInstructions)
if !loop {
fmt.Println(ret)
break
}
}
}
}
}