Day 8: Part 1 and 2
Signed-off-by: James Griffin <james@unsupervised.ca>
This commit is contained in:
129
eight/day_eight.go
Normal file
129
eight/day_eight.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package eight
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type program struct {
|
||||
instructions []instruction
|
||||
accumulator int
|
||||
preempted bool
|
||||
}
|
||||
|
||||
type instruction struct {
|
||||
operation string
|
||||
argument int
|
||||
executed bool
|
||||
}
|
||||
|
||||
func (p *program) load(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
var op string
|
||||
var value int
|
||||
|
||||
count, err := fmt.Sscanf(scanner.Text(), "%s %d", &op, &value)
|
||||
if count != 2 || err != nil {
|
||||
return fmt.Errorf("Unable to parse %s: %w", scanner.Text(), err)
|
||||
}
|
||||
|
||||
p.instructions = append(p.instructions, instruction{
|
||||
operation: op,
|
||||
argument: value,
|
||||
executed: false,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *program) exec() int {
|
||||
i := 0
|
||||
for {
|
||||
if i >= len(p.instructions) {
|
||||
p.preempted = false
|
||||
return p.accumulator
|
||||
} else if i < 0 {
|
||||
return p.accumulator
|
||||
}
|
||||
|
||||
if p.instructions[i].executed {
|
||||
break
|
||||
}
|
||||
|
||||
p.instructions[i].executed = true
|
||||
switch p.instructions[i].operation {
|
||||
case "acc":
|
||||
p.accumulator += p.instructions[i].argument
|
||||
i++
|
||||
case "jmp":
|
||||
i += p.instructions[i].argument
|
||||
default:
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
return p.accumulator
|
||||
}
|
||||
|
||||
func (p *program) reset() {
|
||||
p.accumulator = 0
|
||||
p.preempted = true
|
||||
for i := 0; i < len(p.instructions); i++ {
|
||||
p.instructions[i].executed = false
|
||||
}
|
||||
}
|
||||
|
||||
func (p *program) flipJmpNop(index int) {
|
||||
if index < 0 || index > len(p.instructions) {
|
||||
return
|
||||
}
|
||||
|
||||
switch p.instructions[index].operation {
|
||||
case "nop":
|
||||
p.instructions[index].operation = "jmp"
|
||||
case "jmp":
|
||||
p.instructions[index].operation = "nop"
|
||||
}
|
||||
}
|
||||
|
||||
func (p *program) heal() int {
|
||||
for i := 0; i < len(p.instructions); i++ {
|
||||
p.reset()
|
||||
p.flipJmpNop(i)
|
||||
p.exec()
|
||||
|
||||
if !p.preempted {
|
||||
return i
|
||||
}
|
||||
p.flipJmpNop(i)
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// PartOne Find the value of the accumulator before any instruction is executed twice
|
||||
func PartOne() string {
|
||||
p := program{}
|
||||
p.load("eight/handheld.code")
|
||||
|
||||
return fmt.Sprintf("The accumulator is at %d before the loop begins", p.exec())
|
||||
}
|
||||
|
||||
// PartTwo Find the corrupt instruction, flip it, and execute to termination
|
||||
func PartTwo() string {
|
||||
p := program{}
|
||||
p.load("eight/handheld.code")
|
||||
p.exec()
|
||||
index := p.heal()
|
||||
|
||||
return fmt.Sprintf("The accumulator is at %d after termination by correcting instruction %d", p.accumulator, index+1)
|
||||
}
|
Reference in New Issue
Block a user