Advent of Code 2016 Complete

This commit is contained in:
2016-12-28 08:48:23 -06:00
parent a01a65364c
commit a0c467fd41
8 changed files with 1144 additions and 519 deletions

30
2016/day25/input Normal file
View 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
View 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
View 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