193 lines
3.5 KiB
Go
193 lines
3.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
inp := h.StdinToStringSlice()
|
||
|
part1(inp)
|
||
|
fmt.Println()
|
||
|
part2(inp)
|
||
|
}
|
||
|
|
||
|
func part1(inp []string) {
|
||
|
fmt.Println("# Part 1")
|
||
|
dev, gates := parseInput1(inp)
|
||
|
// Perform all logic
|
||
|
gateDone := make(map[int]bool)
|
||
|
for len(gateDone) != len(gates)-1 {
|
||
|
for i := range gates {
|
||
|
if _, ok := gateDone[i]; !ok {
|
||
|
pts := strings.Split(gates[i], " ")
|
||
|
var w1, w2, ok bool
|
||
|
if w1, ok = dev[pts[0]]; ok {
|
||
|
if w2, ok = dev[pts[2]]; ok {
|
||
|
switch pts[1] {
|
||
|
case "AND":
|
||
|
dev[pts[4]] = w1 && w2
|
||
|
case "OR":
|
||
|
dev[pts[4]] = w1 || w2
|
||
|
case "XOR":
|
||
|
dev[pts[4]] = w1 != w2
|
||
|
}
|
||
|
gateDone[i] = true
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fmt.Println(findValueOf(dev, "z"))
|
||
|
}
|
||
|
|
||
|
// Not fully working yet... I solved this part manually.
|
||
|
func part2(inp []string) {
|
||
|
fmt.Println("# Part 2")
|
||
|
gates := parseInput2(inp)[1]
|
||
|
|
||
|
var swapped []string
|
||
|
var c0 string
|
||
|
|
||
|
for i := 0; i < 45; i++ {
|
||
|
n := fmt.Sprintf("%02d", i)
|
||
|
var m1, n1, r1, z1, c1 string
|
||
|
|
||
|
m1 = find("x"+n, "y"+n, "XOR", gates)
|
||
|
n1 = find("x"+n, "y"+n, "AND", gates)
|
||
|
|
||
|
if c0 != "" {
|
||
|
r1 = find(c0, m1, "AND", gates)
|
||
|
if r1 == "" {
|
||
|
m1, n1 = n1, m1
|
||
|
swapped = append(swapped, m1, n1)
|
||
|
r1 = find(c0, m1, "AND", gates)
|
||
|
}
|
||
|
|
||
|
z1 = find(c0, m1, "XOR", gates)
|
||
|
|
||
|
if strings.HasPrefix(m1, "z") {
|
||
|
m1, z1 = z1, m1
|
||
|
swapped = append(swapped, m1, z1)
|
||
|
}
|
||
|
|
||
|
if strings.HasPrefix(n1, "z") {
|
||
|
n1, z1 = z1, n1
|
||
|
swapped = append(swapped, n1, z1)
|
||
|
}
|
||
|
|
||
|
if strings.HasPrefix(r1, "z") {
|
||
|
r1, z1 = z1, r1
|
||
|
swapped = append(swapped, r1, z1)
|
||
|
}
|
||
|
|
||
|
c1 = find(r1, n1, "OR", gates)
|
||
|
}
|
||
|
|
||
|
if strings.HasPrefix(c1, "z") && c1 != "z45" {
|
||
|
c1, z1 = z1, c1
|
||
|
swapped = append(swapped, c1, z1)
|
||
|
}
|
||
|
|
||
|
if c0 == "" {
|
||
|
c0 = n1
|
||
|
} else {
|
||
|
c0 = c1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sort and join swapped wires
|
||
|
sort.Strings(swapped)
|
||
|
fmt.Println(strings.Join(swapped, ","))
|
||
|
}
|
||
|
|
||
|
func parseInput1(inp []string) (map[string]bool, []string) {
|
||
|
dev := make(map[string]bool)
|
||
|
var gates []string
|
||
|
var inGates bool
|
||
|
for i := range inp {
|
||
|
if len(inp[i]) == 0 {
|
||
|
inGates = true
|
||
|
}
|
||
|
if !inGates {
|
||
|
if inp[i][3] == ':' {
|
||
|
wire := inp[i][:3]
|
||
|
v := inp[i][5] == '1'
|
||
|
dev[wire] = v
|
||
|
}
|
||
|
} else {
|
||
|
gates = append(gates, inp[i])
|
||
|
}
|
||
|
}
|
||
|
return dev, gates
|
||
|
}
|
||
|
|
||
|
func parseInput2(inp []string) [][]string {
|
||
|
var parts [][]string
|
||
|
var currPt []string
|
||
|
for _, line := range inp {
|
||
|
if line == "" {
|
||
|
if len(currPt) > 0 {
|
||
|
parts = append(parts, currPt)
|
||
|
currPt = []string{}
|
||
|
}
|
||
|
} else {
|
||
|
currPt = append(currPt, line)
|
||
|
}
|
||
|
}
|
||
|
if len(currPt) > 0 {
|
||
|
parts = append(parts, currPt)
|
||
|
}
|
||
|
return parts
|
||
|
}
|
||
|
|
||
|
func findHighestReg(dev map[string]bool) int {
|
||
|
var highest string
|
||
|
for i := range dev {
|
||
|
if i > highest {
|
||
|
highest = i
|
||
|
}
|
||
|
}
|
||
|
ret, _ := strconv.Atoi(highest[1:])
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func findValueOf(dev map[string]bool, register string) int64 {
|
||
|
var highest string
|
||
|
for i := range dev {
|
||
|
if i > highest {
|
||
|
highest = i
|
||
|
}
|
||
|
}
|
||
|
get, _ := strconv.Atoi(highest[1:])
|
||
|
var val int64
|
||
|
for i := get; ; i-- {
|
||
|
key := fmt.Sprintf("%s%02d", register, i)
|
||
|
v, ok := dev[key]
|
||
|
if !ok {
|
||
|
break
|
||
|
} else {
|
||
|
val = val << 1
|
||
|
if v {
|
||
|
val += 1
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return val
|
||
|
}
|
||
|
|
||
|
func find(w1, w2, op string, gates []string) string {
|
||
|
for _, gate := range gates {
|
||
|
if strings.HasPrefix(gate, fmt.Sprintf("%s %s %s", w1, op, w2)) ||
|
||
|
strings.HasPrefix(gate, fmt.Sprintf("%s %s %s", w2, op, w2)) {
|
||
|
parts := strings.Split(gate, " -> ")
|
||
|
return parts[len(parts)-1]
|
||
|
}
|
||
|
}
|
||
|
return ""
|
||
|
}
|