This repository has been archived by the owner on Apr 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
125 lines (115 loc) · 2.78 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"fmt"
"strconv"
"strings"
"github.com/derat/advent-of-code/lib"
)
type input struct {
op, lhs, rhs string // rhs unused for SET, NOT
}
func main() {
inputs := make(map[string]input) // keyed by dest wire id
signals := make(map[string]uint16) // final wire values keyed by id
deps := make(map[string][]string) // wire id to ids depending on it
check := make(map[string]struct{}) // newly-resolved wires
// Records src depending on dst.
// If src is a literal value, also adds it to signals and check.
addDep := func(src, dst string) {
deps[src] = append(deps[src], dst)
if v, err := strconv.Atoi(src); err == nil {
signals[src] = uint16(v)
check[src] = struct{}{}
}
}
for _, ln := range lib.InputLines("2015/7") {
switch {
case strings.HasPrefix(ln, "NOT"):
var src, dst string
lib.Extract(ln, `^NOT (\w+) -> ([a-z]+)$`, &src, &dst)
inputs[dst] = input{"NOT", src, ""}
addDep(src, dst)
case strings.Contains(ln, "AND") || strings.Contains(ln, "OR") || strings.Contains(ln, "SHIFT"):
var lhs, op, rhs, dst string
lib.Extract(ln, `^(\w+) (AND|OR|LSHIFT|RSHIFT) (\w+) -> ([a-z]+)$`, &lhs, &op, &rhs, &dst)
inputs[dst] = input{op, lhs, rhs}
addDep(lhs, dst)
addDep(rhs, dst)
default:
var src, dst string
lib.Extract(ln, `^(\w+) -> (\w+)$`, &src, &dst)
inputs[dst] = input{"SET", src, ""}
addDep(src, dst)
}
}
// Returns in's value, or false if it can't be computed yet.
compute := func(in input) (uint16, bool) {
lhs, lok := signals[in.lhs]
rhs, rok := signals[in.rhs]
switch in.op {
case "SET":
if lok {
return lhs, true
}
return 0, false
case "AND":
if lok && rok {
return lhs & rhs, true
}
return 0, false
case "OR":
if lok && rok {
return lhs | rhs, true
}
return 0, false
case "NOT":
if lok {
return ^lhs, true
}
return 0, false
case "LSHIFT":
if lok && rok {
return lhs << int(rhs), true
}
return 0, false
case "RSHIFT":
if lok && rok {
return lhs >> int(rhs), true
}
return 0, false
default:
panic(fmt.Sprintf("Invalid op %q", in.op))
}
}
solve := func() {
for len(check) > 0 {
newCheck := make(map[string]struct{})
for src := range check {
for _, dst := range deps[src] {
if _, ok := signals[dst]; ok {
continue // already computed it
}
in := inputs[dst]
if v, ok := compute(in); ok {
signals[dst] = v
newCheck[dst] = struct{}{}
}
}
}
check = newCheck
}
}
solve()
a := signals["a"]
fmt.Println(a)
// Part 2: Reset all wires and override b to take a's old value.
for id := range inputs {
delete(signals, id)
}
signals["b"] = a
for id := range signals {
check[id] = struct{}{} // check hardcoded wires again
}
solve()
fmt.Println(signals["a"])
}