2018 Day 21 Complete
This commit is contained in:
parent
032308f704
commit
1509573604
226
2018/day21/day21.go
Normal file
226
2018/day21/day21.go
Normal 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
32
2018/day21/input
Normal 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
84
2018/day21/problem
Normal 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
|
Loading…
Reference in New Issue
Block a user