2018 Day 16 Complete
This commit is contained in:
parent
e60c0a3f8d
commit
943079f64f
Binary file not shown.
270
2018/day16/day16.go
Normal file
270
2018/day16/day16.go
Normal 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
4064
2018/day16/input
Normal file
File diff suppressed because it is too large
Load Diff
187
2018/day16/problem
Normal file
187
2018/day16/problem
Normal 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
3
2018/day16/testinput
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Before: [3, 2, 1, 1]
|
||||||
|
9 2 1 2
|
||||||
|
After: [3, 2, 2, 1]
|
Loading…
Reference in New Issue
Block a user