diff --git a/08/input b/08/input new file mode 100644 index 0000000..4d281ca --- /dev/null +++ b/08/input @@ -0,0 +1,591 @@ +acc -5 +acc +48 +acc -1 +acc +5 +jmp +426 +acc +8 +jmp +72 +acc +22 +nop +64 +acc +18 +jmp +447 +acc +9 +acc +21 +acc -1 +acc -18 +jmp +349 +jmp +475 +acc +10 +nop +273 +acc -12 +acc +16 +jmp +519 +jmp +315 +acc -15 +acc +7 +acc +41 +acc -3 +jmp +97 +acc +28 +jmp +245 +acc +20 +acc -13 +acc +14 +jmp +304 +acc +20 +nop +73 +acc +0 +jmp +308 +jmp +1 +acc +6 +acc -18 +nop -7 +jmp +327 +acc +39 +acc -14 +jmp +473 +jmp +1 +nop +31 +acc -17 +jmp +496 +nop +449 +jmp +163 +acc +50 +nop -31 +nop -11 +acc -7 +jmp +29 +nop +376 +nop +311 +acc +14 +acc -11 +jmp +24 +acc -13 +jmp +237 +jmp +518 +jmp +246 +jmp +380 +acc +40 +acc +17 +acc +42 +acc -14 +jmp +293 +acc +8 +acc +25 +acc +9 +nop +251 +jmp +464 +jmp +409 +jmp +452 +jmp +1 +acc -6 +jmp +230 +jmp +106 +acc -13 +jmp +40 +jmp +452 +acc +16 +jmp +37 +acc -11 +jmp +118 +acc -5 +nop +322 +acc +4 +jmp +425 +nop +61 +nop +190 +acc +37 +acc +44 +jmp +275 +acc +32 +jmp -78 +jmp +485 +nop -1 +acc +50 +jmp +424 +jmp +423 +acc +23 +jmp +460 +acc -11 +acc +10 +jmp -67 +acc -14 +acc -14 +acc +39 +acc -6 +jmp +331 +acc +12 +acc +7 +acc +29 +jmp +65 +nop -26 +jmp +1 +acc +45 +jmp +188 +acc +23 +acc +42 +acc +18 +acc +34 +jmp -94 +acc +35 +acc +0 +nop +282 +acc +33 +jmp +297 +acc +10 +acc +16 +jmp +142 +acc -9 +jmp +9 +acc +35 +jmp +15 +jmp +1 +acc -19 +acc +18 +jmp +156 +jmp +230 +jmp +421 +acc +33 +acc -2 +acc +24 +acc +17 +jmp -66 +acc +32 +acc +38 +jmp -76 +acc +13 +jmp +74 +acc +30 +acc +49 +jmp +220 +nop -44 +acc +36 +nop -23 +nop -29 +jmp +157 +acc -3 +acc -13 +jmp -124 +nop +350 +acc +29 +acc +7 +acc +42 +jmp +282 +acc -4 +acc +33 +acc +50 +acc +1 +jmp +101 +acc +13 +nop +369 +acc -11 +acc -2 +jmp +56 +jmp -5 +acc -1 +acc -1 +jmp +52 +jmp +246 +acc +38 +acc -11 +jmp +30 +acc +18 +nop +15 +jmp +67 +jmp -112 +acc -14 +jmp -8 +nop -73 +jmp +4 +acc +0 +nop +111 +jmp +317 +acc -17 +nop +108 +jmp +91 +acc +9 +jmp +324 +acc +35 +acc +9 +acc +31 +nop +208 +jmp +177 +acc -17 +jmp -135 +jmp +46 +nop +145 +acc +41 +acc -4 +acc -17 +jmp -147 +acc +8 +jmp +357 +acc +25 +jmp +231 +acc -19 +acc +46 +jmp +268 +acc -18 +acc +34 +jmp +3 +jmp -83 +jmp +294 +jmp +89 +nop +27 +acc +32 +acc -1 +acc +5 +jmp +230 +acc +9 +nop -92 +jmp -146 +acc +16 +nop +91 +jmp +251 +jmp +1 +acc +50 +jmp -49 +acc +28 +nop -60 +jmp -29 +nop +328 +acc -13 +jmp +115 +jmp +160 +jmp +1 +acc +34 +acc +44 +acc -18 +jmp +40 +jmp +305 +acc -18 +acc +44 +jmp -174 +acc +15 +nop -62 +jmp +275 +nop +34 +nop +59 +acc +27 +jmp -212 +acc +8 +acc +36 +acc +2 +jmp +27 +jmp -240 +acc +10 +acc +22 +jmp +225 +acc -13 +jmp +246 +jmp -230 +jmp +120 +acc -14 +acc -19 +jmp +261 +acc +8 +jmp -170 +acc -17 +acc +33 +acc +43 +jmp +16 +acc +6 +acc +25 +jmp +140 +jmp +12 +jmp -101 +acc +1 +jmp +67 +jmp +141 +jmp +219 +jmp -46 +acc +20 +acc +6 +acc +39 +acc +43 +jmp +32 +acc +46 +jmp -41 +acc -1 +acc +48 +jmp +220 +acc +13 +acc +33 +acc -9 +nop -206 +jmp -137 +acc +35 +acc +11 +acc -12 +acc -2 +jmp +1 +acc +11 +acc +15 +jmp -73 +jmp +1 +jmp +142 +jmp +1 +acc +29 +acc -7 +acc +45 +jmp -302 +acc -9 +jmp +5 +acc +14 +acc +5 +jmp -313 +jmp -86 +acc -11 +acc +13 +acc +3 +jmp +171 +acc -8 +acc +47 +nop +205 +jmp +181 +acc -19 +acc +26 +jmp -340 +acc +31 +acc +45 +acc +16 +acc +16 +jmp -41 +acc +44 +jmp +76 +acc +0 +acc +47 +acc +9 +acc -12 +jmp +159 +acc +21 +jmp -50 +jmp +1 +jmp -18 +acc +46 +jmp -5 +jmp +120 +jmp +51 +jmp +123 +acc +28 +nop -288 +jmp -293 +jmp -39 +jmp -309 +jmp -206 +jmp -274 +acc -10 +acc +39 +jmp +124 +acc +6 +acc -12 +acc -12 +jmp -294 +acc +30 +acc +42 +acc +30 +acc -17 +jmp -227 +nop -241 +acc +46 +jmp -64 +nop -106 +nop -25 +acc +48 +acc +48 +jmp -323 +acc +30 +acc -10 +jmp -382 +acc +44 +jmp -21 +acc -6 +jmp -102 +acc -17 +acc -13 +acc +23 +jmp -199 +acc +7 +acc +28 +acc +43 +jmp -186 +nop -105 +jmp -390 +acc +29 +nop +168 +acc +49 +jmp -9 +jmp -335 +acc +4 +jmp -86 +nop -348 +acc -17 +acc -12 +jmp +107 +acc +28 +jmp -72 +acc +17 +acc +31 +nop -10 +jmp -295 +acc +41 +jmp -271 +jmp -350 +nop -64 +acc -11 +acc +6 +jmp -198 +acc -5 +jmp -206 +acc +23 +jmp -390 +jmp +1 +jmp +1 +acc +9 +nop -91 +jmp -15 +acc +36 +acc +27 +acc +42 +jmp +18 +acc +20 +acc +10 +acc +44 +jmp +46 +jmp +110 +acc +31 +jmp -371 +acc +13 +acc -16 +nop -245 +acc +30 +jmp +38 +acc -6 +acc -14 +acc +21 +acc +46 +jmp -206 +acc +35 +acc +25 +acc +22 +acc -9 +jmp -92 +acc +20 +nop -113 +nop -189 +jmp -453 +acc +43 +acc -18 +acc -19 +acc -4 +jmp -364 +acc +35 +acc +44 +acc +19 +acc -13 +jmp -297 +acc -11 +acc +36 +nop -92 +jmp -93 +jmp -330 +acc +40 +jmp -248 +jmp -255 +acc +36 +acc +32 +jmp -190 +acc -15 +jmp -187 +jmp -23 +nop -268 +jmp -203 +acc -10 +acc +14 +acc -17 +nop -400 +jmp +61 +nop +60 +acc +17 +acc -9 +jmp -409 +acc +0 +acc +13 +acc +47 +acc -6 +jmp -102 +acc +37 +jmp -257 +acc -1 +acc +41 +acc +25 +jmp -397 +acc +9 +acc +31 +jmp -48 +acc -11 +jmp -332 +jmp -433 +jmp +30 +jmp +38 +acc +17 +nop -376 +nop -93 +acc +50 +jmp -249 +acc -10 +jmp -225 +acc +10 +jmp +35 +jmp -475 +acc +18 +jmp -250 +acc -12 +acc +25 +jmp -450 +jmp -411 +acc +45 +jmp -117 +acc -6 +acc +30 +acc -6 +nop -313 +jmp -271 +acc +22 +acc +13 +acc -12 +acc +4 +jmp -379 +acc +36 +acc +17 +acc +15 +acc +47 +jmp -417 +jmp +4 +jmp -332 +acc +23 +jmp -336 +acc +34 +acc +1 +acc +50 +acc +7 +jmp -466 +jmp -70 +acc +4 +nop +8 +acc +18 +jmp -28 +jmp -47 +jmp -410 +acc -1 +acc +3 +jmp -90 +acc +12 +acc +41 +jmp -98 +jmp -55 +acc +17 +nop -85 +acc +48 +acc +50 +jmp +1 \ No newline at end of file diff --git a/08/main.go b/08/main.go new file mode 100644 index 0000000..b79173c --- /dev/null +++ b/08/main.go @@ -0,0 +1,165 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +func main() { + partOne() + partTwo() +} + +type opCode struct { + operation string + value int +} + +type register struct { + value int +} + +type registry map[string]*register + +type program []opCode + +func lineToOp(s string) opCode { + sp := strings.Split(s, " ") + i, _ := strconv.Atoi(sp[1]) + return opCode{ + operation: sp[0], + value: i, + } +} + +// take registry, program, current opcode location, perform operation if possible, return next opcode location +func execute(r registry, p program, i int) (int, error) { + if i >= len(p) { + return -1, fmt.Errorf("program terminates") + } + currentOp := p[i] + switch currentOp.operation { + case "nop": + return i + 1, nil + case "acc": + r["acc"].value = r["acc"].value + currentOp.value + return i + 1, nil + case "jmp": + return i + currentOp.value, nil + default: + return -1, fmt.Errorf("unknown opcode") + } +} + +// The boot code is represented as a text file with one instruction per line of text. +// Each instruction consists of an operation (acc, jmp, or nop) and an argument (a signed number like +4 or -20). + +// * `acc` increases or decreases a single global value called the accumulator by the value given in the argument. +// For example, acc +7 would increase the accumulator by 7. The accumulator starts at 0. +// After an acc instruction, the instruction immediately below it is executed next. +// * `jmp` jumps to a new instruction relative to itself. +// The next instruction to execute is found using the argument as an offset from the jmp instruction; +// for example, jmp +2 would skip the next instruction, jmp +1 would continue to the instruction immediately below it, +// and jmp -20 would cause the instruction 20 lines above to be executed next. +// * `nop` stands for No OPeration - it does nothing. The instruction immediately below it is executed next. + +// Run your copy of the boot code. Immediately before any instruction is executed a second time, what value is in the accumulator? + +func partOne() { + f, _ := os.Open("input") + reader := bufio.NewReader(f) + scanner := bufio.NewScanner(reader) + + prog := program{} + for scanner.Scan() { + line := scanner.Text() + prog = append(prog, lineToOp(line)) + } + + reg := registry{ + "acc": ®ister{ + value: 0, + }, + } + currentOp := 0 + executedLines := []int{} + for { + executedLines = append(executedLines, currentOp) + nextOp, err := execute(reg, prog, currentOp) + if nextOp == -1 || err != nil { + fmt.Println(err.Error()) + break + } + for _, j := range executedLines { + if nextOp == j { + fmt.Println(reg["acc"].value) + return + } + } + currentOp = nextOp + } +} + +// The program is supposed to terminate by attempting to execute an instruction immediately after the last instruction in the file. +// By changing exactly one jmp or nop, you can repair the boot code and make it terminate correctly. +// Fix the program so that it terminates normally by changing exactly one jmp (to nop) or nop (to jmp). +// What is the value of the accumulator after the program terminates? + +func partTwo() { + f, _ := os.Open("input") + reader := bufio.NewReader(f) + scanner := bufio.NewScanner(reader) + + prog := program{} + + for scanner.Scan() { + line := scanner.Text() + prog = append(prog, lineToOp(line)) + } + + // guess we're just going to brute-force this huh + for i := range prog { + newP := make(program, len(prog)) + copy(newP, prog) + if prog[i].operation == "jmp" { + newP[i].operation = "nop" + } else if prog[i].operation == "nop" { + newP[i].operation = "jmp" + } + result, err := isolatedProgramRunner(newP) + if err == nil { + fmt.Println(result) + return + } + } +} + +func isolatedProgramRunner(p program) (int, error) { + reg := registry{ + "acc": ®ister{ + value: 0, + }, + } + executedLines := []int{} + + currentOp := 0 + for { + executedLines = append(executedLines, currentOp) + nextOp, err := execute(reg, p, currentOp) + if nextOp == -1 { + return reg["acc"].value, nil + } + if err != nil { + return -1, err + } + for _, j := range executedLines { + if nextOp == j { + return -1, fmt.Errorf("program loops") + } + } + currentOp = nextOp + } +}