From 54a91e53c73608c1c342cc5742605769cfe0d868 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 23 Dec 2016 13:20:07 -0600 Subject: [PATCH] Day 23 Complete --- 2016/day23/main.go | 168 ++++++++++++++++++++++++++++++------------- 2016/day23/problem | 93 ++++++++++++++++++++++++ 2016/day23/testinput | 7 -- 3 files changed, 212 insertions(+), 56 deletions(-) create mode 100644 2016/day23/problem delete mode 100644 2016/day23/testinput diff --git a/2016/day23/main.go b/2016/day23/main.go index ebbfff2..e14c32d 100644 --- a/2016/day23/main.go +++ b/2016/day23/main.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/fatih/color" termbox "github.com/nsf/termbox-go" "../../" @@ -18,9 +19,10 @@ var regs = map[string]int{ "d": 0, } -var instructions []string -var curr int -var pause bool +var instructions, lastInst []string +var curr, cursor int +var pause, step, skip bool +var breakpoints []int func main() { var debug bool @@ -54,70 +56,107 @@ func main() { var ins []string for curr < len(instructions) || done { if debug { - lastInst := ins - // print state and wait for user to step - PrintState() - fmt.Println("Last Instruction:", lastInst) - //PrintInstructionState() - fmt.Println("(q): quit (space): pause/unpause") - ev := <-eventChan - if ev.Type == termbox.EventKey { - if ev.Key == termbox.KeySpace { - pause = !pause - } - if ev.Ch == 'q' { - break - } - } + lastInst = ins } ins = strings.Fields(instructions[curr]) - curr++ + if len(ins) == 0 { + break + } // Optimize multiplication /* - // TODO: > cpy b c inc a dec c jnz c -2 dec d jnz d -5 - == mlt b d a - and curr += 5 + == add (b * d) to a + set c & d to 0 + curr += 5 */ if ins[0] == "cpy" { - - if strings.HasPrefix(instructions[curr+1], "inc") && strings.HasPrefix(instructions[curr+2], "dec") && strings.HasPrefix(instructions[curr+3], "jnz") && strings.HasPrefix(instructions[curr+4], "dec") && strings.HasPrefix(instructions[curr+5], "jnz") { - - allGood := true - // The right instruction set, make sure the arguments match up + if len(instructions) >= curr+6 { ins1 := strings.Fields(instructions[curr+1]) ins2 := strings.Fields(instructions[curr+2]) ins3 := strings.Fields(instructions[curr+3]) ins4 := strings.Fields(instructions[curr+4]) ins5 := strings.Fields(instructions[curr+5]) - // Make sure all "c"s are correct - if ins[2] != ins2[1] && ins[2] != ins3[1] { - allGood = false - } - if allGood { - // Make sure all "b"s are correct - if ins[1] == ins1[1] || ins[1] == ins2[1] || ins[1] == ins4[1] { - allGood = false + if ins1[0] == "inc" && ins2[0] == "dec" && ins3[0] == "jnz" && ins4[0] == "dec" && ins5[0] == "jnz" { + allGood := true + if allGood { + // Do the multiplication + // ins[1] * ins4[1] + // add that value to ins1[1] + // set ins[2] to 0 + // set ins4[1] to 0 + // Then add 5 to the pc + src1 := ins[1] + src2 := ins4[1] + dst := ins1[1] + if _, ok := regs[dst]; !ok { + // Invalid destination register + allGood = false + } + if _, ok := regs[src1]; !ok { + // Invalid source register + allGood = false + } + if _, ok := regs[src2]; !ok { + allGood = false + } + if allGood { + regs[dst] += (regs[src1] * regs[src2]) + curr += 6 + skip = true + } } } - if allGood { - // Make sure all "d"s are correct - if (ins[1] == ins4[1] || ins[2] == ins4[1]) || ins4[1] != ins5[1] { - allGood = false - } - } - if allGood { - // Go ahead and change the instruction - ins = []string{"mult", ins[1], ins4[1], ins1[1]} - curr += 5 - } } } + if debug { + if isBreakpoint(curr + 1) { + pause = true + step = false + } + for pause && !step { + // print state and wait for user to step + PrintState() + fmt.Println("Last Instruction:", lastInst) + PrintInstructionState() + fmt.Println("(q): quit (space): pause/unpause (s): step (b): toggle breakpoint") + ev := <-eventChan + if ev.Type == termbox.EventKey { + switch { + case ev.Key == termbox.KeySpace: + pause = !pause + case ev.Ch == 'q': + done = true + case ev.Ch == 'b': + toggleBreakpoint(cursor) + case ev.Ch == 's': + step = true + case ev.Key == termbox.KeyArrowUp: + if cursor > 0 { + cursor-- + } + case ev.Key == termbox.KeyArrowDown: + if cursor < len(instructions)-1 { + cursor++ + } + } + } + } + step = false + } + if done { + // User hit 'q' + break + } + if skip { + skip = false + continue + } + curr++ switch ins[0] { case "jnz": // If we have a jnz c -2 it could be moving all of c into another register @@ -211,6 +250,8 @@ func main() { } } PrintState() + fmt.Println("Press any key to exit") + termbox.PollEvent() } // Fancy State Printing @@ -229,11 +270,21 @@ func PrintRegs() { func PrintInstructionState() { for pi := range instructions { if pi == curr { - fmt.Print("> ") + fmt.Print(">") } else { - fmt.Print(" ") + fmt.Print(" ") + } + if isBreakpoint(pi) { + fmt.Print("B") + } else { + fmt.Print(" ") + } + if cursor == pi { + cursor := color.New(color.FgBlack).Add(color.BgWhite) + cursor.Println(instructions[pi]) + } else { + fmt.Println(instructions[pi]) } - fmt.Println(instructions[pi]) } fmt.Println(instructions[curr]) } @@ -252,3 +303,22 @@ func sendNoneEvent(e chan termbox.Event) { } } } + +func toggleBreakpoint(pos int) { + for i := 0; i < len(breakpoints); i++ { + if breakpoints[i] == pos { + breakpoints = append(breakpoints[:i], breakpoints[i+1:]...) + return + } + } + breakpoints = append(breakpoints, pos) +} + +func isBreakpoint(pos int) bool { + for i := 0; i < len(breakpoints); i++ { + if breakpoints[i] == pos { + return true + } + } + return false +} diff --git a/2016/day23/problem b/2016/day23/problem new file mode 100644 index 0000000..b42a03a --- /dev/null +++ b/2016/day23/problem @@ -0,0 +1,93 @@ +Advent of Code + +--- Day 23: Safe Cracking --- + + This is one of the top floors of the nicest tower in EBHQ. The Easter Bunny's private office is here, complete with + a safe hidden behind a painting, and who wouldn't hide a star in a safe behind a painting? + + The safe has a digital screen and keypad for code entry. A sticky note attached to the safe has a password hint on + it: "eggs". The painting is of a large rabbit coloring some eggs. You see 7. + + When you go to type the code, though, nothing appears on the display; instead, the keypad comes apart in your + hands, apparently having been smashed. Behind it is some kind of socket - one that matches a connector in your + prototype computer! You pull apart the smashed keypad and extract the logic circuit, plug it into your computer, + and plug your computer into the safe. + + Now, you just need to figure out what output the keypad would have sent to the safe. You extract the assembunny + code from the logic chip (your puzzle input). + + The code looks like it uses almost the same architecture and instruction set that the monorail computer used! You + should be able to use the same assembunny interpreter for this as you did there, but with one new instruction: + + tgl x toggles the instruction x away (pointing at instructions like jnz does: positive means forward; negative + means backward): + + • For one-argument instructions, inc becomes dec, and all other one-argument instructions become inc. + • For two-argument instructions, jnz becomes cpy, and all other two-instructions become jnz. + • The arguments of a toggled instruction are not affected. + • If an attempt is made to toggle an instruction outside the program, nothing happens. + • If toggling produces an invalid instruction (like cpy 1 2) and an attempt is later made to execute that + instruction, skip it instead. + • If tgl toggles itself (for example, if a is 0, tgl a would target itself and become inc a), the resulting + instruction is not executed until the next time it is reached. + + For example, given this program: + + cpy 2 a + tgl a + tgl a + tgl a + cpy 1 a + dec a + dec a + + • cpy 2 a initializes register a to 2. + • The first tgl a toggles an instruction a (2) away from it, which changes the third tgl a into inc a. + • The second tgl a also modifies an instruction 2 away from it, which changes the cpy 1 a into jnz 1 a. + • The fourth line, which is now inc a, increments a to 3. + • Finally, the fifth line, which is now jnz 1 a, jumps a (3) instructions ahead, skipping the dec a instructions. + + In this example, the final value in register a is 3. + + The rest of the electronics seem to place the keypad entry (the number of eggs, 7) in register a, run the code, and + then send the value left in register a to the safe. + + What value should be sent to the safe? + + Your puzzle answer was ________. + +--- Part Two --- + + The safe doesn't open, but it does make several angry noises to express its frustration. + + You're quite sure your logic is working correctly, so the only other thing is... you check the painting again. As + it turns out, colored eggs are still eggs. Now you count 12. + + As you run the program with this new input, the prototype computer begins to overheat. You wonder what's taking so + long, and whether the lack of any instruction more powerful than "add one" has anything to do with it. Don't + bunnies usually multiply? + + Anyway, what value should actually be sent to the safe? + + Your puzzle answer was ____________. + +References + + Visible links + . http://adventofcode.com/ + . http://adventofcode.com/2016/about + . http://adventofcode.com/2016/support + . http://adventofcode.com/2016/events + . http://adventofcode.com/2016/settings + . http://adventofcode.com/2016/auth/logout + . http://adventofcode.com/2016 + . http://adventofcode.com/2016 + . http://adventofcode.com/2016/leaderboard + . http://adventofcode.com/2016/stats + . http://adventofcode.com/2016/sponsors + . http://adventofcode.com/2016/sponsors + . http://adventofcode.com/2016/day/11 + . http://adventofcode.com/2016/day/12 + . http://adventofcode.com/2016/day/12 + . http://adventofcode.com/2016 + . http://adventofcode.com/2016/day/23/input diff --git a/2016/day23/testinput b/2016/day23/testinput deleted file mode 100644 index bcabc2c..0000000 --- a/2016/day23/testinput +++ /dev/null @@ -1,7 +0,0 @@ -cpy 2 a -tgl a -tgl a -tgl a -cpy 1 a -dec a -dec a