Advent of Code 2016 Complete
This commit is contained in:
30
2016/day25/input
Normal file
30
2016/day25/input
Normal file
@@ -0,0 +1,30 @@
|
||||
cpy a d
|
||||
cpy 7 c
|
||||
cpy 365 b
|
||||
inc d
|
||||
dec b
|
||||
jnz b -2
|
||||
dec c
|
||||
jnz c -5
|
||||
cpy d a
|
||||
jnz 0 0
|
||||
cpy a b
|
||||
cpy 0 a
|
||||
cpy 2 c
|
||||
jnz b 2
|
||||
jnz 1 6
|
||||
dec b
|
||||
dec c
|
||||
jnz c -4
|
||||
inc a
|
||||
jnz 1 -7
|
||||
cpy 2 b
|
||||
jnz c 2
|
||||
jnz 1 4
|
||||
dec b
|
||||
dec c
|
||||
jnz 1 -4
|
||||
jnz 0 0
|
||||
out b
|
||||
jnz a -19
|
||||
jnz 1 -21
|
505
2016/day25/main.go
Normal file
505
2016/day25/main.go
Normal file
@@ -0,0 +1,505 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
termbox "github.com/nsf/termbox-go"
|
||||
|
||||
"../../"
|
||||
)
|
||||
|
||||
var regs = map[string]int{
|
||||
"a": 0,
|
||||
"b": 0,
|
||||
"c": 0,
|
||||
"d": 0,
|
||||
}
|
||||
|
||||
var instructions, lastInst []string
|
||||
var curr, cursor int
|
||||
var done, debug, pause, step, skip bool
|
||||
var breakpoints []int
|
||||
var eventChan chan termbox.Event
|
||||
var outBuff string
|
||||
|
||||
// Available arguments:
|
||||
// -d Debug Mode
|
||||
// -p Pause on start
|
||||
// -25 Run day 25 simulation
|
||||
func main() {
|
||||
var inpFn string
|
||||
if inpFn = aoc.GetArgNumber(1); inpFn == "" {
|
||||
done = true
|
||||
}
|
||||
if inpFn != "" {
|
||||
instructions = aoc.FileToStringSlice(inpFn)
|
||||
}
|
||||
|
||||
if aoc.ArgIsSet("-d") {
|
||||
debug = true
|
||||
}
|
||||
if aoc.ArgIsSet("-p") {
|
||||
pause = true
|
||||
}
|
||||
if aoc.ArgIsSet("-25") {
|
||||
// If running the day 25 simulation, ignore debug and pause flags
|
||||
fmt.Println("Running Day 25 simulation, disabling debug & pause")
|
||||
debug = false
|
||||
pause = false
|
||||
}
|
||||
if debug {
|
||||
err := termbox.Init()
|
||||
//tWidth, tHeight := termbox.Size()
|
||||
if err != nil {
|
||||
fmt.Println("Error initializing termbox")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer termbox.Close()
|
||||
eventChan = make(chan termbox.Event)
|
||||
go readUserInput(eventChan)
|
||||
go sendNoneEvent(eventChan)
|
||||
}
|
||||
if aoc.ArgIsSet("-25") {
|
||||
var day25Solved bool
|
||||
regAStart := regs["a"]
|
||||
regBStart := regs["b"]
|
||||
regCStart := regs["c"]
|
||||
regDStart := regs["d"]
|
||||
for !day25Solved {
|
||||
regs["a"] = regAStart
|
||||
regs["b"] = regBStart
|
||||
regs["c"] = regCStart
|
||||
regs["d"] = regDStart
|
||||
ProcInstructions()
|
||||
day25Solved = true
|
||||
fmt.Println(regAStart, ":", outBuff)
|
||||
if outBuff != "0101010101" {
|
||||
day25Solved = false
|
||||
regAStart++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ProcInstructions()
|
||||
PrintState()
|
||||
}
|
||||
//fmt.Println("Press any key to exit")
|
||||
//termbox.PollEvent()
|
||||
}
|
||||
|
||||
func ProcInstructions() {
|
||||
locRegs := make(map[string]int)
|
||||
for k, v := range regs {
|
||||
locRegs[k] = v
|
||||
}
|
||||
curr = 0
|
||||
outBuff = ""
|
||||
var ins []string
|
||||
for curr < len(instructions) || done {
|
||||
isBreak := isBreakpoint(curr)
|
||||
if debug {
|
||||
lastInst = ins
|
||||
}
|
||||
ins = strings.Fields(instructions[curr])
|
||||
if len(ins) == 0 {
|
||||
break
|
||||
}
|
||||
if isMultOp(curr) {
|
||||
curr = doMultOp(curr)
|
||||
skip = true
|
||||
}
|
||||
if debug {
|
||||
if isBreak {
|
||||
pause = true
|
||||
step = false
|
||||
}
|
||||
for pause && !step && !done {
|
||||
// print state and wait for user to step
|
||||
PrintState()
|
||||
PrintInstructionState()
|
||||
PrintDebugHelp()
|
||||
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.Ch == 'u':
|
||||
updateRegister()
|
||||
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 "out":
|
||||
v, ok := regs[ins[1]]
|
||||
if !ok {
|
||||
outBuff += ins[1]
|
||||
} else {
|
||||
outBuff += aoc.Itoa(v)
|
||||
}
|
||||
if aoc.ArgIsSet("-25") && len(outBuff) == 10 {
|
||||
// This should be long enough for our day 25 answer
|
||||
return
|
||||
}
|
||||
// If we're not debugging, just print it and reset the buffer
|
||||
if !debug && !aoc.ArgIsSet("-25") {
|
||||
fmt.Print(outBuff)
|
||||
outBuff = ""
|
||||
}
|
||||
case "jnz":
|
||||
// If we have a jnz c -2 it could be moving all of c into another register
|
||||
v, ok := regs[ins[1]]
|
||||
if !ok {
|
||||
v = aoc.Atoi(ins[1])
|
||||
}
|
||||
var p int
|
||||
if p, ok = regs[ins[2]]; !ok {
|
||||
p = aoc.Atoi(ins[2])
|
||||
}
|
||||
if v != 0 {
|
||||
// Subtract 1 from the jump because we incremented already
|
||||
curr += p - 1
|
||||
}
|
||||
case "mlt":
|
||||
// a three arg instruction: mlt a b c
|
||||
// take a * b, store in c
|
||||
var ok bool
|
||||
src1 := ins[1]
|
||||
src2 := ins[2]
|
||||
dst := ins[3]
|
||||
if _, ok := regs[dst]; !ok {
|
||||
// invalid destination
|
||||
continue
|
||||
}
|
||||
var src1I, src2I int
|
||||
if src1I, ok = regs[src1]; !ok {
|
||||
src1I = aoc.Atoi(src1)
|
||||
}
|
||||
if src2I, ok = regs[src2]; !ok {
|
||||
src2I = aoc.Atoi(src2)
|
||||
}
|
||||
regs[dst] = src1I * src2I
|
||||
case "cpy":
|
||||
src := ins[1]
|
||||
dst := ins[2]
|
||||
// check if dst is a register
|
||||
if _, ok := regs[dst]; !ok {
|
||||
// Nope, move along
|
||||
continue
|
||||
}
|
||||
// check if the src is a register
|
||||
if v, ok := regs[src]; ok {
|
||||
regs[dst] = v
|
||||
} else {
|
||||
// It's not, must be an int
|
||||
regs[dst] = aoc.Atoi(src)
|
||||
}
|
||||
case "inc":
|
||||
if _, ok := regs[ins[1]]; !ok {
|
||||
continue
|
||||
}
|
||||
regs[ins[1]] = regs[ins[1]] + 1
|
||||
case "dec":
|
||||
if _, ok := regs[ins[1]]; !ok {
|
||||
continue
|
||||
}
|
||||
regs[ins[1]] = regs[ins[1]] - 1
|
||||
case "tgl": // tgl alters an instruction
|
||||
src := ins[1]
|
||||
var srcI int
|
||||
if v, ok := regs[src]; ok {
|
||||
srcI = v
|
||||
} else {
|
||||
srcI = aoc.Atoi(src)
|
||||
}
|
||||
srcI = curr + srcI
|
||||
if srcI < 0 || srcI > len(instructions)-1 {
|
||||
// Invalid instruction
|
||||
continue
|
||||
}
|
||||
altPts := strings.Fields(instructions[srcI-1])
|
||||
if len(altPts) == 2 { // one argument
|
||||
if altPts[0] == "inc" {
|
||||
altPts[0] = "dec"
|
||||
} else {
|
||||
altPts[0] = "inc"
|
||||
}
|
||||
} else { // two arguments
|
||||
if altPts[0] == "jnz" {
|
||||
altPts[0] = "cpy"
|
||||
} else {
|
||||
altPts[0] = "jnz"
|
||||
}
|
||||
}
|
||||
instructions[srcI-1] = strings.Join(altPts, " ")
|
||||
}
|
||||
if debug {
|
||||
PrintState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fancy State Printing
|
||||
func PrintState() {
|
||||
fmt.Println(aoc.ClearScreen)
|
||||
PrintRegs()
|
||||
}
|
||||
|
||||
func PrintRegs() {
|
||||
datLine := fmt.Sprint("\u2502 a:", regs["a"], " b:", regs["b"], " c:", regs["c"], " d:", regs["d"], " \u2502")
|
||||
fmt.Println("\u250C" + strings.Repeat("\u2500", len(datLine)-6) + "\u2510")
|
||||
fmt.Println(datLine)
|
||||
fmt.Println("\u2514" + strings.Repeat("\u2500", len(datLine)-6) + "\u2518")
|
||||
}
|
||||
|
||||
func PrintInstructionState() {
|
||||
optim := color.New(color.FgGreen)
|
||||
for pi := range instructions {
|
||||
if pi == curr {
|
||||
fmt.Print(">")
|
||||
} else {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
if isBreakpoint(pi) {
|
||||
fmt.Print("B")
|
||||
} else {
|
||||
fmt.Print(" ")
|
||||
}
|
||||
if cursor == pi {
|
||||
cursor := color.New(color.FgBlack).Add(color.BgWhite)
|
||||
if isMultOp(pi) {
|
||||
cursor.Println("+ " + instructions[pi] + " == optimized")
|
||||
} else if mo, _ := isInMultOp(pi); mo {
|
||||
cursor.Println("| " + instructions[pi])
|
||||
} else {
|
||||
cursor.Println(instructions[pi])
|
||||
}
|
||||
} else {
|
||||
if isMultOp(pi) {
|
||||
optim.Println("+ " + instructions[pi] + " == optimized")
|
||||
} else if mo, _ := isInMultOp(pi); mo {
|
||||
optim.Println("| " + instructions[pi])
|
||||
} else {
|
||||
fmt.Println(instructions[pi])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PrintDebugHelp() {
|
||||
fmt.Println("(s): step | (space): pause/unpause | (b): toggle breakpoint")
|
||||
fmt.Println("(u): update register to value | (q): quit")
|
||||
}
|
||||
|
||||
func readUserInput(e chan termbox.Event) {
|
||||
for {
|
||||
e <- termbox.PollEvent()
|
||||
}
|
||||
}
|
||||
|
||||
func sendNoneEvent(e chan termbox.Event) {
|
||||
for {
|
||||
time.Sleep(time.Second / 32)
|
||||
if !pause {
|
||||
e <- termbox.Event{Type: termbox.EventNone}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isInMultOp returns true and the pc for the
|
||||
// start of the multiplication operation if pos is
|
||||
// located within it
|
||||
func isInMultOp(pos int) (bool, int) {
|
||||
// We need to check instructions[pos +- 5] to see if any
|
||||
// are a multiplication op and return the pos for the (first) one
|
||||
// that is
|
||||
if isMultOp(pos) {
|
||||
return true, pos
|
||||
}
|
||||
for i := 1; i < 6; i++ {
|
||||
if isMultOp(pos - i) {
|
||||
return true, (pos - i)
|
||||
}
|
||||
}
|
||||
return false, pos
|
||||
}
|
||||
|
||||
// isMultOpStart return whether pos is the start of
|
||||
// what can be optimized as multiplication
|
||||
/*
|
||||
> cpy b c
|
||||
inc a
|
||||
dec c
|
||||
jnz c -2
|
||||
dec d
|
||||
jnz d -5
|
||||
== add (b * d) to a
|
||||
set c & d to 0
|
||||
curr += 5
|
||||
*/
|
||||
func isMultOp(pos int) bool {
|
||||
if pos < 0 || pos > len(instructions)-1 {
|
||||
return false
|
||||
}
|
||||
ins := strings.Fields(instructions[pos])
|
||||
if len(ins) < 3 {
|
||||
return false
|
||||
}
|
||||
if ins[0] == "cpy" {
|
||||
if len(instructions) >= pos+6 {
|
||||
ins1 := strings.Fields(instructions[pos+1])
|
||||
ins2 := strings.Fields(instructions[pos+2])
|
||||
ins3 := strings.Fields(instructions[pos+3])
|
||||
ins4 := strings.Fields(instructions[pos+4])
|
||||
ins5 := strings.Fields(instructions[pos+5])
|
||||
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
|
||||
}
|
||||
return allGood
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// doMultOp performs a multiplcation operation and returns the new pc
|
||||
func doMultOp(pos int) int {
|
||||
isOp, pos := isInMultOp(pos)
|
||||
if !isOp {
|
||||
// No optimization to do
|
||||
return pos
|
||||
}
|
||||
ins := strings.Fields(instructions[pos])
|
||||
ins1 := strings.Fields(instructions[pos+1])
|
||||
ins4 := strings.Fields(instructions[pos+4])
|
||||
// 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]
|
||||
regs[dst] += (regs[src1] * regs[src2])
|
||||
regs[ins[2]] = 0
|
||||
regs[ins4[1]] = 0
|
||||
pos += 6
|
||||
return pos
|
||||
}
|
||||
|
||||
func toggleBreakpoint(pos int) {
|
||||
_, pos = isInMultOp(pos)
|
||||
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 {
|
||||
_, pos = isInMultOp(pos)
|
||||
for i := 0; i < len(breakpoints); i++ {
|
||||
if breakpoints[i] == pos {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func updateRegister() {
|
||||
var updReg string
|
||||
fmt.Println("Update which register? (a,b,c,d)")
|
||||
ev := <-eventChan
|
||||
if ev.Type == termbox.EventKey {
|
||||
switch {
|
||||
case ev.Ch == 'a':
|
||||
updReg = "a"
|
||||
case ev.Ch == 'b':
|
||||
updReg = "b"
|
||||
case ev.Ch == 'c':
|
||||
updReg = "c"
|
||||
case ev.Ch == 'd':
|
||||
updReg = "d"
|
||||
default:
|
||||
fmt.Println("Invalid register (" + string(ev.Ch) + ")")
|
||||
fmt.Println("Press any key to continue")
|
||||
ev = <-eventChan
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("Enter new value (must be integer, end with enter)")
|
||||
var newVal string
|
||||
for ev.Key != termbox.KeyEnter {
|
||||
ev = <-eventChan
|
||||
if ev.Ch >= '0' && ev.Ch <= '9' {
|
||||
newVal += string(ev.Ch)
|
||||
fmt.Print(string(ev.Ch))
|
||||
}
|
||||
}
|
||||
fmt.Println("Setting Register (" + updReg + ") to " + newVal)
|
||||
var v int
|
||||
var e error
|
||||
if v, e = strconv.Atoi(newVal); e != nil {
|
||||
fmt.Println()
|
||||
fmt.Println("Error parsing integer")
|
||||
fmt.Println(e)
|
||||
fmt.Println("Press any key to continue")
|
||||
ev = <-eventChan
|
||||
return
|
||||
}
|
||||
regs[updReg] = v
|
||||
}
|
74
2016/day25/problem
Normal file
74
2016/day25/problem
Normal file
@@ -0,0 +1,74 @@
|
||||
Advent of Code
|
||||
|
||||
--- Day 25: Clock Signal ---
|
||||
|
||||
You open the door and find yourself on the roof. The city sprawls away from you for miles and miles.
|
||||
|
||||
There's not much time now - it's already Christmas, but you're nowhere near the North Pole, much too far to deliver
|
||||
these stars to the sleigh in time.
|
||||
|
||||
However, maybe the huge antenna up here can offer a solution. After all, the sleigh doesn't need the stars, exactly; it
|
||||
needs the timing data they provide, and you happen to have a massive signal generator right here.
|
||||
|
||||
You connect the stars you have to your prototype computer, connect that to the antenna, and begin the transmission.
|
||||
|
||||
Nothing happens.
|
||||
|
||||
You call the service number printed on the side of the antenna and quickly explain the situation. "I'm not sure what
|
||||
kind of equipment you have connected over there," he says, "but you need a clock signal." You try to explain that this
|
||||
is a signal for a clock.
|
||||
|
||||
"No, no, a clock signal - timing information so the antenna computer knows how to read the data you're sending it. An
|
||||
endless, alternating pattern of 0, 1, 0, 1, 0, 1, 0, 1, 0, 1...." He trails off.
|
||||
|
||||
You ask if the antenna can handle a clock signal at the frequency you would need to use for the data from the stars.
|
||||
"There's no way it can! The only antenna we've installed capable of that is on top of a top-secret Easter Bunny
|
||||
installation, and you're definitely not-" You hang up the phone.
|
||||
|
||||
You've extracted the antenna's clock signal generation assembunny code (your puzzle input); it looks mostly compatible
|
||||
with code you worked on just recently.
|
||||
|
||||
This antenna code, being a signal generator, uses one extra instruction:
|
||||
|
||||
• out x transmits x (either an integer or the value of a register) as the next value for the clock signal.
|
||||
|
||||
The code takes a value (via register a) that describes the signal to generate, but you're not sure how it's used. You'll
|
||||
have to find the input to produce the right signal through experimentation.
|
||||
|
||||
What is the lowest positive integer that can be used to initialize register a and cause the code to output a clock
|
||||
signal of 0, 1, 0, 1... repeating forever?
|
||||
|
||||
Your puzzle answer was ____.
|
||||
|
||||
--- Part Two ---
|
||||
|
||||
The antenna is ready. Now, all you need is the fifty stars required to generate the signal for the sleigh, but you don't
|
||||
have enough.
|
||||
|
||||
You look toward the sky in desperation... suddenly noticing that a lone star has been installed at the top of the
|
||||
antenna! Only 49 more to go.
|
||||
|
||||
If you like, you can [ [Retransmit the Signal] ] .
|
||||
|
||||
Both parts of this puzzle are complete! They provide two gold stars: **
|
||||
|
||||
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
|
||||
. https://en.wikipedia.org/wiki/Clock_signal
|
||||
. http://adventofcode.com/2016/day/12
|
||||
. http://adventofcode.com/2016/day/23
|
||||
. http://adventofcode.com/2016
|
||||
. http://adventofcode.com/2016/day/25/input
|
Reference in New Issue
Block a user