2018 Day 21 Complete

This commit is contained in:
Brian Buller 2018-12-21 07:04:10 -06:00
parent 032308f704
commit 1509573604
3 changed files with 342 additions and 0 deletions

226
2018/day21/day21.go Normal file
View File

@ -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
}

32
2018/day21/input Normal file
View File

@ -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

84
2018/day21/problem Normal file
View File

@ -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