from collections import defaultdict
class Executor():
def __init__(self):
self.components = {}
self.to_run = set()
self.sources = []
self.destinations = []
def execute(self):
while self.to_run:
self.to_run.pop().evaluate(self)
def add_component(self, name, component):
self.components[name] = component
self.to_run.add(component)
class Connection():
def __init__(self, source, dest):
self.source = source
self.dest = dest
def evaluate(self, executor):
executor.set_input(self.dest, executor.get_outval(self.source))
def add_connection(self, source, destination):
sourceComponent, sourceWire = source.split('.')
destComponent, destWire = destination.split('.')
connection = self.Connection(source, destination)
self.to_run.add(connection)
self.components[sourceComponent].add_listener(sourceWire, connection)
def set_input(self, wireDescriptor, val):
component, wire = wireDescriptor.split('.')
self.components[component].set_input(wire, val, self)
def get_inval(self, descriptor):
component, wire = descriptor.split('.')
return self.components[component].get_input(wire)
def get_outval(self, descriptor):
component, wire = descriptor.split('.')
return self.components[component].get_output(wire)
def set_displayset(self, sources, destinations):
self.sources = sources
self.destinations = destinations
def get_displaystate(self):
sources = {descriptor: self.get_inval(descriptor) for descriptor in self.sources}
destinations = {descriptor: self.get_outval(descriptor) for descriptor in self.destinations}
return {
'inputs': sources,
'outputs': destinations
}
def queue(self, runnable):
self.to_run.add(runnable)
class BaseCircuit():
def __init__(self):
self.outputs = {}
self.listeners = defaultdict(lambda: [])
self.inputs = {}
def outputs(self):
return self.outputs.keys()
def get_output(self, outkey):
return self.outputs[outkey]
def set_input(self, inkey, value, executor):
if self.inputs[inkey] != value:
executor.queue(self)
self.inputs[inkey] = value
def get_input(self, inkey):
return self.inputs[inkey]
def get_inputs(self):
return self.inputs.keys()
def add_listener(self, outkey, listener):
self.listeners[outkey].append(listener)
def _set_output(self, outputs, executor):
for outkey, outval in outputs.items():
if outval != self.outputs[outkey]:
self.outputs[outkey] = outval
for listener in self.listeners[outkey]:
executor.queue(listener)
def evaluate(self):
raise Exception("Evaluate called on abstract BaseCircuit class")
class OrGate(BaseCircuit):
def __init__(self):
super().__init__()
self.outputs = {
'out': False,
}
self.inputs = {
'a': False,
'b': False,
}
def evaluate(self, executor):
print("Evaluate got called")
self._set_output(
{
'out': self.get_input('a') or self.get_input('b'),
},
executor,
)
class NorGate(BaseCircuit):
def __init__(self):
super().__init__()
self.outputs = {
'out': True,
}
self.inputs = {
'a': False,
'b': False,
}
def evaluate(self, executor):
self._set_output(
{
'out': (not self.get_input('a')) and (not self.get_input('b')),
},
executor,
)
from pprint import pprint
executor = Executor()
executor.add_component("orGate", OrGate())
executor.add_connection("orGate.out", "orGate.b")
executor.set_displayset(
sources=['orGate.a', 'orGate.b'],
destinations=['orGate.out'],
)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input('orGate.a', True)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input('orGate.a', False)
executor.execute()
pprint(executor.get_displaystate())
Evaluate got called {'inputs': {'orGate.a': False, 'orGate.b': False}, 'outputs': {'orGate.out': False}} Evaluate got called Evaluate got called {'inputs': {'orGate.a': True, 'orGate.b': True}, 'outputs': {'orGate.out': True}} Evaluate got called {'inputs': {'orGate.a': False, 'orGate.b': True}, 'outputs': {'orGate.out': True}}
executor = Executor()
executor.add_component("topNor", NorGate())
executor.add_component("bottomNor", NorGate())
executor.add_connection("topNor.out", "bottomNor.a")
executor.add_connection("bottomNor.out", "topNor.b")
executor.set_displayset(
sources=["topNor.a", "topNor.b", "bottomNor.a", "bottomNor.b"],
destinations=["topNor.out", "bottomNor.out"],
)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("topNor.a", True)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("topNor.a", False)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("bottomNor.b", True)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("bottomNor.b", False)
executor.execute()
pprint(executor.get_displaystate())
{'inputs': {'bottomNor.a': False, 'bottomNor.b': False, 'topNor.a': False, 'topNor.b': True}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.a': False, 'bottomNor.b': False, 'topNor.a': True, 'topNor.b': True}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.a': False, 'bottomNor.b': False, 'topNor.a': False, 'topNor.b': True}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.a': True, 'bottomNor.b': True, 'topNor.a': False, 'topNor.b': False}, 'outputs': {'bottomNor.out': False, 'topNor.out': True}} {'inputs': {'bottomNor.a': True, 'bottomNor.b': False, 'topNor.a': False, 'topNor.b': False}, 'outputs': {'bottomNor.out': False, 'topNor.out': True}}
def parse_circuit(circuit):
executor = Executor()
for name, component in circuit['components'].items():
executor.add_component(name, component)
for source, dest in circuit['connections']:
executor.add_connection(source, dest)
executor.set_displayset(
sources=circuit['in_displayset'],
destinations=circuit['out_displayset'],
)
return executor
executor = parse_circuit({
'components': {
'topNor': NorGate(),
'bottomNor': NorGate(),
},
'connections': [
('topNor.out', 'bottomNor.a'),
('bottomNor.out', 'topNor.b'),
],
'in_displayset': [
'topNor.a',
'bottomNor.b',
],
'out_displayset': [
'topNor.out',
'bottomNor.out',
],
})
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("topNor.a", True)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("topNor.a", False)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("bottomNor.b", True)
executor.execute()
pprint(executor.get_displaystate())
executor.set_input("bottomNor.b", False)
executor.execute()
pprint(executor.get_displaystate())
{'inputs': {'bottomNor.b': False, 'topNor.a': False}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.b': False, 'topNor.a': True}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.b': False, 'topNor.a': False}, 'outputs': {'bottomNor.out': True, 'topNor.out': False}} {'inputs': {'bottomNor.b': True, 'topNor.a': False}, 'outputs': {'bottomNor.out': False, 'topNor.out': True}} {'inputs': {'bottomNor.b': False, 'topNor.a': False}, 'outputs': {'bottomNor.out': False, 'topNor.out': True}}