-
Notifications
You must be signed in to change notification settings - Fork 0
/
logicgate_solution.py
273 lines (214 loc) · 6.35 KB
/
logicgate_solution.py
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
"""
Yingshi Liu
CS3B, Assignment #4, Logic gate simulation (Part 1)
10/31/2022
"""
class Input:
"""A class representing an input"""
def __init__(self, owner):
if not isinstance(owner, LogicGate):
raise TypeError("Owner should be a type of LogicGate")
self._owner = owner
def __str__(self):
try:
return str(self.value)
except AttributeError:
# handle the exception that no value initially
return "(no value)"
@property
def owner(self):
return self._owner
@property
def value(self):
return self._value
@value.setter
def value(self, value):
# Normalize the value to bool
self._value = bool(value)
self.owner.evaluate()
class Output:
"""A class representing an output"""
def __init__(self):
self._connections = []
def __str__(self):
try:
return str(self.value)
except AttributeError:
# handle the exception that no value initially
return "(no value)"
def connect(self, input_):
if not isinstance(input_, Input):
raise TypeError("Output must be connected to an input")
if input_ not in self.connections:
self.connections.append(input_)
try:
input_.value = self._value
except AttributeError:
pass
@property
def value(self):
return self._value
@value.setter
def value(self, value):
# Normalize the value to bool
self._value = bool(value)
# After the output value changes, set all the connected inputs
# to the same value.
for connection in self.connections:
connection.value = self.value
@property
def connections(self):
return self._connections
class LogicGate:
"""Base class for all logic gates."""
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
class UnaryGate(LogicGate):
"""A class representing logic gate with a single input."""
def __init__(self, name):
super().__init__(name)
self._input = Input(self)
self._output = Output()
def __str__(self):
return (f"LogicGate {self.name}: input={self.input}, "
f"output={self.output}")
@property
def input(self):
return self._input
@property
def output(self):
return self._output
class BinaryGate(LogicGate):
"""A class representing logic gate with two inputs."""
def __init__(self, name):
super().__init__(name)
self._input0 = Input(self)
self._input1 = Input(self)
self._output = Output()
def __str__(self):
return (f"LogicGate {self.name}: input0={self.input0}, "
f"input1={self.input1}, output={self.output}")
@property
def input0(self):
return self._input0
@property
def input1(self):
return self._input1
@property
def output(self):
return self._output
class NotGate(UnaryGate):
def evaluate(self):
try:
self.output.value = not self.input.value
except AttributeError:
pass
class AndGate(BinaryGate):
def evaluate(self):
try:
self.output.value = self.input0.value and self.input1.value
except AttributeError:
pass
class OrGate(BinaryGate):
def evaluate(self):
try:
self.output.value = self.input0.value or self.input1.value
except AttributeError:
pass
class XorGate(BinaryGate):
def evaluate(self):
try:
# Assume the value is bool, != is same as xor
self.output.value = (self.input0.value != self.input1.value)
except AttributeError:
pass
def test():
"""Umbrella test function"""
tests = [
test_input,
test_output,
test_not,
test_and,
test_or,
test_xor,
test_not_not,
test_and_not,
]
for t in tests:
print("Running " + t.__name__ + " " + "-" * 20)
t()
def test_input():
input_ = Input(NotGate("test"))
print("Initially, input_ is:", input_)
try:
print(input_.value)
print("Failed: input_.value exists before it's set, which should not happen!")
except AttributeError:
print("Succeeded: input_.value doesn't exist before it's set.")
input_.value = True
print("After set to True, input_ is:", input_)
def test_output():
output = Output()
print("Initially, output is:", output)
try:
print(output.value)
print("Failed: output.value exists before it's set, which should not happen!")
except AttributeError:
print("Succeeded: output.value doesn't exist before it's set.")
output.value = True
print("After set to True, output is:", output)
def test_not():
not_gate = NotGate("not")
not_gate.input.value = True
print(not_gate)
not_gate.input.value = False
print(not_gate)
def test_and():
and_gate = AndGate("and")
print("AND gate initial state:", and_gate)
and_gate.input0.value = True
print("AND gate with 1 input set", and_gate)
and_gate.input1.value = False
print("AND gate with 2 inputs set:", and_gate)
and_gate.input1.value = True
print("AND gate with 2 inputs set:", and_gate)
def test_or():
or_gate = OrGate("or")
or_gate.input0.value = False
or_gate.input1.value = False
print(or_gate)
or_gate.input1.value = True
print(or_gate)
def test_xor():
xor_gate = XorGate("xor")
xor_gate.input0.value = False
xor_gate.input1.value = False
print(xor_gate)
xor_gate.input1.value = True
print(xor_gate)
def test_not_not():
not_gate1 = NotGate("not1")
not_gate2 = NotGate("not2")
not_gate1.output.connect(not_gate2.input)
print(not_gate1)
print(not_gate2)
print("Setting not-gate input to False...")
not_gate1.input.value = False
print(not_gate1)
print(not_gate2)
def test_and_not():
and_gate = AndGate("and")
not_gate = NotGate("not")
and_gate.output.connect(not_gate.input)
and_gate.input0.value = True
and_gate.input1.value = False
print(and_gate)
print(not_gate)
and_gate.input1.value = True
print(and_gate)
print(not_gate)
if __name__ == '__main__':
test()