Skip to content

Commit abf4135

Browse files
committed
Create a playground for reverse simulation
1 parent bd6248d commit abf4135

File tree

1 file changed

+179
-0
lines changed

1 file changed

+179
-0
lines changed

20.rev.swift

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
struct Module {
2+
enum MType {
3+
case flip
4+
case conjunction
5+
case broadcast
6+
}
7+
8+
let type: MType?
9+
let inputs: [String]
10+
let outputs: [String]
11+
}
12+
13+
extension Module: CustomStringConvertible {
14+
var description: String {
15+
let td = switch type {
16+
case .flip: "!"
17+
case .conjunction: "&"
18+
case .broadcast: "*"
19+
case nil: "#"
20+
}
21+
let id = inputs.joined(separator: "|")
22+
let od = outputs.joined(separator: "|")
23+
return [
24+
td,
25+
inputs.isEmpty ? nil : "inputs \(id)",
26+
outputs.isEmpty ? nil : "outputs \(od)"
27+
].compactMap({ $0 }).joined(separator: " ")
28+
}
29+
}
30+
31+
typealias Modules = [String: Module]
32+
33+
let verbose = switch CommandLine.arguments.last {
34+
case "-v": 1
35+
case "-vv": 2
36+
default: 0
37+
}
38+
39+
func readInput() -> Modules {
40+
// Pass 1: Build up partial modules
41+
var modules = Modules()
42+
while let line = readLine() {
43+
let words = line.split { !$0.isLetter }
44+
let type: Module.MType? = switch line.first {
45+
case "%": .flip
46+
case "&": .conjunction
47+
default: words.first == "broadcaster" ? .broadcast : nil
48+
}
49+
let name = String(words.first!)
50+
let outputs = Array(words.dropFirst(1).map { String($0) })
51+
modules[name] = Module(type: type, inputs: [], outputs: outputs)
52+
}
53+
54+
// Discover all inputs
55+
var inputs = [String: Set<String>]()
56+
for (name, module) in modules {
57+
for output in module.outputs {
58+
inputs[output, default: Set()].insert(name)
59+
if modules[output] == nil {
60+
modules[output] = Module(type: nil, inputs: [], outputs: [])
61+
}
62+
}
63+
}
64+
65+
// Pass 2: Hook up intputs into modules
66+
var result = Modules()
67+
for (name, module) in modules {
68+
let inputs = inputs[name]?.sorted() ?? []
69+
let outputs = module.outputs.sorted()
70+
result[name] = Module(type: module.type, inputs: inputs, outputs: outputs)
71+
}
72+
return result
73+
}
74+
75+
// extension Module {
76+
// typealias State = [String: Bool]
77+
// typealias Pulse = (value: Bool, from: String, to: String)
78+
// }
79+
80+
// typealias PropogateResult = (state: Module.State, pulses: [Module.Pulse])
81+
82+
// func propogate(
83+
// pulse: Module.Pulse, module: Module, state: Module.State
84+
// ) -> PropogateResult? {
85+
// func emit(state: Module.State, value v: Bool) -> PropogateResult {
86+
// (state: state,
87+
// pulses: module.outputs.map { (value: v, from: module.name, to: $0) })
88+
// }
89+
90+
// switch module.type {
91+
// case .broadcast:
92+
// return emit(state: state, value: pulse.value)
93+
// case .flip:
94+
// if pulse.value {
95+
// return nil
96+
// } else {
97+
// let newValue = !state["", default: false]
98+
// let newState = state.merging(["": newValue]) { _, new in new }
99+
// return emit(state: newState, value: newValue)
100+
// }
101+
// case .conjunction:
102+
// let newState = state.merging([pulse.from: pulse.value]) { _, new in new }
103+
// let newValue = !newState.values.reduce(true) { $0 && $1 }
104+
// return emit(state: newState, value: newValue)
105+
// default:
106+
// return nil
107+
// }
108+
// }
109+
110+
// func simulate(modules: Modules, times: Int) -> (p1: Int, p2: Int) {
111+
// let buttonPress = (value: false, from: "button", to: "broadcaster")
112+
113+
// var counts = [true: 0, false: 0]
114+
// // Examples don't have "rx", so don't go into an infinite loop. But since
115+
// // this solution doesn't work for p2 yet, this search for rx is actually
116+
// // always disabled for now.
117+
// var rxN: Int? = haveRx(modules: modules) ? 0 : 0
118+
// var states = [String: Module.State]()
119+
120+
// initConjunctions(modules: modules, states: &states)
121+
122+
// var n = 0
123+
// while n < times || rxN == nil {
124+
// n += 1
125+
126+
// var pending = [buttonPress]
127+
// var pi = 0
128+
129+
// counts[buttonPress.value]? += 1
130+
131+
// while pi < pending.count {
132+
// let pulse = pending[pi]
133+
// let (value, from, to) = pulse
134+
// pi += 1
135+
136+
// if verbose > 0 {
137+
// print("button press \(n) pulse \(pi)\t\t\(from) -\(value ? "high" : "low")-> \(to)")
138+
// }
139+
140+
// if to == "rx" {
141+
// if !value {
142+
// print("button press \(n) sending \(value) to rx")
143+
// if rxN == nil || rxN == 0 {
144+
// rxN = n
145+
// }
146+
// }
147+
// }
148+
149+
// let module = modules[to, default: .named(to)]
150+
// let state = states[to, default: Module.State()]
151+
// if let new = propogate(pulse: pulse, module: module, state: state) {
152+
// states[to] = new.state
153+
// pending.append(contentsOf: new.pulses)
154+
// for b in new.pulses.map({ $0.value }) {
155+
// counts[b]? += 1
156+
// }
157+
// }
158+
// }
159+
// }
160+
161+
// let p1 = counts[false]! * counts[true]!
162+
// return (p1: p1, p2: rxN!)
163+
// }
164+
165+
166+
// func haveRx(modules: Modules) -> Bool {
167+
// for (input, module) in modules {
168+
// if input == "rx" { return true }
169+
// for output in module.outputs {
170+
// if output == "rx" { return true }
171+
// }
172+
// }
173+
// return false
174+
// }
175+
176+
let modules = readInput()
177+
print(modules)
178+
// let r = simulate(modules: modules, times: 1000)
179+
// print(r)

0 commit comments

Comments
 (0)