257 lines
5.4 KiB
Go
257 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
func main() {
|
|
fmt.Println(part1(readData("example_simple.txt")), 4)
|
|
fmt.Println(part1(readData("example.txt")), 2024)
|
|
fmt.Println(part1(readData("data.txt")), 49574189473968)
|
|
// fmt.Println(part2(readData("data.txt").gates))
|
|
fmt.Println(part2(readData("data-2.txt").gates))
|
|
|
|
}
|
|
|
|
const (
|
|
AND = "AND"
|
|
OR = "OR"
|
|
XOR = "XOR"
|
|
)
|
|
|
|
type Gate struct {
|
|
op string
|
|
a, b string
|
|
}
|
|
|
|
type Circuit struct {
|
|
values map[string]bool
|
|
gates map[string]Gate
|
|
}
|
|
|
|
func part1(input Circuit) (result uint64) {
|
|
queue := []string{}
|
|
for output := range input.gates {
|
|
queue = append(queue, output)
|
|
}
|
|
|
|
for len(queue) > 0 {
|
|
output := queue[len(queue)-1]
|
|
if _, alreadyComputed := input.values[output]; alreadyComputed {
|
|
queue = queue[:len(queue)-1]
|
|
continue
|
|
}
|
|
|
|
gate := input.gates[output]
|
|
valueA, okA := input.values[gate.a]
|
|
valueB, okB := input.values[gate.b]
|
|
|
|
if !okA || !okB {
|
|
if !okA {
|
|
queue = append(queue, gate.a)
|
|
}
|
|
if !okB {
|
|
queue = append(queue, gate.b)
|
|
}
|
|
} else {
|
|
input.values[output] = evaluate(gate.op, valueA, valueB)
|
|
queue = queue[:len(queue)-1]
|
|
}
|
|
}
|
|
|
|
zWires := []string{}
|
|
for wire := range input.values {
|
|
if wire[0] == 'z' {
|
|
zWires = append(zWires, wire)
|
|
}
|
|
}
|
|
|
|
sort.Sort(sort.Reverse(sort.StringSlice(zWires)))
|
|
|
|
for _, w := range zWires {
|
|
if input.values[w] {
|
|
result = result<<1 | 1
|
|
} else {
|
|
result = result << 1
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func evaluate(op string, a, b bool) bool {
|
|
switch op {
|
|
case AND:
|
|
return a && b
|
|
case OR:
|
|
return a || b
|
|
case XOR:
|
|
return a != b
|
|
default:
|
|
panic("unknown operator")
|
|
}
|
|
}
|
|
|
|
func name(prefix byte, num int) string {
|
|
a := byte(num%10 + '0')
|
|
b := byte(num/10 + '0')
|
|
return string([]byte{prefix, b, a})
|
|
}
|
|
|
|
func evaluateAdder(gates map[string]Gate, a, b uint64) uint64 {
|
|
circuit := Circuit{gates: gates, values: make(map[string]bool)}
|
|
for i := range 50 {
|
|
x := a&(uint64(1)<<i) != 0
|
|
y := b&(uint64(1)<<i) != 0
|
|
circuit.values[name('x', i)] = x
|
|
circuit.values[name('y', i)] = y
|
|
}
|
|
return part1(circuit)
|
|
}
|
|
|
|
func printAround(w string, prefix string, gates map[string]Gate, depth int) {
|
|
if depth == 0 {
|
|
return
|
|
}
|
|
if g, ok := gates[w]; ok {
|
|
fmt.Println(prefix, w, g)
|
|
printAround(g.a, prefix+" ", gates, depth-1)
|
|
printAround(g.b, prefix+" ", gates, depth-1)
|
|
}
|
|
}
|
|
|
|
func part2(gates map[string]Gate) string {
|
|
// ckb-z39
|
|
// tqq-z20
|
|
// ksv-z06
|
|
// kbs-nbd
|
|
// ckb,kbs,ksv,nbd,tqq,z06,z20,z39
|
|
|
|
// fmt.Println("z without xor")
|
|
// for out, g := range gates {
|
|
// if out[0] == 'z' && g.op != XOR && out != "z45" {
|
|
// fmt.Println(out, g)
|
|
// }
|
|
// }
|
|
// z39 {0 cmj hpp} DONE
|
|
// z20 {1 tsm dnc} DONE
|
|
|
|
// z06 {AND x06 y06} DONE
|
|
// nsp {XOR x06 y06}
|
|
// ksv {XOR qtf nsp}
|
|
|
|
// printAround("z06", gates, 3)
|
|
// fmt.Println("")
|
|
// for out, g := range gates {
|
|
// if g.a == "nsp" || g.b == "nsp" {
|
|
// fmt.Println(out, g)
|
|
// }
|
|
// }
|
|
// fmt.Println("xor without x or y")
|
|
// for out, g := range gates {
|
|
// if g.op == XOR && (g.a[0] != 'x' && g.a[0] != 'y' && g.b[0] != 'x' && g.b[0] != 'y' && out[0] != 'z') {
|
|
// fmt.Println(out, g)
|
|
// }
|
|
// }
|
|
// ckb {2 hpp cmj} DONE
|
|
// tqq {2 bnp mtq} DONE
|
|
// ksv {2 qtf nsp} DONE
|
|
|
|
// for i := range uint64(50) {
|
|
// x := uint64(1) << i - 1
|
|
// res1 := evaluateAdder(gates, x, 1)
|
|
// res2 := x + 1
|
|
// if res1 != res2 {
|
|
// fmt.Println(i, res1, res2)
|
|
// }
|
|
// }
|
|
// Issue at 11
|
|
// printAround("z11", "", gates, 4)
|
|
// printAround("z10", "", gates, 4)
|
|
// z11 {XOR jsv pjk}
|
|
// jsv {OR jvr kbs}
|
|
// jvr {AND nbd dnn}
|
|
// nbd {AND x10 y10}
|
|
// dnn {OR jwh gcp}
|
|
// kbs {XOR y10 x10}
|
|
// pjk {XOR y11 x11}
|
|
//
|
|
// z10 {XOR dnn nbd}
|
|
// dnn {OR jwh gcp}
|
|
// jwh {AND tnc gbw}
|
|
// tnc {OR tjd vsw}
|
|
// gbw {XOR x09 y09}
|
|
// gcp {AND x09 y09}
|
|
// nbd {AND x10 y10}
|
|
|
|
// findGate := func(gate Gate) string {
|
|
// for output, g := range gates {
|
|
// if g.op == gate.op && ((g.a == gate.a && g.b == gate.b) || (g.a == gate.b && g.b == gate.a)) {
|
|
// return output
|
|
// }
|
|
// }
|
|
// return ""
|
|
// }
|
|
|
|
// carry := make([]string, 100)
|
|
// carry[0] = findGate(Gate{AND, "x00", "y00"})
|
|
// if carry[0] == "" {
|
|
// panic("Oh no")
|
|
// }
|
|
|
|
// for i := 1; i < 2; i++ {
|
|
// if tmpz0 := findGate(Gate{XOR, name('x', i), name('y', i)}); tmpz0 != "" {
|
|
// fmt.Println("tmpz0", i, name('x', i), name('y', i), "->", tmpz0)
|
|
// z := findGate(Gate{XOR, tmpz0, carry[i-1]})
|
|
// if z[0] == 'z' {
|
|
// fmt.Println("z", i, tmpz0, carry[i-1], "->", z)
|
|
// } else {
|
|
// fmt.Println("oh no")
|
|
// }
|
|
// } else if tmpz0 := findGate(Gate{XOR, name('x', i), carry[i-1]}); tmpz0 != "" {
|
|
// fmt.Println("tmpz0", i, name('x', i), carry[i-1], "->", tmpz0)
|
|
// } else if tmpz0 := findGate(Gate{XOR, name('y', i), carry[i-1]}); tmpz0 != "" {
|
|
// fmt.Println("tmpz0", i, name('y', i), carry[i-1], "->", tmpz0)
|
|
// }
|
|
// }
|
|
|
|
// // for output, g := range gates {
|
|
|
|
// // }
|
|
|
|
return ""
|
|
}
|
|
|
|
func readData(fileName string) (data Circuit) {
|
|
data = Circuit{
|
|
values: make(map[string]bool),
|
|
gates: make(map[string]Gate),
|
|
}
|
|
|
|
fp, _ := os.Open(fileName)
|
|
scanner := bufio.NewScanner(fp)
|
|
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if len(line) == 0 {
|
|
break
|
|
}
|
|
|
|
wire := line[0:3]
|
|
value := line[5] == '1'
|
|
|
|
data.values[wire] = value
|
|
}
|
|
|
|
for scanner.Scan() {
|
|
line := strings.Split(strings.TrimSpace(scanner.Text()), " ")
|
|
data.gates[line[4]] = Gate{line[1], line[0], line[2]}
|
|
}
|
|
|
|
return
|
|
}
|