2018 Day 16 Complete

This commit is contained in:
Brian Buller 2018-12-16 01:56:33 +00:00
parent e60c0a3f8d
commit 943079f64f
5 changed files with 4524 additions and 0 deletions

Binary file not shown.

270
2018/day16/day16.go Normal file
View File

@ -0,0 +1,270 @@
package main
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"strconv"
"strings"
)
func main() {
input := stdinToStringSlice()
pt2Idx := part1(input)
part2(input[pt2Idx:])
}
var probs map[string]int
func part1(input []string) int {
probs = make(map[string]int)
var messySamples int
var ret int
for i := 0; i < len(input); i += 4 {
if !strings.HasPrefix(input[i], "Before: ") {
// We're done with the part 1 input
ret = i
break
}
aft := NewState()
aft.loadState(input[i+2])
if cmd, err := aft.parseCommand(input[i+1]); err == nil {
origCd := cmd[0]
var numMatches int
for j := 0; j < 16; j++ {
bef := NewState()
bef.loadState(input[i])
cmd[0] = j
bef.run(cmd)
if bef.registerString() == aft.registerString() {
numMatches++
key := fmt.Sprintf("%d:%d", origCd, j)
probs[key]++
}
}
if numMatches > 2 {
messySamples++
}
}
}
fmt.Println("= Part 1 =")
fmt.Println(messySamples)
return ret + 2
}
var opMap [16]int
func part2(input []string) {
for i := 0; i < 16; i++ {
opMap[i] = -1
}
fmt.Println("= Part 2 =")
m1, m2 := -1, -1
for {
m1, m2, probs = findOnlyChance(probs)
if m1 == -1 {
break
}
opMap[m1] = m2
}
vpc := NewState()
for i := range input {
if cmd, err := vpc.parseCommand(input[i]); err == nil {
cmd[0] = opMap[cmd[0]]
vpc.run(cmd)
}
}
fmt.Println(vpc.reg[0])
}
func findOnlyChance(of map[string]int) (int, int, map[string]int) {
m1, m2 := -1, -1
for i := 0; i < 16; i++ {
var num int
for k := range of {
codes := strings.Split(k, ":")
if Atoi(codes[0]) == i {
num++
if num > 1 {
m2 = -1
break
}
m2 = Atoi(codes[1])
}
}
if num == 1 {
m1 = i
break
}
if num > 1 {
continue
}
}
if m1 == -1 {
return -1, -1, of
}
// If we're here, we found something
// Remove other possibilities for m1: and :m2 and return
for k := range of {
a1 := strconv.Itoa(m1)
a2 := strconv.Itoa(m2)
if strings.HasPrefix(k, a1+":") ||
strings.HasSuffix(k, ":"+a2) {
delete(of, k)
}
}
return m1, m2, of
}
type State struct {
reg [4]int
OpCodes map[int]func(a, b, c int)
}
func NewState() *State {
s := &State{}
s.OpCodes = make(map[int]func(a, b, c int))
s.OpCodes[0] = s.addr
s.OpCodes[1] = s.addi
s.OpCodes[2] = s.mulr
s.OpCodes[3] = s.muli
s.OpCodes[4] = s.banr
s.OpCodes[5] = s.bani
s.OpCodes[6] = s.borr
s.OpCodes[7] = s.bori
s.OpCodes[8] = s.setr
s.OpCodes[9] = s.seti
s.OpCodes[10] = s.gtir
s.OpCodes[11] = s.gtri
s.OpCodes[12] = s.gtrr
s.OpCodes[13] = s.eqir
s.OpCodes[14] = s.eqri
s.OpCodes[15] = s.eqrr
return s
}
func (s *State) registerString() string {
return fmt.Sprint(s.reg)
}
func (s *State) loadState(inp string) {
s.reg = [4]int{0, 0, 0, 0}
inp = strings.Trim(inp, "ABeftor: []")
pts := strings.Split(inp, ",")
for i := range pts {
s.reg[i] = Atoi(strings.TrimSpace(pts[i]))
}
}
func (s *State) parseCommand(inp string) ([]int, error) {
var ret []int
pts := strings.Split(inp, " ")
for i := range pts {
ret = append(ret, Atoi(pts[i]))
}
if len(ret) != 4 {
return ret, errors.New("Invalid Command: " + inp)
}
return ret, nil
}
func (s *State) run(cmd []int) error {
if fn, ok := s.OpCodes[cmd[0]]; !ok {
return errors.New(fmt.Sprintf("Invalid OpCode: %d", cmd[0]))
} else {
fn(cmd[1], cmd[2], cmd[3])
}
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 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
}

4064
2018/day16/input Normal file

File diff suppressed because it is too large Load Diff

187
2018/day16/problem Normal file
View File

@ -0,0 +1,187 @@
Advent of Code
--- Day 16: Chronal Classification ---
As you see the Elves defend their hot chocolate
successfully, you go back to falling through time. This is
going to become a problem.
If you're ever going to return to your own time, you need
to understand how this device on your wrist works. You
have a little while before you reach your next
destination, and with a bit of trial and error, you manage
to pull up a programming manual on the device's tiny
screen.
According to the manual, the device has four registers
(numbered 0 through 3) that can be manipulated by
instructions containing one of 16 opcodes. The registers
start with the value 0.
Every instruction consists of four values: an opcode, two
inputs (named A and B), and an output (named C), in that
order. The opcode specifies the behavior of the
instruction and how the inputs are interpreted. The
output, C, is always treated as a register.
In the opcode descriptions below, if something says "value
A", it means to take the number given as A literally.
(This is also called an "immediate" value.) If something
says "register A", it means to use the number given as A
to read from (or write to) the register with that number.
So, if the opcode addi adds register A and value B,
storing the result in register C, and the instruction addi
0 7 3 is encountered, it would add 7 to the value
contained by register 0 and store the sum in register 3,
never modifying registers 0, 1, or 2 in the process.
Many opcodes are similar except for how they interpret
their arguments. The opcodes fall into seven general
categories:
Addition:
* addr (add register) stores into register C the result
of adding register A and register B.
* addi (add immediate) stores into register C the result
of adding register A and value B.
Multiplication:
* mulr (multiply register) stores into register C the
result of multiplying register A and register B.
* muli (multiply immediate) stores into register C the
result of multiplying register A and value B.
Bitwise AND:
* banr (bitwise AND register) stores into register C the
result of the bitwise AND of register A and register
B.
* bani (bitwise AND immediate) stores into register C
the result of the bitwise AND of register A and value
B.
Bitwise OR:
* borr (bitwise OR register) stores into register C the
result of the bitwise OR of register A and register B.
* bori (bitwise OR immediate) stores into register C the
result of the bitwise OR of register A and value B.
Assignment:
* setr (set register) copies the contents of register A
into register C. (Input B is ignored.)
* seti (set immediate) stores value A into register C.
(Input B is ignored.)
Greater-than testing:
* gtir (greater-than immediate/register) sets register C
to 1 if value A is greater than register B. Otherwise,
register C is set to 0.
* gtri (greater-than register/immediate) sets register C
to 1 if register A is greater than value B. Otherwise,
register C is set to 0.
* gtrr (greater-than register/register) sets register C
to 1 if register A is greater than register B.
Otherwise, register C is set to 0.
Equality testing:
* eqir (equal immediate/register) sets register C to 1
if value A is equal to register B. Otherwise, register
C is set to 0.
* eqri (equal register/immediate) sets register C to 1
if register A is equal to value B. Otherwise, register
C is set to 0.
* eqrr (equal register/register) sets register C to 1 if
register A is equal to register B. Otherwise, register
C is set to 0.
Unfortunately, while the manual gives the name of each
opcode, it doesn't seem to indicate the number. However,
you can monitor the CPU to see the contents of the
registers before and after instructions are executed to
try to work them out. Each opcode has a number from 0
through 15, but the manual doesn't say which is which. For
example, suppose you capture the following sample:
Before: [3, 2, 1, 1]
9 2 1 2
After: [3, 2, 2, 1]
This sample shows the effect of the instruction 9 2 1 2 on
the registers. Before the instruction is executed,
register 0 has value 3, register 1 has value 2, and
registers 2 and 3 have value 1. After the instruction is
executed, register 2's value becomes 2.
The instruction itself, 9 2 1 2, means that opcode 9 was
executed with A=2, B=1, and C=2. Opcode 9 could be any of
the 16 opcodes listed above, but only three of them behave
in a way that would cause the result shown in the sample:
* Opcode 9 could be mulr: register 2 (which has a value
of 1) times register 1 (which has a value of 2)
produces 2, which matches the value stored in the
output register, register 2.
* Opcode 9 could be addi: register 2 (which has a value
of 1) plus value 1 produces 2, which matches the value
stored in the output register, register 2.
* Opcode 9 could be seti: value 2 matches the value
stored in the output register, register 2; the number
given for B is irrelevant.
None of the other opcodes produce the result captured in
the sample. Because of this, the sample above behaves like
three opcodes.
You collect many of these samples (the first section of
your puzzle input). The manual also includes a small test
program (the second section of your puzzle input) - you
can ignore it for now.
Ignoring the opcode numbers, how many samples in your
puzzle input behave like three or more opcodes?
Your puzzle answer was 547.
--- Part Two ---
Using the samples you collected, work out the number of
each opcode and execute the test program (the second
section of your puzzle input).
What value is contained in register 0 after executing the
test program?
Your puzzle answer was 582.
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://en.wikipedia.org/wiki/Hardware_register
. https://en.wikipedia.org/wiki/Instruction_set_architecture#Instructions
. https://en.wikipedia.org/wiki/Bitwise_AND
. https://en.wikipedia.org/wiki/Bitwise_OR
. https://adventofcode.com/2018
. https://adventofcode.com/2018/day/16/input

3
2018/day16/testinput Normal file
View File

@ -0,0 +1,3 @@
Before: [3, 2, 1, 1]
9 2 1 2
After: [3, 2, 2, 1]