adventofcode/2024/day24/main.go

193 lines
3.5 KiB
Go
Raw Normal View History

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 ""
}