Python Project: Binary Adding Machine
07-15-2012
, 10:49 AM
Hey what's up guys. About a month and a half ago I decided I wanted to seriously try learning programming (took few courses in uni but mostly bombed them playing poker all day). I did about 20 project euler problems and realized that I was just building algorithms. And I wasn't learning about classes, which I figured are important, so I decided I needed to actually start some kind of project.
I decided on building a program that would model a physical binary adding machine. I got the idea from reading a book called Code by Charles Petzold. This book basically teaches you how computers work starting from morse code and flashlights, to binary and relays, all the way up to RAM, CPU, etc. It's turned out to be my favorite thing I've read in a long time, and I highly recommend it.
So anyway, about halfway through the book he explains how to make a binary adding machine. Basically you make relays out of wires and switches, and then combine those relays into logic gates, and then eventually combine those logic gates and get a binary adding machine. And while reading this, I really wanted to try to build one of my own. But a machine that can add two 8 bit numbers require a lot of relays, and I didn't want to have to build them all.
So instead I've decided to recreate the binary adding machine as a Python program. So far I've written up the code for a simple circuit with a switch (a flashlight). Here's a visual model i found off google:

And here's the module:
And here's the program:
The next thing I want to do is add an Electromagnet class, which will help me build a relay. Which looks like this:
Once I've got that i'll move on to building the logic gates. I'll try to explain what's going on for those that are interested.
If you have any suggestions I'd love to hear them. If you just want to chat about programming send me a PM. I don't really know where to find people who can help me so I'm basically learning everything on my own through the internet.
I decided on building a program that would model a physical binary adding machine. I got the idea from reading a book called Code by Charles Petzold. This book basically teaches you how computers work starting from morse code and flashlights, to binary and relays, all the way up to RAM, CPU, etc. It's turned out to be my favorite thing I've read in a long time, and I highly recommend it.
So anyway, about halfway through the book he explains how to make a binary adding machine. Basically you make relays out of wires and switches, and then combine those relays into logic gates, and then eventually combine those logic gates and get a binary adding machine. And while reading this, I really wanted to try to build one of my own. But a machine that can add two 8 bit numbers require a lot of relays, and I didn't want to have to build them all.
So instead I've decided to recreate the binary adding machine as a Python program. So far I've written up the code for a simple circuit with a switch (a flashlight). Here's a visual model i found off google:

And here's the module:
Code:
#parts: wire, switch, and battery
# charge is a variable shared by all classes that tells whether
# or not there's a complete circuit providing power
class Parts(object):
charge = "no charge"
# wires to connect stuff
# I'm having other classes inherit Wire so I can connect
# stuff directly, without having to create a Wire instance
# between everything
class Wire (Parts):
def connect(self, connected_to):
self.connected_to = connected_to
self.connected_to.source = self
# checks if there's a complete circuit
def check_circuit(self):
if self.check_in() == "circuit complete" and self.check_out() == "circuit complete":
Parts.charge = "has charge"
else:
Parts.charge = "no charge"
def check_in(self):
if str(self.source) == "open":
return "circuit incomplete"
if str(self.source) != "battery plus":
self.source.check_in()
return "circuit complete"
def check_out(self):
if str(self.connected_to) == "open":
return "circuit incomplete"
if str(self.connected_to) != "battery minus":
self.connected_to.check_in()
return "circuit complete"
class Switch(Wire):
def __init__(self, open_closed):
self.open_closed = open_closed
def __str__(self):
return self.open_closed
class BatteryPlus(Wire):
def __str__(self):
return "battery plus"
class BatteryMinus():
def __str__(self):
return "battery minus"
class Lightbulb(Wire):
def __str__(self):
return "lightbulb"
def check_light(self):
self.check_circuit()
if Parts.charge == "has charge":
print "light on!"
else:
print "light off"
Code:
#simple circuit
from parts import *
class Flashlight(object):
def __init__(self):
#parts
self.plus = BatteryPlus()
self.lightbulb = Lightbulb()
self.switch = Switch("open")
self.minus = BatteryMinus()
#construction
self.plus.connect(self.switch)
self.switch.connect(self.lightbulb)
self.lightbulb.connect(self.minus)
#operation
def on(self):
self.switch.open_closed = "closed"
self.lightbulb.check_light()
def off(self):
self.switch.open_closed = "open"
self.lightbulb.check_light()
#test
new = Flashlight()
new.on()
new.off()
new.on()
new.off()
Once I've got that i'll move on to building the logic gates. I'll try to explain what's going on for those that are interested.
If you have any suggestions I'd love to hear them. If you just want to chat about programming send me a PM. I don't really know where to find people who can help me so I'm basically learning everything on my own through the internet.
07-15-2012
, 12:03 PM
Here's a suggestion:
Keep going and keep posting ITT. This is a neat project
Keep going and keep posting ITT. This is a neat project
07-15-2012
, 07:03 PM
I think this is really awesome project. I recently worked through something like this. Maybe you can watch this video so you can see how to generalize the procedures a little bit:
http://www.youtube.com/watch?v=9jbQrNGQVKc
Unfortunately, you'll have to translate all of the above to python, but I think you'll get the general idea down.
Basically, they build a wire, then the various gates, and store the state of the gates. They create a the whole program using a queue:
Python has a Queue module, http://docs.python.org/library/queue.html, though I don't know anything about it.
http://www.youtube.com/watch?v=9jbQrNGQVKc
Unfortunately, you'll have to translate all of the above to python, but I think you'll get the general idea down.
Basically, they build a wire, then the various gates, and store the state of the gates. They create a the whole program using a queue:
Python has a Queue module, http://docs.python.org/library/queue.html, though I don't know anything about it.
07-16-2012
, 12:25 AM
this is pretty cool and I'd really like to see the project grow. But I don't understand this
is there a return missing from line 5?
Code:
def check_in(self):
if str(self.source) == "open":
return "circuit incomplete"
if str(self.source) != "battery plus":
self.source.check_in()
return "circuit complete"
07-16-2012
, 04:18 AM
Quote:
this is pretty cool and I'd really like to see the project grow. But I don't understand this
is there a return missing from line 5?
Code:
def check_in(self):
if str(self.source) == "open":
return "circuit incomplete"
if str(self.source) != "battery plus":
self.source.check_in()
return "circuit complete"
One thing I'm not sure about is why the function doesn't exit at the first iteration with a return statement. Instead it appears to hold the return statement from completing until its "outer" recursion iterations complete. At least I think that's what's happening when i stick a print statement before the return statement. I get more than one print out.
07-17-2012
, 12:33 AM
Hey, I'm really glad that you guys think the project is interesting. So I finished the relay program which required a lot of interesting adjustments to accommodate its new properties since the flashlight.
For people who don't know how a relay works, here's a picture of one:

Basically a wire goes into an electromagnet (an electromagnet turns into a magnet when supplied electricity) which pulls a switch. And you can set up the switch so that when it gets pulled it completes a circuit (or break an already complete circuit). This is useful because you can pull switches remotely now, instead of having to open and close switches by hand. Then if you wire multiple relays in different ways, you can get them to open and close switches under various conditions, which is a rough explanation of how you make logic gates.
Anyway here's the code. A lot of things are changed since the flashlight program. Electromagnet class and Relay class are at the bottom.
Here's a test for this code:
One interesting problem I had was that I wanted the relay to work like any other part. I wanted to be able to connect to and from Relay objects, because the logic gates I'm going to build require me to connect multiple relays. So for example I want to be able to write "part.connect(relay)". But then it connects to the whole Relay object, instead of the collection of its parts. The problem is that when I check for complete circuits, I follow along connected parts. So I needed a way for a circuit check to start outside the relay and then eventually continue the circuit check inside the relay. So for example, what i wanted it to actually do was "part.connect(relay.electromagnet)" where electromagnet is the first object inside relay. That way I could accurately model a charge moving into the relay where it continues to do the circuit check. But that prevents me from being able to use the relay like a black box, which was my original goal.
So one weird thing you might see in here is that I added a connect_back function. Where after I connect to a part, the connected_to part connects back. And then in the Relay class, I overwrote the connect_back function so that it changes the connected_to. So if a part connects to a relay, it would tell relay to create a connect_back attribute linking back, but then the relay's overridden connect_back function would change the part's connected to attribute from "relay" to "relay.electromagnet". Maybe this is a convoluted way of doing it but I had a hard time thinking of another way.
So next I'm going to work on the logic gates. From what I've read I'm only going to need three gates and an inverter. I'll try to explain what those are and how I went about making them next time.
There were a ton of things I wanted to write about but it was just getting too long and complicated, so if you had any questions feel free to let me know.
For people who don't know how a relay works, here's a picture of one:

Basically a wire goes into an electromagnet (an electromagnet turns into a magnet when supplied electricity) which pulls a switch. And you can set up the switch so that when it gets pulled it completes a circuit (or break an already complete circuit). This is useful because you can pull switches remotely now, instead of having to open and close switches by hand. Then if you wire multiple relays in different ways, you can get them to open and close switches under various conditions, which is a rough explanation of how you make logic gates.
Anyway here's the code. A lot of things are changed since the flashlight program. Electromagnet class and Relay class are at the bottom.
Code:
#parts: wire, switch, battery plus, battery minus, lightbulb, electromagnet, relay
reset_parts = []
class Parts(object):
def __init__(self):
self.default = None
self.status = None
def _check_circuit(self):
if self.status == "open":
for x in reset_parts:
x.status = x.default
return
if str(self) != "battery minus":
self.wire_out._check_circuit()
if str(self) == "switch" or str(self) == "lightbulb":
reset_parts.append(self)
self.operate()
def operate(self):
pass
class Wire (Parts):
def connect(self, wire_out):
self.wire_out = wire_out
self.wire_out.connect_back(self)
# fix for the "black box" problem
def connect_back(self, wire_in):
self.wire_in = wire_in
class Switch(Wire):
def __init__(self, default):
self.default = default
self.status = default
def __str__(self):
return "switch"
def check_circuit(self):
if str(self.wire_in) == "battery plus":
self._check_circuit()
class BatteryPlus(Wire):
def __str__(self):
return "battery plus"
class BatteryMinus(Wire):
def __str__(self):
return "battery minus"
class Lightbulb(Wire):
def __init__(self):
self.default = "light off"
self.status = "light off"
def __str__(self):
return "lightbulb"
def operate(self):
self.status = "light on!"
def check(self):
return self.status
class Electromagnet(Wire):
def __init__(self, switch_obj):
self.switch_obj = switch_obj
self.default = None
self.status = None
def __str__(self):
return "electromagnet"
def operate(self):
if self.switch_obj.default == "open":
self.switch_obj.status = "closed"
elif self.switch_obj.default == "closed":
self.switch_obj.status = "open"
self.switch_obj.check_circuit()
class Relay(Wire):
def __init__(self):
# parts
self.switch = Switch("open")
self.em = Electromagnet(self.switch)
self.ground = BatteryMinus()
self.voltage = BatteryPlus()
#construction
self.em.connect(self.ground)
self.voltage.connect(self.switch)
# fix connections for the "black box" problem
def connect_back(self, wire_in):
self.wire_in = wire_in
self.wire_in.wire_out = self.em
def connect(self, wire_out):
self.switch.wire_out = wire_out
Code:
#test relay
from parts import *
# parts
battery_plus = BatteryPlus()
switch = Switch("open")
relay = Relay()
lightbulb = Lightbulb()
battery_minus = BatteryMinus()
#construction
battery_plus.connect(switch)
switch.connect(relay)
relay.connect(lightbulb)
lightbulb.connect(battery_minus)
#operation
def on():
switch.status = "closed"
switch.check_circuit()
print lightbulb.check()
def off():
switch.status = "open"
switch.check_circuit()
print lightbulb.check()
on()
off()
on()
off()
on()
So one weird thing you might see in here is that I added a connect_back function. Where after I connect to a part, the connected_to part connects back. And then in the Relay class, I overwrote the connect_back function so that it changes the connected_to. So if a part connects to a relay, it would tell relay to create a connect_back attribute linking back, but then the relay's overridden connect_back function would change the part's connected to attribute from "relay" to "relay.electromagnet". Maybe this is a convoluted way of doing it but I had a hard time thinking of another way.
So next I'm going to work on the logic gates. From what I've read I'm only going to need three gates and an inverter. I'll try to explain what those are and how I went about making them next time.
There were a ton of things I wanted to write about but it was just getting too long and complicated, so if you had any questions feel free to let me know.
07-19-2012
, 03:23 PM
What is the "black box problem?" I'm not sure what you think "black box" means, but there's some evidence you may be confused here, but I should hear it from you before I carry on.
I also think that it is better if you have the wire have a single state, thus you won't have to write all of this, and similar:
The wire should only carry a single state only after it is changed by one of your gates. Thus, wire A will always be 1 or 0. Think about how you can set this on the wires and simply use the wire as a connection between gate B and gate C. Once you generalize the state of the wire, creating your black-box procedures will be much easier.
I'm not entirely sure why you are inheriting the features of the wire to the other objects. This is akin to having a bicycle class inheriting from a car class because you need tires.
I also think that it is better if you have the wire have a single state, thus you won't have to write all of this, and similar:
Code:
class Wire (Parts):
def connect(self, wire_out):
self.wire_out = wire_out
self.wire_out.connect_back(self)
# fix for the "black box" problem
def connect_back(self, wire_in):
self.wire_in = wire_in
I'm not entirely sure why you are inheriting the features of the wire to the other objects. This is akin to having a bicycle class inheriting from a car class because you need tires.
07-19-2012
, 11:15 PM
Join Date: Dec 2004
Posts: 2,162
I just wanted to thank OP for bringing Petzold's book Code to my attention. This is one of the most entertaining and insightful technical books I've read and makes me even more resentful of the awful CS classes I waded through that touched on a lot of the same topics in a far more confusing manner.
07-20-2012
, 05:26 AM
Quote:
What is the "black box problem?" I'm not sure what you think "black box" means, but there's some evidence you may be confused here, but I should hear it from you before I carry on.
I also think that it is better if you have the wire have a single state, thus you won't have to write all of this, and similar:
The wire should only carry a single state only after it is changed by one of your gates. Thus, wire A will always be 1 or 0. Think about how you can set this on the wires and simply use the wire as a connection between gate B and gate C. Once you generalize the state of the wire, creating your black-box procedures will be much easier.
I'm not entirely sure why you are inheriting the features of the wire to the other objects. This is akin to having a bicycle class inheriting from a car class because you need tires.
I also think that it is better if you have the wire have a single state, thus you won't have to write all of this, and similar:
Code:
class Wire (Parts):
def connect(self, wire_out):
self.wire_out = wire_out
self.wire_out.connect_back(self)
# fix for the "black box" problem
def connect_back(self, wire_in):
self.wire_in = wire_in
I'm not entirely sure why you are inheriting the features of the wire to the other objects. This is akin to having a bicycle class inheriting from a car class because you need tires.
And by easy to use and understand, I mean I want the user to be able to write x.connect(y) for any part (wire, lightbulb, etc), even parts that are constructed from parts (relays, logic gates). This kind of got complicated though because with the logic gates I realized that some of the parts are requiring multiple inputs.
Maybe another problem is that I want the program to model the properties of an electrical device as closely as possible. So for the relay I could have programmed it to just take an input of 1 or 0 and pump out an according 1 or 0. But I wanted the operation of the relay to actually reflect the workings of its inner parts. So a circuit check would follow a current from outside the relay, and then go into the relay itself to power the electromagnet inside. So the blackbox problem is essentially getting that to happen without having to write "wire.connect(relay.electromagnet)" because the "relay.electromagnet" is referencing the inside of the relay. Which I don't want because I want people to be able to use the Relay class without having to know its construction.
The reason I make classes inherit Wire is I also don't want to have to write:
x.connect(wire1)
wire1.connect(y)
y.connect(wire2)
wire2.connect(z)
If I don't have the parts inherit class Wire, then I'll have to insert a wire in between every part. Having all the parts inhertit the class Wire allows me to write the above previous as:
x.connect(y)
y.connect(z)
which I think is still quite intuitive.
weevil,
I'm glad you're enjoying the book!
everyone,
I'm still working on the project, and almost finished with the logic gates. I had to make a lot of adjustments along the way. But I think the logic gates should be done pretty soon, and then it'd just one more small step to the finished program. I hope.
07-20-2012
, 06:19 PM
Why don't you just create a list like [wire, gate, wire, gate, wire, gate]?
07-22-2012
, 12:36 AM
device = Device()
device.construct([switch,relay,lightbulb]) #random example
And then have the finished product pop out. The only thing is that now I'm working on the logic gates and they have multiple inputs. And I can't think of how to put all the parts in a list and feed it into just one function in an intuitive way. But I still really like the idea and I'm still kind of using it.
So, the way I wrote things before you'd have to write x.connect(y). But your post gave me the idea to do it this way: connect(x,y) This way x and y can refer to each other in a much cleaner way. It collapses connect() and connect_back() functions I was using before into one function. It's so simple, but it didn't occur to me at first that I could use a global function.
07-22-2012
, 05:15 AM
Excellent. I asked you why you didn't use a list so you can see where you current techniques are heading, and your current thought process shows you understand. I just wanted to ask you in the most simplistic way possible. Of course, the list isn't really the correct answer, IMO, but it's in the correct direction, and perhaps the final answer will be a list, but probably not in a way you are familiar with, but I'll let you determine the best way.
You are basically creating a program on top of a program, and your program, you are dealing with 4 basic primitives: wire, and-gate, or-gate, inverter, and only one of these primitives have a state you really need to keep track of: wire.
If you make a function like so:
You have a function that takes two arguments (two wires) and returns one value (one wire-state).
Python also keeps state easily:
and via command line:
The challenging part of all of this will be chaining together all your gates, but I think you will figure out that answer once you get all your primitives created. Think of this: if you try to create the top-level stuff first, you are forcing yourself into design decisions on your primitives that may not be easy (or possible) to create, but if you create your primitives first and not worry about chaining them together, you'll at least you can modify the primitives in a way to fit the connections, but I think you'll find you won't have to, because the primitives are simple and straightforward.
You are basically creating a program on top of a program, and your program, you are dealing with 4 basic primitives: wire, and-gate, or-gate, inverter, and only one of these primitives have a state you really need to keep track of: wire.
If you make a function like so:
Code:
def andGate(wire1, wire2):
<your code>
return 1
else: return 0
Python also keeps state easily:
Code:
def wireState(wire):
return wire
wire1 = 1
wire2 = 0
wire1 = wireState(wire1)
wire2 = wireState(wire2)
Code:
>>> wire1 1 >>> wire2 0 >>> wire1 = wireState(9) >>> wire1 9 >>> wire2 0 >>> wire1 9
07-22-2012
, 07:35 AM
Join Date: Sep 2004
Posts: 360
This is cool, I think I'll get me that book too (I want to puzzle with it myself a little).
I feel like doing something similar in Java. If it's appropriate to do so, I could discuss about my way to build the actual circuit (I have something in mind that makes use of a list).
Keep up the good work, it's inspiring.
I feel like doing something similar in Java. If it's appropriate to do so, I could discuss about my way to build the actual circuit (I have something in mind that makes use of a list).
Keep up the good work, it's inspiring.
Last edited by cyberfish; 07-22-2012 at 07:43 AM.
07-22-2012
, 02:05 PM
Whew, so I finally finished the logic gates. I really didn't expect it to get as complicated as it was, and I feel like I've just been running my brain to exhaustion for the last couple days. Debugging was a nightmare and now I can really see the value of good planning and good development practices, It was so satisfying though to see the last logic gate pump out the correct outputs. I really feel like this is the home stretch.
Ok for people who don't know how the logic gates work. Basically you have two binary inputs and one binary output. So for our machine, you have two switches as inputs. They are binary because they're either switched on or off. The output is a lightbulb, which is also either on or off.
Depending on what kind of logic gate it is, your inputs will have different outputs. For example AND gates only turn the light on if both switches are on. OR gates can turn the light on if either one or both switches are on. NAND is short for "Not AND" and the light is on unless both switches are on. And NOR is short for "Not OR" and light is on only when both switches are off. Here's a few pics that show how this would be put together.


and here are some logic tables:

I also needed to build an inverter (can also be called a NOT gate). When a current goes into an inverter, the inverter turns it off. When no current goes into the inverter, the inverter produces a current. This was really easy to make though, because it's the same as a relay with the switch turned to "closed" as default and then have the electromagnet "open" the switch when powered.
So here's the code:
And here is the tester program for the logic gates. A marked a place for where you can put in the logic gates and try them out.
I think the most interesting and difficult part of this project by far is reproducing the properties of a current. Because in real life a wire is always "checking" if there's a complete current or not. But with a program, everything is sequential, and the less steps the better. So you end up having to check for complete circuits at strategic times, so that it behaves like a real electrical device that knows at all times if it's on a complete circuit or not.
But then you have multiple circuits that are connected by relays, and whether certain circuits are going to be complete will depend on whether the circuit connected to it by the relay is complete. Now this made it so that I also needed to know what order to check the circuits in also.
Add to that, wires that can be split and merged. This got really complicated for me really fast. With the split wires you have to check both sides of the split before you know if either side has a charge. Similar problem (but different) with merged wires. Also since I was using recursive loops to check through the connected parts, now I had a problem where everything wasn't called input and output anymore. Now I had input1, input2 and output1, output2 and I couldn't just run the same function through them.
Anyway, I'm pretty happy with some of the solutions I made, although others less so. If you have any thoughts I'd love to hear them. I think the next post will be the final part of this project where I'll explain how to put the logic gates together to do binary addition. Stay tuned!
Ok for people who don't know how the logic gates work. Basically you have two binary inputs and one binary output. So for our machine, you have two switches as inputs. They are binary because they're either switched on or off. The output is a lightbulb, which is also either on or off.
Depending on what kind of logic gate it is, your inputs will have different outputs. For example AND gates only turn the light on if both switches are on. OR gates can turn the light on if either one or both switches are on. NAND is short for "Not AND" and the light is on unless both switches are on. And NOR is short for "Not OR" and light is on only when both switches are off. Here's a few pics that show how this would be put together.


and here are some logic tables:

I also needed to build an inverter (can also be called a NOT gate). When a current goes into an inverter, the inverter turns it off. When no current goes into the inverter, the inverter produces a current. This was really easy to make though, because it's the same as a relay with the switch turned to "closed" as default and then have the electromagnet "open" the switch when powered.
So here's the code:
Code:
# parts: wire, switch, battery plus side (voltage), battery minus side (ground), lightbulb
# electromagnet
circuits = set([])
class Parts(object):
priority = 0
def find_circuits(self):
self.circuit_ins()
self.circuit_outs()
def circuit_ins(self):
if str(self.wire_in) == "plus":
circuits.add((Parts.priority, self.wire_in))
return
if str(self.wire_in) == "em":
Parts.priority += 1
self.wire_in.switch.find_circuits()
if str(self.wire_in) == "switch" and self.wire_in.my_em:
Parts.priority -= 1
self.wire_in.my_em.find_circuits()
self.wire_in.circuit_ins()
Parts.priority = 0
def circuit_outs(self):
if str(self.wire_out) == "minus":
return
if str(self.wire_out) == "em":
Parts.priority += 1
self.wire_out.switch.find_circuits()
if str(self.wire_out) == "switch" and self.wire_out.my_em:
Parts.priority -= 1
self.wire_out.my_em.find_circuits()
self.wire_out.circuit_outs()
Parts.priority = 0
def on_off(self):
for x in sorted(circuits):
if x[1].check_switches() == "complete":
x[1].circuit_on()
elif x[1].check_switches() == "incomplete":
x[1].circuit_off()
def check_switches(self):
if str(self.wire_out) == "switch" and self.wire_out.status == "open":
return "incomplete"
if str(self.wire_out) == "minus":
return "complete"
x = self.wire_out.check_switches()
return x
def circuit_on(self):
self.activate()
if str(self) in ("minus", "merge"):
return
self.wire_out.circuit_on()
def circuit_off(self):
self.deactivate()
if str(self) in ("minus", "merge"):
return
self.wire_out.circuit_off()
def activate(self):
pass
def deactivate(self):
pass
class Wire(Parts):
def connect(self, wire_out):
self.wire_out = wire_out
wire_out.connect_back(self)
def connect_back(self, wire_in):
self.wire_in = wire_in
class SplitWire(Wire):
def __init__(self):
self.wire_out1 = Wire()
self.wire_out2 = Wire()
self.wire_out1.wire_in = self
self.wire_out2.wire_in = self
def check_switches(self):
if not "complete" in (self.wire_out1.check_switches(),
self.wire_out2.check_switches()):
return "incomplete"
return "complete"
def circuit_on(self):
self.wire_out1.circuit_on()
self.wire_out2.circuit_on()
def circuit_off(self):
self.wire_out1.circuit_off()
self.wire_out2.circuit_off()
def circuit_outs(self):
self.priority_old = Parts.priority
self.wire_out1.circuit_outs()
Parts.priority = self.priority_old
self.wire_out2.circuit_outs()
Parts.priority = self.priority_old
def connect(self, wire_out1, wire_out2):
self.wire_out1.connect(wire_out1)
self.wire_out2 .connect(wire_out2)
wire_out1.connect_back(self)
wire_out2.connect_back(self)
class MergeWire(Wire):
def __init__(self):
self.input1 = Wire()
self.input2 = Wire()
self.input1.wire_out = self
self.input2.wire_out = self
self.wire_in1 = self.input1
self.wire_in2 = self.input2
self.charge = []
def __str__(self):
return "merge"
def circuit_ins(self):
self.priority_old = Parts.priority
self.wire_in1.circuit_ins()
Parts.priority = self.priority_old
self.wire_in2.circuit_ins()
Parts.priority = self.priority_old
def activate(self):
self.charge.append("on")
if len(self.charge) > 1:
if "on" in self.charge:
self.wire_out.circuit_on()
elif "on" not in self.charge:
self.wire_out.circuit_off()
del self.charge[:]
def deactivate(self):
self.charge.append("off")
if len(self.charge) > 1:
if "on" in self.charge:
self.wire_out.circuit_on()
elif "on" not in self.charge:
self.wire_out.circuit_off()
del self.charge[:]
class Switch(Wire):
def __init__(self, default = "open"):
self.default = default
self.status = default
self.my_em = None
def __str__(self):
return "switch"
def on(self):
self.status = "closed"
self.find_circuits()
def off(self):
self.status = "open"
self.find_circuits()
class BattPlus(Wire):
def __str__(self):
return "plus"
class BattMinus(Wire):
def __str__(self):
return "minus"
class Lightbulb(Wire):
def __init__(self):
self.status = "light off"
def __str__(self):
return "light"
def activate(self):
self.status = "light on!"
def deactivate(self):
self.status = "light off"
def check(self):
self.on_off()
print self.status
class Electromagnet(Wire):
def __init__(self, switch):
self.switch = switch
switch.my_em = self
def __str__(self):
return "em"
def activate(self):
if self.switch.default == "closed":
self.switch.status = "open"
elif self.switch.default == "open":
self.switch.status = "closed"
def deactivate(self):
self.switch.status = self.switch.default
#
# Relay and Inverter
#
class Relay(Wire):
def __init__(self):
# parts
self.switch = Switch()
self.input2 = self.switch
self.em = Electromagnet(self.switch)
self.input1 = self.em
self.ground = BattMinus()
self.voltage = BattPlus()
#construction
self.em.connect(self.ground)
self.voltage.connect(self.switch)
# fix connections
def connect_back(self, wire_in):
wire_in.wire_out = self.em
self.em.wire_in = wire_in
def connect(self, wire_out):
self.switch.wire_out = wire_out
wire_out.connect_back(self.switch)
class Inverter(Wire):
def __init__(self):
# parts
self.switch = Switch("closed")
self.input2 = self.switch
self.em = Electromagnet(self.switch)
self.input1 = self.em
self.ground = BattMinus()
self.voltage = BattPlus()
#construction
self.em.connect(self.ground)
self.voltage.connect(self.switch)
# fix connections
def connect_back(self, wire_in):
wire_in.wire_out = self.em
self.em.wire_in = wire_in
def connect(self, wire_out):
self.switch.wire_out = wire_out
wire_out.connect_back(self.switch)
#
# Logic Gates: AND, OR, NAND, NOR, XOR
#
class AndGate(Wire):
def __init__(self):
#parts
self.relay1 = Relay()
self.relay2 = Relay()
self.input1 = self.relay1
self.input2 = self.relay2
#construction
self.relay1.connect(self.relay2.input2)
#fix connections
def connect(self, wire_out):
self.relay2.input2.wire_out = wire_out
wire_out.connect_back(self.relay2.input2)
class OrGate(Wire):
def __init__(self):
#parts
self.relay1 = Relay()
self.relay2 = Relay()
self.merge = MergeWire()
self.input1 = self.relay1
self.input2 = self.relay2
#construction
self.relay1.connect(self.merge.input1)
self.relay2.connect(self.merge.input2)
#fix connections
def connect(self, wire_out):
self.merge.wire_out = wire_out
wire_out.connect_back(self.merge)
class NandGate(Wire):
def __init__(self):
#parts
self.invert1 = Inverter()
self.invert2 = Inverter()
self.merge = MergeWire()
self.input1 = self.invert1
self.input2 = self.invert2
#construction
self.invert1.connect(self.merge.input1)
self.invert2.connect(self.merge.input2)
#fix connections
def connect(self, wire_out):
self.merge.wire_out = wire_out
wire_out.connect_back(self.merge)
class NorGate(Wire):
def __init__(self):
#parts
self.invert1 = Inverter()
self.invert2 = Inverter()
self.input1 = self.invert1
self.input2 = self.invert2
#construction
self.invert1.connect(self.invert2.input2)
#fix connections
def connect(self, wire_out):
self.invert2.input2.wire_out = wire_out
wire_out.connect_back(self.invert2.input2)
Code:
# logic gate tester
from parts import *
#parts
voltage1 = BattPlus()
voltage2 = BattPlus()
switch1 = Switch()
switch2 = Switch()
and_gate = AndGate()
nand_gate = NandGate()
or_gate = OrGate()
nor_gate = NorGate()
light = Lightbulb()
ground = BattMinus()
#construction
voltage1.connect(switch1)
voltage2.connect(switch2)
#
# You can replace the logic gate in the next 3 lines to
# whichever logic gate you want.
switch1.connect(and_gate.input1)
switch2.connect(and_gate.input2)
and_gate.connect(light)
light.connect(ground)
#operation
while 1:
print "first switch: enter 1 to switch on, 0 to switch off"
on_off1 = input("> ")
if on_off1 == 1:
switch1.on()
if on_off1 == 0:
switch1.off()
print "second switch: enter 1 to switch on, 0 to switch off"
on_off2 = input("> ")
if on_off2 ==1:
switch2.on()
if on_off2 == 0:
switch2.off()
light.check()
print ""
But then you have multiple circuits that are connected by relays, and whether certain circuits are going to be complete will depend on whether the circuit connected to it by the relay is complete. Now this made it so that I also needed to know what order to check the circuits in also.
Add to that, wires that can be split and merged. This got really complicated for me really fast. With the split wires you have to check both sides of the split before you know if either side has a charge. Similar problem (but different) with merged wires. Also since I was using recursive loops to check through the connected parts, now I had a problem where everything wasn't called input and output anymore. Now I had input1, input2 and output1, output2 and I couldn't just run the same function through them.
Anyway, I'm pretty happy with some of the solutions I made, although others less so. If you have any thoughts I'd love to hear them. I think the next post will be the final part of this project where I'll explain how to put the logic gates together to do binary addition. Stay tuned!
Last edited by WeAreSamurai; 07-22-2012 at 02:33 PM.
Reason: adding pictures
07-23-2012
, 06:44 AM
Join Date: Sep 2004
Posts: 360
I've got a question about how 'simultaneous events' are handled:
Suppose Wire X is split into A and B, so they carry both the same signal. And suppose the two logic gates are EX-NOR.
How is a change in X handled by the logic gates?
I thought you could do it 1 by 1 until some sort of steady-state was reached but in cases like this the result might be different.
Suppose Wire X is split into A and B, so they carry both the same signal. And suppose the two logic gates are EX-NOR.
How is a change in X handled by the logic gates?
I thought you could do it 1 by 1 until some sort of steady-state was reached but in cases like this the result might be different.
07-23-2012
, 08:43 AM
I'm not really an expert on circuits, so I'm not really sure. Did you mean to say EX-NOR, because the gates in the picture are NAND gates, but I think you're assuming that they are EX_NOR. In which case I think the C and D outputs would follow an oscillating pattern, and then I guess when you turn on X, C and D would stabilize at whatever value they were at at the time. If I were programming it I guess I'd have it return a random value, 1 or 0.
That's my guess just looking at it, but I'm not really one to ask.
And if you have anything you want to post feel free!
That's my guess just looking at it, but I'm not really one to ask.
And if you have anything you want to post feel free!
07-23-2012
, 11:19 AM
Join Date: Sep 2004
Posts: 360
Thanks, the gates were indeed EX-NOR (I couldn't find a correct picture).
I will try to build an actual circuit by using 2 lists:
1) objects (logic gates, lights, buttons, ...)
2) objects (wires)
Every wire has an input/output which needs to be attached to an object from the first list. All objects from the first list need wires to be attached to their inputs/outputs. (output to input and input to output)
After this proces I turn the objects from the first list on (from top to bottom), they check input and adjust output.
When an 'action' object from the first list is used (switch, clock, ...): I would adjust the state of the wire attached to the output and iterate through the first list adjusting output-wires until a steady-state was reached.
I think I might have problems with these 'simultaneous events'. But even besides that it's maybe not a correct way to build this (not a good representation of reality, ...).
I will try to build an actual circuit by using 2 lists:
1) objects (logic gates, lights, buttons, ...)
2) objects (wires)
Every wire has an input/output which needs to be attached to an object from the first list. All objects from the first list need wires to be attached to their inputs/outputs. (output to input and input to output)
After this proces I turn the objects from the first list on (from top to bottom), they check input and adjust output.
When an 'action' object from the first list is used (switch, clock, ...): I would adjust the state of the wire attached to the output and iterate through the first list adjusting output-wires until a steady-state was reached.
I think I might have problems with these 'simultaneous events'. But even besides that it's maybe not a correct way to build this (not a good representation of reality, ...).
07-23-2012
, 11:28 PM
I decided to try this in the Python way, but I'm not going to go past where OP is at, so all I have is a framework of primitives here, thus my paltry excuse is that it isn't done. Regardless, Feel free to poke holes in this:
(fwiw, I really hate the repetition of the gates, but I can't seem to ponder a better solution today.)
For connections, I'm going to create a function that creates a list of objects. I've written the prototype for that, which I'll show off at a later time.
(fwiw, I really hate the repetition of the gates, but I can't seem to ponder a better solution today.)
Code:
def objectState(x):
return x
def reverse(x):
if x == 0: return 1
if x == 1: return 0
def logic(x, y):
if x == y: return True
else: return False
def andGate(inputA, inputB, output = 0):
if logic(inputA, inputB) == True:
output = inputA
return output
def orGate(inputA, inputB, output = 1):
if logic(inputA, inputB) == True:
output = inputA
return output
def norGate(inputA, inputB, output = 0):
if logic(inputA, inputB) == True:
output = reverse(inputA)
return output
def nandGate(inputA, inputB, output = 1):
if logic(inputA, inputB) == True:
output = reverse(inputA)
return output
def inverter(inputA, inputB = None):
return reverse(inputA)
def gates(gateType, inputA, inputB = None):
return gateType(inputA, inputB)
def lightBulb(wire):
if objectState(wire) == 1:
print("Light is on!")
else: print("Light is off!")
07-25-2012
, 07:30 PM
Just turbobrowsing (and I have picked up Code for reading on the train, read upto the relay chapter during the last couple of rides...seems like I'll really like the book). I guess I'd model a circuit as graphs with the nodes being gates and links being wires or smth like that. Might try hacking something up later 
Conceptionally this seems extremly similar to the neural networks I coded during university. Each neuron having inputs/outputs stuff "propergating" through the net etc etc. so maybe if you're interested neural networks might be an interesting follow up project
Conceptionally this seems extremly similar to the neural networks I coded during university. Each neuron having inputs/outputs stuff "propergating" through the net etc etc. so maybe if you're interested neural networks might be an interesting follow up project
Last edited by clowntable; 07-25-2012 at 07:35 PM.
07-26-2012
, 04:57 PM
Where is OP? I'm still waiting for the adders and stuff. I decided to work on this a little bit this morning and created the half adder, full adder and ripple adder. The ripple adder allows you the add n-bit characters. Right now, the ripple adder just takes strings because in Python land, 000100001 and [0001110001] are illegal, and if you do 0o0000100010 it will simply spit out a number, which isn't cool. Well, actually this feature makes debugging really easy.
07-26-2012
, 10:23 PM
Hey I'm still here!
I've actually finished everything up to the full adder and hoping to get around to posting them later today.
I think it's really cool that you've decided to actually code this. I'm really curious how it'll turn out because with the lists and tuples I ran into a lot of trouble with referencing. I'm also interested in seeing a model where the pieces actually carry a charge variable, I think cyberfish was taking that approach too. Pretty early on I dropped that model for the current one that looks for complete circuits or incomplete circuits, and then turns every part in that circuit on or off respectively. I'm not sure which would have been better, but I'd be interested to see how certain problems were dealt with.
That does sound really interesting! Glad you're enjoying the book.
Quote:
I decided to try this in the Python way, but I'm not going to go past where OP is at, so all I have is a framework of primitives here, thus my paltry excuse is that it isn't done. Regardless, Feel free to poke holes in this:
(fwiw, I really hate the repetition of the gates, but I can't seem to ponder a better solution today.)
For connections, I'm going to create a function that creates a list of objects. I've written the prototype for that, which I'll show off at a later time.
(fwiw, I really hate the repetition of the gates, but I can't seem to ponder a better solution today.)
For connections, I'm going to create a function that creates a list of objects. I've written the prototype for that, which I'll show off at a later time.
Quote:
Just turbobrowsing (and I have picked up Code for reading on the train, read upto the relay chapter during the last couple of rides...seems like I'll really like the book). I guess I'd model a circuit as graphs with the nodes being gates and links being wires or smth like that. Might try hacking something up later 
Conceptionally this seems extremly similar to the neural networks I coded during university. Each neuron having inputs/outputs stuff "propergating" through the net etc etc. so maybe if you're interested neural networks might be an interesting follow up project
Conceptionally this seems extremly similar to the neural networks I coded during university. Each neuron having inputs/outputs stuff "propergating" through the net etc etc. so maybe if you're interested neural networks might be an interesting follow up project
07-27-2012
, 12:10 AM
Well, once you get yours posted, I'll post mine. Yeah, I can add in some probes to the program to show the wire- and object-states as they progress, but not today. Sort of burned out with the project I'm currently working on.
As for using lists: they'll be available to use for custom circuits and stuff like that but they aren't used in the primitives. They would be abstracted into a function, though of course, someone can use lists directly. I'll try to match the functionality of whatever you post after I see it and play around with it.
My program, at this point, only has the various gates, three adders, and a few helper functions. Still have to make the lightbulb, wires, and the connection function.
As for using lists: they'll be available to use for custom circuits and stuff like that but they aren't used in the primitives. They would be abstracted into a function, though of course, someone can use lists directly. I'll try to match the functionality of whatever you post after I see it and play around with it.
My program, at this point, only has the various gates, three adders, and a few helper functions. Still have to make the lightbulb, wires, and the connection function.
07-27-2012
, 02:07 AM
Ok so here are the half adder and the full adder, and one more logic gate. But before that I'll explain what I'm trying to do with them.
If you don't know how binary numbers work, basically, in binary there's only 0's and 1's. There's no 2 - 9. Normally after 9, you've run out of unique numbers so you go to 10, essentially adding another digit and starting over with 0-9 except with a 1 in front (ie ten through nineteen). In binary you go 0, 1, and then you've run out of unique numbers so you add a new digit and start over. So you go to 10 which represents 2 in our normal decimal system. And from there you can count, 11 (3), 100 (4), 101 (5), 110 (6).
The advantage of using binary numbers is that you can use something like a switch or a light and when it's off or on, you can have that represent 0 or 1. And that's exactly what we're doing in this program. With the logic gates, we're taking in two inputs that we control with two switches, (switch on = 1, switch off = 0) and then returning a single output (light on = 1, light off = 0), who's result will depend on how the logic gates are wired. What we want is to wire them so that the inputs and resulting output will match what we would expect from adding two binary numbers.
For example, here's the simplest case adding two one digit numbers.
0+0=0 - switch1 off and switch2 off results in lightbulb off
1+0=1 - switch1 on and switch2 off results in lightbulb on
0+1=1 - switch1 off and switch2 on results in lightbulb on
1+1=10 - ?
The first three cases are straightforward, but what about 1+1. Well, each logic gate only has one output, so we want two logic gates, one for each digit of the result. So we have:
0+0=00
1+0=01
0+1=01
1+1=10
We want one gate which will output 0 (lightbulb off) in every case except when we have two inputs of 1 (both switches on). That would be the first digit. And then for the second digit we want the output 0 when both inputs are 0 or 1, and output 1 in the other cases. The first digit can be represented by the AND gate. The second digit is a little more complicated, it's represented by the XOR gate. I didn't have the XOR gate last time, but I've written the code and put it at the bottom of my module this time.
Here's what the XOR gate looks like:

So then the "half adder" is just two switches wired to an AND gate and XOR gate:

But it's called a half adder because it doesn't account for "carrying the one". Let's imagine we're adding two, two digit binary numbers.
11
+11
On the right side we just add two 1's and get 10. So we would write down the 0, but then "carry the 1". Now on the left side we're adding 1+1+1, where the last 1 is the carry-in. The full adder then will be able to account for the carry in. This is wired as follows:

So here's the module so far:
And here's the code a wrote up to test the half adder:
And the test for the full adder:
At this point the adding machine is almost finished. The adding machine is basically just a bunch of full adders strung together, or what's called a ripple adder. Here's a picture of that:

All the adding machine really does is connect the switches (at the P's and Q's in the picture) and lightbulbs (at the S's in the picture).
I was hoping to be finished by this post, but I've decided to keep going and create a graphic interface for this program. It's my first time working with a graphics module and I'm pretty happy with the way it's turning out so far. I like the fact that using a GUI retains the feeling of using a machine more as opposed to using a program. I have a lot of it done already so it should be done before the weekend.
If you don't know how binary numbers work, basically, in binary there's only 0's and 1's. There's no 2 - 9. Normally after 9, you've run out of unique numbers so you go to 10, essentially adding another digit and starting over with 0-9 except with a 1 in front (ie ten through nineteen). In binary you go 0, 1, and then you've run out of unique numbers so you add a new digit and start over. So you go to 10 which represents 2 in our normal decimal system. And from there you can count, 11 (3), 100 (4), 101 (5), 110 (6).
The advantage of using binary numbers is that you can use something like a switch or a light and when it's off or on, you can have that represent 0 or 1. And that's exactly what we're doing in this program. With the logic gates, we're taking in two inputs that we control with two switches, (switch on = 1, switch off = 0) and then returning a single output (light on = 1, light off = 0), who's result will depend on how the logic gates are wired. What we want is to wire them so that the inputs and resulting output will match what we would expect from adding two binary numbers.
For example, here's the simplest case adding two one digit numbers.
0+0=0 - switch1 off and switch2 off results in lightbulb off
1+0=1 - switch1 on and switch2 off results in lightbulb on
0+1=1 - switch1 off and switch2 on results in lightbulb on
1+1=10 - ?
The first three cases are straightforward, but what about 1+1. Well, each logic gate only has one output, so we want two logic gates, one for each digit of the result. So we have:
0+0=00
1+0=01
0+1=01
1+1=10
We want one gate which will output 0 (lightbulb off) in every case except when we have two inputs of 1 (both switches on). That would be the first digit. And then for the second digit we want the output 0 when both inputs are 0 or 1, and output 1 in the other cases. The first digit can be represented by the AND gate. The second digit is a little more complicated, it's represented by the XOR gate. I didn't have the XOR gate last time, but I've written the code and put it at the bottom of my module this time.
Here's what the XOR gate looks like:

So then the "half adder" is just two switches wired to an AND gate and XOR gate:

But it's called a half adder because it doesn't account for "carrying the one". Let's imagine we're adding two, two digit binary numbers.
11
+11
On the right side we just add two 1's and get 10. So we would write down the 0, but then "carry the 1". Now on the left side we're adding 1+1+1, where the last 1 is the carry-in. The full adder then will be able to account for the carry in. This is wired as follows:

So here's the module so far:
Code:
# parts: wire, switch, battery plus side (voltage), battery minus side (ground),
# lightbulb, electromagnet
circuits = set([])
class Parts(object):
priority = 0
def find_circuits(self):
self.circuit_ins()
self.circuit_outs()
def circuit_ins(self):
if str(self.wire_in) == "plus":
circuits.add((Parts.priority, self.wire_in))
return
if str(self.wire_in) == "em":
Parts.priority += 1
self.wire_in.switch.find_circuits()
if str(self.wire_in) == "switch" and self.wire_in.my_em:
Parts.priority -= 1
self.wire_in.my_em.find_circuits()
self.wire_in.circuit_ins()
Parts.priority = 0
def circuit_outs(self):
if str(self.wire_out) == "minus":
return
if str(self.wire_out) == "em":
Parts.priority += 1
self.wire_out.switch.find_circuits()
if str(self.wire_out) == "switch" and self.wire_out.my_em:
Parts.priority -= 1
self.wire_out.my_em.find_circuits()
self.wire_out.circuit_outs()
Parts.priority = 0
def on_off(self):
for x in sorted(circuits):
if x[1].check_switches() == "complete":
x[1].circuit_on()
elif x[1].check_switches() == "incomplete":
x[1].circuit_off()
def check_switches(self):
if str(self.wire_out) == "switch" and self.wire_out.status == "open":
return "incomplete"
if str(self.wire_out) == "minus":
return "complete"
x = self.wire_out.check_switches()
return x
def circuit_on(self):
self.activate()
if str(self) in ("minus", "merge"):
return
self.wire_out.circuit_on()
def circuit_off(self):
self.deactivate()
if str(self) in ("minus", "merge"):
return
self.wire_out.circuit_off()
def activate(self):
pass
def deactivate(self):
pass
class Wire(Parts):
def connect(self, wire_out):
self.wire_out = wire_out
wire_out.connect_back(self)
def connect_back(self, wire_in):
self.wire_in = wire_in
class SplitWire(Wire):
def __init__(self):
self.wire_out1 = Wire()
self.wire_out2 = Wire()
self.wire_out1.wire_in = self
self.wire_out2.wire_in = self
def check_switches(self):
if not "complete" in (self.wire_out1.check_switches(),
self.wire_out2.check_switches()):
return "incomplete"
return "complete"
def circuit_on(self):
self.wire_out1.circuit_on()
self.wire_out2.circuit_on()
def circuit_off(self):
self.wire_out1.circuit_off()
self.wire_out2.circuit_off()
def circuit_outs(self):
self.priority_old = Parts.priority
self.wire_out1.circuit_outs()
Parts.priority = self.priority_old
self.wire_out2.circuit_outs()
Parts.priority = self.priority_old
def connect(self, wire_out1, wire_out2):
self.wire_out1.connect(wire_out1)
self.wire_out2 .connect(wire_out2)
wire_out1.connect_back(self)
wire_out2.connect_back(self)
class MergeWire(Wire):
def __init__(self):
self.input1 = Wire()
self.input2 = Wire()
self.input1.wire_out = self
self.input2.wire_out = self
self.wire_in1 = self.input1
self.wire_in2 = self.input2
self.charge = []
def __str__(self):
return "merge"
def circuit_ins(self):
self.priority_old = Parts.priority
self.wire_in1.circuit_ins()
Parts.priority = self.priority_old
self.wire_in2.circuit_ins()
Parts.priority = self.priority_old
def activate(self):
self.charge.append("on")
if len(self.charge) > 1:
if "on" in self.charge:
self.wire_out.circuit_on()
elif "on" not in self.charge:
self.wire_out.circuit_off()
del self.charge[:]
def deactivate(self):
self.charge.append("off")
if len(self.charge) > 1:
if "on" in self.charge:
self.wire_out.circuit_on()
elif "on" not in self.charge:
self.wire_out.circuit_off()
del self.charge[:]
class BattPlus(Wire):
def __str__(self):
return "plus"
class BattMinus(Wire):
def __str__(self):
return "minus"
class Electromagnet(Wire):
def __init__(self, switch):
self.switch = switch
switch.my_em = self
def __str__(self):
return "em"
def activate(self):
if self.switch.default == "closed":
self.switch.status = "open"
elif self.switch.default == "open":
self.switch.status = "closed"
def deactivate(self):
self.switch.status = self.switch.default
class Lightbulb(Wire):
def __init__(self):
self.status = "light off"
def __str__(self):
return "light"
def activate(self):
self.status = "light on!"
def deactivate(self):
self.status = "light off"
def check(self):
self.on_off()
return self.status
class Switch(Wire):
def __init__(self, default = "open"):
self.default = default
self.status = default
self.my_em = None
def __str__(self):
return "switch"
def on(self):
self.status = "closed"
self.find_circuits()
def off(self):
self.status = "open"
self.find_circuits()
#
# Relay and Inverter
#
class Relay(Wire):
def __init__(self):
# parts
self.switch = Switch()
self.input2 = self.switch
self.em = Electromagnet(self.switch)
self.input1 = self.em
self.ground = BattMinus()
self.voltage = BattPlus()
#construction
self.em.connect(self.ground)
self.voltage.connect(self.switch)
# fix connections
def connect_back(self, wire_in):
wire_in.wire_out = self.em
self.em.wire_in = wire_in
def connect(self, wire_out):
self.switch.connect(wire_out)
class Inverter(Wire):
def __init__(self):
# parts
self.switch = Switch("closed")
self.input2 = self.switch
self.em = Electromagnet(self.switch)
self.input1 = self.em
self.ground = BattMinus()
self.voltage = BattPlus()
#construction
self.em.connect(self.ground)
self.voltage.connect(self.switch)
# fix connections
def connect_back(self, wire_in):
wire_in.wire_out = self.em
self.em.wire_in = wire_in
def connect(self, wire_out):
self.switch.connect(wire_out)
#
# Logic Gates: AND, OR, NAND, NOR, XOR
#
class AndGate(Wire):
def __init__(self):
#parts
self.relay1 = Relay()
self.relay2 = Relay()
self.input1 = self.relay1
self.input2 = self.relay2
#construction
self.relay1.connect(self.relay2.input2)
#fix connections
def connect(self, wire_out):
self.relay2.connect(wire_out)
class OrGate(Wire):
def __init__(self):
#parts
self.relay1 = Relay()
self.relay2 = Relay()
self.merge = MergeWire()
self.input1 = self.relay1
self.input2 = self.relay2
#construction
self.relay1.connect(self.merge.input1)
self.relay2.connect(self.merge.input2)
#fix connections
def connect(self, wire_out):
self.merge.connect(wire_out)
class NandGate(Wire):
def __init__(self):
#parts
self.invert1 = Inverter()
self.invert2 = Inverter()
self.merge = MergeWire()
self.input1 = self.invert1
self.input2 = self.invert2
#construction
self.invert1.connect(self.merge.input1)
self.invert2.connect(self.merge.input2)
#fix connections
def connect(self, wire_out):
self.merge.connect(wire_out)
class NorGate(Wire):
def __init__(self):
#parts
self.invert1 = Inverter()
self.invert2 = Inverter()
self.input1 = self.invert1
self.input2 = self.invert2
#construction
self.invert1.connect(self.invert2.input2)
#fix connections
def connect(self, wire_out):
self.invert2.connect(wire_out)
class XorGate(Wire):
def __init__(self):
#parts
self.split1 = SplitWire()
self.split2 = SplitWire()
self.or_gate = OrGate()
self.nand_gate = NandGate()
self.and_gate = AndGate()
self.input1 = self.split1
self.input2 = self.split2
#construction
self.split1.connect(self.or_gate.input1, self.nand_gate.input1)
self.split2.connect(self.or_gate.input2, self.nand_gate.input2)
self.or_gate.connect(self.and_gate.input1)
self.nand_gate.connect(self.and_gate.input2)
#fix connections
def connect(self, wire_out):
self.and_gate.connect(wire_out)
#
# Half Adder and Full Adder
#
class HalfAdder(Wire):
def __init__(self):
# parts
self.split1 = SplitWire()
self.split2 = SplitWire()
self.xor_gate = XorGate()
self.and_gate = AndGate()
self.input1 = self.split1
self.input2 = self.split2
self.output1 = self.xor_gate
self.output2 = self.and_gate
# construction
self.split1.connect(self.xor_gate.input1, self.and_gate.input1)
self.split2.connect(self.xor_gate.input2, self.and_gate.input2)
class FullAdder(Wire):
def __init__(self):
# parts
self.half_adder1 = HalfAdder()
self.half_adder2 = HalfAdder()
self.or_gate = OrGate()
self.input1 = self.half_adder1.input1
self.input2 = self.half_adder1.input2
self.input3 = self.half_adder2.input1
self.carry_in = self.input3
self.output1 = self.half_adder2.output1
self.sum_out = self.output1
self.output2 = self.or_gate
self.carry_out = self.output2
# construction
self.half_adder1.output1.connect(self.half_adder2.input2)
self.half_adder1.output2.connect(self.or_gate.input2)
self.half_adder2.output2.connect(self.or_gate.input1)
Code:
# half adder tester
from parts import *
# parts
v1 = BattPlus()
v2 = BattPlus()
s1 = Switch()
s2 = Switch()
light1 = Lightbulb()
light2 = Lightbulb()
g1 = BattMinus()
g2 = BattMinus()
half_adder = HalfAdder()
# construction
v1.connect(s1)
v2.connect(s2)
s1.connect(half_adder.input1)
s2.connect(half_adder.input2)
half_adder.output2.connect(light1)
half_adder.output1.connect(light2)
light1.connect(g1)
light2.connect(g2)
#operation
while 1:
print "first switch: enter 1 to switch on, 0 to switch off"
on_off1 = input("> ")
if on_off1 == 1:
s1.on()
if on_off1 == 0:
s1.off()
print "second switch: enter 1 to switch on, 0 to switch off"
on_off2 = input("> ")
if on_off2 ==1:
s2.on()
if on_off2 == 0:
s2.off()
print light1.check(), light2.check()
print ""
Code:
# full adder tester
from parts import *
# parts
v1 = BattPlus()
v2 = BattPlus()
v3 = BattPlus()
s1 = Switch()
s2 = Switch()
s3 = Switch()
light1 = Lightbulb()
light2 = Lightbulb()
g1 = BattMinus()
g2 = BattMinus()
full_adder = FullAdder()
# construction
v1.connect(s1)
v2.connect(s2)
v3.connect(s3)
s1.connect(full_adder.input1)
s2.connect(full_adder.input2)
s3.connect(full_adder.input3)
full_adder.output2.connect(light1)
full_adder.output1.connect(light2)
light1.connect(g1)
light2.connect(g2)
# operation
while 1:
print "first switch: enter 1 to switch on, 0 to switch off"
on_off1 = input("> ")
if on_off1 == 1:
s1.on()
if on_off1 == 0:
s1.off()
print "second switch: enter 1 to switch on, 0 to switch off"
on_off2 = input("> ")
if on_off2 ==1:
s2.on()
if on_off2 == 0:
s2.off()
print "third switch: enter 1 to switch on, 0 to switch off"
on_off3 = input("> ")
if on_off3 ==1:
s3.on()
if on_off3 == 0:
s3.off()
print light1.check(), light2.check()
print ""

All the adding machine really does is connect the switches (at the P's and Q's in the picture) and lightbulbs (at the S's in the picture).
I was hoping to be finished by this post, but I've decided to keep going and create a graphic interface for this program. It's my first time working with a graphics module and I'm pretty happy with the way it's turning out so far. I like the fact that using a GUI retains the feeling of using a machine more as opposed to using a program. I have a lot of it done already so it should be done before the weekend.
07-27-2012
, 05:28 PM
When it the light supposed to turn on? Or can you give me an explanation of what is happening here?
Test the adder:
Code:
>>> first switch: enter 1 to switch on, 0 to switch off > 1 second switch: enter 1 to switch on, 0 to switch off > 1 light off light off first switch: enter 1 to switch on, 0 to switch off > 0 second switch: enter 1 to switch on, 0 to switch off > 0 light off light off first switch: enter 1 to switch on, 0 to switch off > 1 second switch: enter 1 to switch on, 0 to switch off > 0 light off light off first switch: enter 1 to switch on, 0 to switch off > 0 second switch: enter 1 to switch on, 0 to switch off > 1 light off light off
Code:
first switch: enter 1 to switch on, 0 to switch off > 1 second switch: enter 1 to switch on, 0 to switch off > 1 third switch: enter 1 to switch on, 0 to switch off > 1 light off light off first switch: enter 1 to switch on, 0 to switch off > 0 second switch: enter 1 to switch on, 0 to switch off > 0 third switch: enter 1 to switch on, 0 to switch off > 0 light off light off first switch: enter 1 to switch on, 0 to switch off > 1 second switch: enter 1 to switch on, 0 to switch off > 0 third switch: enter 1 to switch on, 0 to switch off > 1 light off light off first switch: enter 1 to switch on, 0 to switch off > 0 second switch: enter 1 to switch on, 0 to switch off > 1 third switch: enter 1 to switch on, 0 to switch off > 0 light off light off
07-28-2012
, 10:03 PM
Code:
def reverse(x):
if x == 0: return 1
if x == 1: return 0
def logic(x, y, z):
if x == y: return x
else: return z
def andGate(inputA, inputB, output = 0):
return logic(inputA, inputB, output)
def orGate(inputA, inputB, output = 1):
return logic(inputA, inputB, output)
def norGate(inputA, inputB, output = 1):
return reverse(logic(inputA, inputB, output))
def nandGate(inputA, inputB, output = 0):
return reverse(logic(inputA, inputB, output))
def inverter(inputA, output = None):
return reverse(inputA)
def halfAdder(wire1, wire2):
h1 = andGate(wire1,wire2)
return andGate(orGate(wire1,wire2), inverter(h1)), h1
def fullAdder(wire1, wire2, cin):
h1 = halfAdder(wire2, cin)
h2 = halfAdder(wire1, h1[0])
cout = orGate(h1[1], h2[1])
return h2[0], cout
def rippleAdder(num1, num2, sumWires = '', cin = 0):
if len(num1) != len(num2):
return print('your objects are not the same length\n', len(num1), len(num2))
if len(num1) == 0:
return sumWires, cin
else:
h1 = int(num1[0])
h2 = int(num2[0])
s, c = fullAdder(h1, h2, cin)
sumWires+=str(s)
return rippleAdder(num1[1:], num2[1:], sumWires, c)
def lightbulb(wire):
for i in wire:
if i == 1: print('Light On!')
else: print('Light Off!')
def start():
gateDict = {1:andGate, 2:orGate, 3:nandGate, 4:norGate, 5:inverter}
adderDict = {1:halfAdder, 2:fullAdder, 3:rippleAdder}
chooseType = int(input('Press 1 for Gate, Press 2 for Adder :'))
if chooseType == 1:
chooseGate = int(input('''
Press 1 for And Gate
Press 2 for Or Gate
Press 3 for Nand Gate
Press 4 for Nor Gate
Press 5 for Inverter
>>>'''))
if chooseGate == 1 or chooseGate == 2 or chooseGate == 3 or chooseGate == 4:
onOff1 = int(input('press 0 to turn off wire1, press 1 to turn on wire1'))
onOff2 = int(input('press 0 to turn off wire2, press 1 to turn on wire2'))
lightbulb(gateDict[chooseGate](onOff1, onOff2))
elif chooseGate == 5:
onOff1 = int(input('press 0 to turn off wire1, press 1 to turn on wire1'))
lightbulb(gateDict[chooseGate](onOff1))
if chooseType == 2:
chooseAdder = int(input('''
Press 1 for Half Adder
Press 2 for Full Adder
Press 3 for Ripple Adder
>>>'''))
if chooseAdder == 1:
onOff1 = int(input('press 0 to turn off wire1, press 1 to turn on wire1'))
onOff2 = int(input('press 0 to turn off wire2, press 1 to turn on wire2'))
lightbulb(adderDict[chooseAdder](onOff1, onOff2))
if chooseAdder == 2:
onOff1 = int(input('press 0 to turn off wire1, press 1 to turn on wire1'))
onOff2 = int(input('press 0 to turn off wire2, press 1 to turn on wire2'))
onOff3 = int(input('press 0 to turn off carrier, press 1 to turn on carrier'))
lightbulb(adderDict[chooseAdder](onOff1, onOff2, onOff3))
if chooseAdder == 3:
pass
start()
I think it's interesting that WeAreSamurai and I have very different approaches to the problem set. I don't know which is better or which is worse. As I said, I already did something like this, and that was from a book that is hard-core functional programming. Most of that translates okay to Python, but there's some things to work around.
I know, the start() function could use some improvement, but I think that you can see at least how I plan to tie things together.
The Ripple Adder works just as expected. I used this simulation to test against. The ripple adder in the simulation does only 8-bit. If you do test mine against his, remember that his reads from right to left and mine reads from left to right. My Ripple Adder is supposed to work with n-bits, so if you really feel inspired to run 128 bits, have at it, but I can't guarantee the results.
To use the Ripple Adder, comment out the start() at the bottom, run the program and go to your command prompt:
Code:
>>> rippleAdder('0011', '1010')
('1000', 1)
>>> rippleAdder('0011', '1010', cin = 1)
('0100', 1)
>>>
So, aside from the ripple adder, I think I haven't went past WeAreSamurai.
Feedback is used for internal purposes. LEARN MORE
Powered by:
Hand2Note
Copyright ©2008-2022, Hand2Note Interactive LTD