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