2018 Day 16 Complete
This commit is contained in:
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
|
||||
}
|
||||
Reference in New Issue
Block a user