diff --git a/eight/day_eight.go b/eight/day_eight.go new file mode 100644 index 0000000..a89e00e --- /dev/null +++ b/eight/day_eight.go @@ -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) +} diff --git a/eight/day_eight_test.go b/eight/day_eight_test.go new file mode 100644 index 0000000..b09f132 --- /dev/null +++ b/eight/day_eight_test.go @@ -0,0 +1,97 @@ +package eight + +import "testing" + +func (p *program) visited() int { + highest := 0 + for i, instruction := range p.instructions { + if instruction.executed { + if i > highest { + highest = i + } + } + } + return highest +} + +func Test_program_load(t *testing.T) { + p := program{} + err := p.load("sample.code") + if err != nil { + t.Log(err) + t.FailNow() + } + + if len(p.instructions) != 9 { + t.Logf("Expected 9 instructions, Got %d instructions", len(p.instructions)) + t.FailNow() + } +} + +func Test_program_execute(t *testing.T) { + p := program{} + p.load("sample.code") + + result := p.exec() + if result != 5 { + t.Logf("Expected result of 5, Got %d", result) + t.FailNow() + } +} + +func Test_program_terminate(t *testing.T) { + p := program{} + p.load("sample.code") + + p.exec() + highest := p.visited() + p.flipJmpNop(highest) + p.reset() + result := p.exec() + highest = p.visited() + + if highest+1 != len(p.instructions) { + t.Logf("Made it to %d of %d instructions", highest+1, len(p.instructions)) + t.Fail() + } + + if result != 8 || p.preempted { + t.Logf("Expected result of 8, Got %d and the program was preempted", result) + t.FailNow() + } +} + +func Test_program_heal(t *testing.T) { + p := program{} + p.load("sample.code") + + p.exec() + index := p.heal() + highest := p.visited() + + if highest+1 != len(p.instructions) { + t.Logf("Made it to %d of %d instructions by flipping instruction %d", highest+1, len(p.instructions), index+1) + t.Fail() + } + + if p.accumulator != 8 || p.preempted { + t.Logf("Expected result of 8, Got %d and the program was preempted", p.accumulator) + t.FailNow() + } +} + +func Test_handheld_terminate(t *testing.T) { + p := program{} + p.load("handheld.code") + + p.exec() + highest := p.visited() + t.Logf("Made it to %d of %d instructions on the first run", highest+1, len(p.instructions)) + p.heal() + highest = p.visited() + + if highest+1 != len(p.instructions) || p.preempted { + t.Logf("Made it to %d of %d instructions", highest+1, len(p.instructions)) + t.Fail() + } +} diff --git a/eight/handheld.code b/eight/handheld.code new file mode 100644 index 0000000..5f0ecbb --- /dev/null +++ b/eight/handheld.code @@ -0,0 +1,660 @@ +jmp +11 +nop +495 +nop +402 +jmp +570 +jmp +569 +jmp +451 +acc -12 +jmp +364 +acc +30 +acc +21 +jmp +430 +jmp +87 +acc -12 +acc -4 +acc +11 +jmp +50 +jmp +149 +jmp +341 +nop +1 +acc +33 +jmp +461 +acc +43 +acc -15 +jmp +440 +acc +18 +acc +22 +acc -14 +nop +576 +jmp -22 +acc +33 +acc +0 +acc +34 +jmp +369 +nop +497 +nop +469 +acc -12 +jmp +93 +acc -13 +jmp +337 +acc +5 +acc +18 +acc +26 +nop +115 +jmp +67 +nop +282 +nop -6 +nop +289 +jmp +303 +acc +10 +acc -15 +jmp +153 +nop +445 +acc -8 +acc +11 +jmp +374 +acc +35 +acc -9 +nop +199 +jmp +1 +jmp +369 +jmp +1 +acc +22 +acc -18 +acc +17 +jmp +303 +acc +37 +acc +13 +acc +22 +nop +307 +jmp +154 +nop +381 +acc -6 +nop -54 +acc +38 +jmp +494 +acc +37 +acc +15 +jmp +475 +jmp +474 +nop +534 +acc +37 +jmp +359 +jmp +296 +acc +40 +jmp +157 +acc +5 +nop +139 +acc +49 +acc +45 +jmp +237 +acc +42 +acc +8 +acc +43 +jmp +466 +nop +362 +acc +43 +acc +44 +jmp +233 +acc +30 +acc +42 +acc -6 +jmp -97 +jmp +527 +acc +2 +acc +13 +nop +425 +jmp +113 +nop +374 +acc +31 +jmp +48 +acc +29 +acc +15 +acc +35 +jmp +357 +acc +19 +acc -2 +jmp +480 +acc +1 +jmp +385 +acc +16 +acc +47 +jmp +397 +jmp +1 +jmp +1 +acc +5 +acc -5 +jmp +529 +acc +11 +jmp +123 +acc +44 +acc +49 +jmp +413 +acc +13 +acc +10 +acc -6 +acc +11 +jmp -33 +acc +25 +acc +47 +acc +40 +acc +23 +jmp +39 +acc +50 +acc +12 +jmp +386 +acc +23 +jmp +464 +acc +15 +nop +361 +acc +30 +jmp +346 +jmp +1 +acc +19 +acc +16 +acc +23 +jmp +441 +jmp +69 +acc +12 +acc +46 +acc -5 +jmp +427 +acc +49 +nop +173 +acc -12 +jmp +249 +acc +41 +acc +29 +nop +168 +acc +31 +jmp +349 +acc +40 +acc +8 +acc +14 +jmp +231 +acc -17 +jmp +215 +nop +202 +acc +0 +nop +172 +jmp +351 +acc +21 +acc +31 +nop +405 +acc +14 +jmp +272 +acc +5 +acc +33 +acc +31 +acc +21 +jmp -91 +acc -18 +acc +35 +jmp +23 +acc -10 +nop +374 +acc +27 +jmp -157 +acc +39 +acc +8 +acc +34 +acc +34 +jmp +333 +jmp -51 +acc -18 +acc +26 +jmp +377 +acc -5 +jmp +190 +acc +45 +jmp +1 +acc +29 +jmp +202 +acc +25 +acc +30 +jmp +90 +acc +49 +nop +240 +jmp +109 +jmp +291 +acc +9 +jmp +348 +acc +39 +jmp +3 +jmp +273 +jmp -218 +jmp +150 +jmp +1 +jmp +148 +acc +9 +acc +11 +acc +20 +acc +3 +jmp -167 +nop +223 +jmp +275 +nop +309 +jmp +20 +acc -18 +acc -10 +acc -2 +jmp +173 +acc +13 +acc -17 +nop +132 +acc -6 +jmp +240 +acc +37 +acc +4 +acc +49 +acc -16 +jmp +171 +jmp +239 +nop +300 +nop +311 +acc -9 +jmp -180 +acc +32 +acc +21 +jmp +1 +jmp -62 +nop +141 +acc +46 +acc +25 +nop -7 +jmp +318 +acc +3 +jmp +185 +nop +196 +acc +16 +acc +18 +jmp -47 +acc +39 +acc +35 +acc +21 +acc +14 +jmp +23 +acc +20 +acc +20 +jmp +97 +nop -71 +acc +50 +acc -11 +jmp -145 +nop -218 +acc +42 +acc +23 +acc +35 +jmp +183 +nop +16 +nop -206 +acc +2 +acc +11 +jmp +129 +acc +37 +acc +41 +acc +47 +nop -280 +jmp +93 +acc -12 +acc +31 +jmp +10 +acc +2 +acc +29 +jmp +64 +acc -14 +nop +308 +jmp -251 +acc +8 +acc +10 +jmp +259 +acc +38 +nop -131 +acc +45 +jmp +6 +acc +18 +acc +43 +nop -218 +nop -94 +jmp +178 +jmp +1 +acc +27 +acc +29 +jmp +324 +acc -12 +acc +30 +jmp +115 +acc -1 +jmp -224 +jmp +1 +jmp +205 +acc +47 +jmp -66 +acc +21 +acc +44 +jmp +147 +acc +2 +acc +50 +acc -14 +acc +50 +jmp -165 +acc +33 +acc +20 +acc -5 +acc +19 +jmp -246 +acc +26 +acc +44 +jmp -96 +acc +22 +jmp +127 +nop +25 +acc -14 +acc -15 +jmp -314 +jmp +1 +acc +11 +acc +12 +jmp +71 +acc +0 +acc +16 +acc +26 +nop +242 +jmp -172 +acc +8 +acc +15 +acc -4 +jmp -78 +acc +42 +jmp +225 +acc -7 +jmp +243 +jmp +242 +acc +23 +acc +21 +jmp +54 +acc +25 +jmp -18 +jmp -42 +jmp +26 +jmp -368 +acc +29 +acc +22 +acc +1 +acc +0 +jmp +255 +acc +39 +jmp +1 +nop -332 +acc +22 +jmp +92 +acc +45 +acc +29 +jmp +12 +jmp +1 +acc +22 +jmp +1 +jmp -245 +jmp -162 +acc -4 +acc -4 +jmp +28 +nop -4 +jmp -386 +jmp -28 +acc -1 +acc +25 +nop -28 +jmp -10 +acc +9 +acc +45 +jmp +1 +acc +13 +jmp -171 +acc +3 +acc +19 +acc -8 +acc +11 +jmp -266 +acc -18 +nop -380 +jmp -155 +acc +36 +acc -13 +acc +35 +acc -16 +jmp -414 +nop -408 +jmp +36 +acc +5 +jmp +101 +acc -7 +acc +17 +jmp -204 +acc -14 +jmp -99 +jmp +1 +nop -165 +acc +10 +acc +13 +jmp +46 +acc -13 +jmp -358 +acc -7 +acc -14 +jmp -31 +acc +21 +acc -9 +jmp -46 +nop -220 +acc -1 +jmp -105 +acc +42 +acc -14 +jmp -75 +acc +6 +jmp -34 +nop -391 +acc -11 +jmp -123 +nop -234 +acc -9 +acc +35 +jmp -317 +nop +150 +acc +11 +jmp +138 +acc +30 +acc -11 +acc +31 +jmp -134 +acc +20 +jmp -200 +acc +13 +acc +14 +acc +25 +jmp -310 +acc +13 +acc +18 +acc -1 +jmp +85 +jmp +72 +acc +1 +jmp -78 +acc -8 +jmp -149 +acc +13 +jmp -438 +acc +38 +nop -25 +jmp -264 +acc +50 +acc +47 +nop -241 +acc +31 +jmp -419 +jmp +57 +nop -359 +jmp -323 +acc +48 +acc +4 +acc -12 +acc +42 +jmp -167 +acc +50 +acc -9 +jmp -138 +nop -171 +acc +48 +jmp -398 +acc -8 +acc +41 +acc +21 +jmp -508 +acc +29 +acc +41 +acc +35 +acc +25 +jmp -388 +jmp -439 +acc +26 +acc +19 +acc +13 +acc -16 +jmp -165 +nop -61 +acc +16 +acc +20 +jmp -312 +nop -19 +jmp -101 +acc +1 +jmp -515 +acc +19 +jmp +96 +jmp +1 +acc +42 +acc +34 +acc +33 +jmp +80 +nop -314 +acc +12 +acc +36 +nop -405 +jmp -87 +acc +16 +nop -100 +acc +11 +acc +15 +jmp -524 +nop -369 +acc +8 +jmp -386 +acc +32 +jmp -77 +acc -7 +acc -16 +acc +33 +acc +30 +jmp -213 +acc -2 +jmp -403 +acc +35 +nop -81 +jmp -340 +acc +7 +acc +3 +jmp -444 +jmp -445 +jmp -218 +acc +39 +acc -9 +jmp +1 +jmp -284 +acc +43 +acc +1 +acc -12 +nop -218 +jmp -460 +jmp -404 +jmp +1 +jmp -135 +jmp -223 +jmp +1 +acc +30 +acc +36 +jmp -61 +jmp -580 +acc -8 +jmp -79 +acc +18 +acc -1 +acc +9 +jmp -321 +jmp -560 +acc +2 +jmp -182 +acc +18 +acc +29 +acc +28 +jmp -129 +acc +10 +nop -120 +jmp +16 +acc +23 +acc +9 +acc +36 +acc +24 +jmp -589 +acc +21 +jmp -419 +nop -275 +jmp -231 +jmp -341 +acc +33 +acc +30 +jmp -470 +nop -337 +jmp -389 +jmp +5 +acc -14 +nop -27 +acc +5 +jmp -78 +acc +40 +acc +2 +acc -5 +nop -205 +jmp -537 +jmp -318 +nop -404 +acc +12 +acc +0 +acc -4 +jmp -54 +acc +8 +acc +32 +nop -357 +acc +35 +jmp -153 +acc +42 +acc +17 +acc -9 +jmp -13 +nop -222 +acc +27 +jmp -63 +acc +11 +acc -17 +nop -45 +acc +4 +jmp -217 +acc +5 +acc +26 +nop -574 +jmp -489 +acc +29 +acc +36 +acc +31 +nop -407 +jmp +1 \ No newline at end of file diff --git a/eight/sample.code b/eight/sample.code new file mode 100644 index 0000000..6fee349 --- /dev/null +++ b/eight/sample.code @@ -0,0 +1,9 @@ +nop +0 +acc +1 +jmp +4 +acc +3 +jmp -3 +acc -99 +acc +1 +jmp -4 +acc +6 \ No newline at end of file diff --git a/main.go b/main.go index 5794303..011c892 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "fmt" - "github.com/thatguygriff/aoc2020/seven" + "github.com/thatguygriff/aoc2020/eight" ) func main() { @@ -32,6 +32,10 @@ func main() { // fmt.Println(six.PartTwo()) // Day 7 - fmt.Println(seven.PartOne()) - fmt.Println(seven.PartTwo()) + // fmt.Println(seven.PartOne()) + // fmt.Println(seven.PartTwo()) + + // Day 8 + fmt.Println(eight.PartOne()) + fmt.Println(eight.PartTwo()) }