From 1509573604c120bc2bb192d9f75694e0d86b8411 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 21 Dec 2018 07:04:10 -0600 Subject: [PATCH] 2018 Day 21 Complete --- 2018/day21/day21.go | 226 ++++++++++++++++++++++++++++++++++++++++++++ 2018/day21/input | 32 +++++++ 2018/day21/problem | 84 ++++++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 2018/day21/day21.go create mode 100644 2018/day21/input create mode 100644 2018/day21/problem diff --git a/2018/day21/day21.go b/2018/day21/day21.go new file mode 100644 index 0000000..5a84ad0 --- /dev/null +++ b/2018/day21/day21.go @@ -0,0 +1,226 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "log" + "os" + "strconv" + "strings" +) + +func main() { + input := stdinToStringSlice() + part1(input) +} + +func part1(input []string) { + vpc := NewState() + if strings.HasPrefix(input[0], "#ip") { + // Binding the ip to a register... + pts := strings.Split(input[0], " ") + vpc.ipReg = Atoi(pts[1]) + input = input[1:] + } + // vpc.reg[0] = 7967233 // Part 1 + loop := make(map[int]bool) + var prev int + for { + if vpc.ip >= len(input) { + break + } + inp := input[vpc.ip] + if op, cmd, err := vpc.parseCommand(inp); err == nil { + if vpc.ipReg > -1 { + vpc.reg[vpc.ipReg] = vpc.ip + } + vpc.run(op, cmd) + if vpc.ip == 28 { + if _, ok := loop[vpc.reg[3]]; ok { + fmt.Println(prev) + break + } + loop[vpc.reg[3]] = true + prev = vpc.reg[3] + } + vpc.ip = vpc.reg[vpc.ipReg] + } + vpc.ip++ + } + fmt.Println(vpc.string()) +} + +type State struct { + ip, ipReg int + reg [6]int + OpCodes map[string]func(a, b, c int) +} + +func NewState() *State { + s := &State{ + ip: 0, + ipReg: -1, + } + s.OpCodes = make(map[string]func(a, b, c int)) + s.OpCodes["addr"] = s.addr + s.OpCodes["addi"] = s.addi + s.OpCodes["mulr"] = s.mulr + s.OpCodes["muli"] = s.muli + s.OpCodes["banr"] = s.banr + s.OpCodes["bani"] = s.bani + s.OpCodes["borr"] = s.borr + s.OpCodes["bori"] = s.bori + s.OpCodes["setr"] = s.setr + s.OpCodes["seti"] = s.seti + s.OpCodes["gtir"] = s.gtir + s.OpCodes["gtri"] = s.gtri + s.OpCodes["gtrr"] = s.gtrr + s.OpCodes["eqir"] = s.eqir + s.OpCodes["eqri"] = s.eqri + s.OpCodes["eqrr"] = s.eqrr + return s +} + +func (s *State) parseCommand(inp string) (string, []int, error) { + var retOp string + var retCmd []int + pts := strings.Split(inp, " ") + if len(pts) != 4 { + return retOp, retCmd, errors.New("Invalid Command") + } + retOp = pts[0] + for _, v := range pts[1:] { + retCmd = append(retCmd, Atoi(v)) + } + return retOp, retCmd, nil +} + +func (s *State) string() string { + ret := fmt.Sprintf("ip=%d ", s.ip) + for i := 0; i < len(s.reg); i++ { + if i == s.ipReg { + ret = fmt.Sprintf("%s <%d> ", ret, s.reg[i]) + } else { + ret = fmt.Sprintf("%s %d ", ret, s.reg[i]) + } + } + return ret +} + +func (s *State) run(op string, cmd []int) error { + if fn, ok := s.OpCodes[op]; !ok { + return errors.New(fmt.Sprintf("Invalid OpCode: %d", cmd[0])) + } else { + fn(cmd[0], cmd[1], cmd[2]) + } + return nil +} + +func (s *State) addr(r1, r2, r3 int) { + s.reg[r3] = s.reg[r1] + s.reg[r2] +} + +func (s *State) addi(r1, v2, r3 int) { + s.reg[r3] = s.reg[r1] + v2 +} + +func (s *State) mulr(r1, r2, r3 int) { + s.reg[r3] = s.reg[r1] * s.reg[r2] +} + +func (s *State) muli(r1, v2, r3 int) { + s.reg[r3] = s.reg[r1] * v2 +} + +func (s *State) banr(r1, r2, r3 int) { + s.reg[r3] = s.reg[r1] & s.reg[r2] +} + +func (s *State) bani(r1, v2, r3 int) { + s.reg[r3] = s.reg[r1] & v2 +} + +func (s *State) borr(r1, r2, r3 int) { + s.reg[r3] = s.reg[r1] | s.reg[r2] +} + +func (s *State) bori(r1, v2, r3 int) { + s.reg[r3] = s.reg[r1] | v2 +} + +func (s *State) setr(r1, r2, r3 int) { + s.reg[r3] = s.reg[r1] +} + +func (s *State) seti(v1, v2, r3 int) { + s.reg[r3] = v1 +} + +func (s *State) gtir(v1, r2, r3 int) { + s.reg[r3] = boolToInt(v1 > s.reg[r2]) +} + +func (s *State) gtri(r1, v2, r3 int) { + s.reg[r3] = boolToInt(s.reg[r1] > v2) +} + +func (s *State) gtrr(r1, r2, r3 int) { + s.reg[r3] = boolToInt(s.reg[r1] > s.reg[r2]) +} + +func (s *State) eqir(v1, r2, r3 int) { + s.reg[r3] = boolToInt(v1 == s.reg[r2]) +} + +func (s *State) eqri(r1, v2, r3 int) { + s.reg[r3] = boolToInt(s.reg[r1] == v2) +} + +func (s *State) eqrr(r1, r2, r3 int) { + s.reg[r3] = boolToInt(s.reg[r1] == s.reg[r2]) +} + +func boolToInt(v bool) int { + if v { + return 1 + } + return 0 +} + +func getDivisors(n int) []int { + ret := []int{n} + for i := 1; i < (n / 2); i++ { + if n%i == 0 { + ret = append(ret, i) + + } + } + return ret +} + +func sum(vals []int) int { + var ret int + for _, v := range vals { + ret += v + } + return ret +} + +func stdinToStringSlice() []string { + var input []string + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + input = append(input, scanner.Text()) + } + return input +} + +func Atoi(i string) int { + var ret int + var err error + if ret, err = strconv.Atoi(i); err != nil { + log.Fatal("Invalid Atoi: " + i) + } + return ret +} diff --git a/2018/day21/input b/2018/day21/input new file mode 100644 index 0000000..d5c4ba4 --- /dev/null +++ b/2018/day21/input @@ -0,0 +1,32 @@ +#ip 2 +seti 123 0 3 +bani 3 456 3 +eqri 3 72 3 +addr 3 2 2 +seti 0 0 2 +seti 0 5 3 +bori 3 65536 1 +seti 10373714 2 3 +bani 1 255 5 +addr 3 5 3 +bani 3 16777215 3 +muli 3 65899 3 +bani 3 16777215 3 +gtir 256 1 5 +addr 5 2 2 +addi 2 1 2 +seti 27 7 2 +seti 0 3 5 +addi 5 1 4 +muli 4 256 4 +gtrr 4 1 4 +addr 4 2 2 +addi 2 1 2 +seti 25 4 2 +addi 5 1 5 +seti 17 0 2 +setr 5 2 1 +seti 7 4 2 +eqrr 3 0 5 +addr 5 2 2 +seti 5 7 2 diff --git a/2018/day21/problem b/2018/day21/problem new file mode 100644 index 0000000..2d07ab2 --- /dev/null +++ b/2018/day21/problem @@ -0,0 +1,84 @@ +Advent of Code + +--- Day 21: Chronal Conversion --- + + You should have been watching where you were going, because as you wander the + new North Pole base, you trip and fall into a very deep hole! + + Just kidding. You're falling through time again. + + If you keep up your current pace, you should have resolved all of the temporal + anomalies by the next time the device activates. Since you have very little + interest in browsing history in 500-year increments for the rest of your life, + you need to find a way to get back to your present time. + + After a little research, you discover two important facts about the behavior + of the device: + + First, you discover that the device is hard-wired to always send you back in + time in 500-year increments. Changing this is probably not feasible. + + Second, you discover the activation system (your puzzle input) for the time + travel module. Currently, it appears to run forever without halting. + + If you can cause the activation system to halt at a specific moment, maybe you + can make the device send you so far back in time that you cause an integer + underflow in time itself and wrap around back to your current time! + + The device executes the program as specified in manual section one and manual + section two. + + Your goal is to figure out how the program works and cause it to halt. You can + only control register 0; every other register begins at 0 as usual. + + Because time travel is a dangerous activity, the activation system begins with + a few instructions which verify that bitwise AND (via bani) does a numeric + operation and not an operation as if the inputs were interpreted as strings. + If the test fails, it enters an infinite loop re-running the test instead of + allowing the program to execute normally. If the test passes, the program + continues, and assumes that all other bitwise operations (banr, bori, and + borr) also interpret their inputs as numbers. (Clearly, the Elves who wrote + this system were worried that someone might introduce a bug while trying to + emulate this system with a scripting language.) + + What is the lowest non-negative integer value for register 0 that causes the + program to halt after executing the fewest instructions? (Executing the same + instruction multiple times counts as multiple instructions executed.) + + Your puzzle answer was 7967233. + +--- Part Two --- + + In order to determine the timing window for your underflow exploit, you also + need an upper bound: + + What is the lowest non-negative integer value for register 0 that causes the + program to halt after executing the most instructions? (The program must + actually halt; running forever does not count as halting.) + + Your puzzle answer was 16477902. + + Both parts of this puzzle are complete! They provide two gold stars: ** + +References + + Visible links + . https://adventofcode.com/ + . https://adventofcode.com/2018/about + . https://adventofcode.com/2018/events + . https://adventofcode.com/2018/settings + . https://adventofcode.com/2018/auth/logout + . Advent of Code Supporter + https://adventofcode.com/2018/support + . https://adventofcode.com/2018 + . https://adventofcode.com/2018 + . https://adventofcode.com/2018/support + . https://adventofcode.com/2018/sponsors + . https://adventofcode.com/2018/leaderboard + . https://adventofcode.com/2018/stats + . https://adventofcode.com/2018/sponsors + . https://cwe.mitre.org/data/definitions/191.html + . https://adventofcode.com/2018/day/16 + . https://adventofcode.com/2018/day/19 + . https://adventofcode.com/2018 + . https://adventofcode.com/2018/day/21/input