Simulation
A stroll through the circuit simulation code
The circuit simulator is the lowest-level piece of Shock Circuit. It's responsible for the gameplay of the game in a way similar to the physics engine of an FPS; in both cases, the basic gameplay is structured around this engine, even though the engine's work is only indirectly visible to the player.
To begin with, we must give credit where credit was due. The circuit simulator in Shock Circuit is actually a port of Paul Falstad's Circuit Simulator applet, an excellent program that you should spend a few minutes right now playing around with.
Done? Okay, let's get to business. Open up circuitsim.py in an editor and take a look around. It's organized into a few classes like so:
- CircuitSim is the most important class. An instance of this is an instance of the simulation, and it's in charge of tracking all the various circuit elements that are active in the game.
- CircuitNode, CircuitNodeLink, and RowInfo are all utility classes used internally by CircuitSim. You can safely ignore them unless you are really doing deep changes to the simulation.
- CircuitElm is the base class for an element, which is how we describe anything sitting on the circuit board and potentially conducting electricity (wires, batteries, resistors, etc). The other Elm classes derive from this, and supply their own methods that define both how that type of element behaves, and how it is drawn.
As a general rule, it's a bad idea to mix drawing and simulation code as we've done in circuitsim.py. It really ought to contain only actual simulation code, and leave the drawing of circuit elements to some other independent part of the game. However, when on a deadline, you can't always afford to do things nicely; sometimes it just needs to work right away.
The most important method in circuitsim.py is CircuitSim's update method. This method is called once per frame by the game code in gamemain.py, and is in charge of changing the logical state of the circuit. In other words, it updates its internal idea of how much current, voltage, and so on is in each part of the circuit to act as though some time has passed, but doesn't actually display those changes onscreen. That doesn't happen until CircuitSim's draw method is called, which makes no change to the circuit but renders all the circuit's elements, in their current state, to the screen, over whatever is already there.
CircuitSim does a great deal of caching between each call to update, only recalculating things which have changed since the last call. For example, it is assumed that cirucit elements will all stay exactly where they currently are unless the simulation is explicitly told otherwise. In the robot code, when the robot picks up or puts down any element, it sets analyzeFlag in the CircuitSim to True, which causes it to re-evaluate its assumptions on the next update. If it had to re-do all of those calculations from scratch every frame, as opposed to only when it was necessary, the program would run about 10 times slower! This sort of strategy is an important part of nearly any physics engine; only recalculate the things you need to, so that the game can devote more of its time to keeping up a nice smooth framerate.
One way to gain a better understanding of unfamiliar code is to try and implement a change. Here are a few ideas you could try, if you're feeling motivated. Listed in order of increasing difficulty:
- Show the voltage change within the battery. Notice how the voltage (represented in the game as a green overlay, drops as electricity flows across a resistor and back to the battery? A similar process is actually happening inside the battery as well, only in reverse, since the battery is addding power to the circuit, while the resistor is taking it away. However, there is no green mask drawn on the battery; this is because it obscures the image of the battery. But for the sake of completeness, suppose you want to re-add that voltage display so you can see the battery doing its job. This is a simple fix; just look at how the end of draw method in VoltageElm differs from the same method in ResistorElm.
- Change the direction of current. Electric current is represented in the game in the "conventional" manner, which means that the little dots are drawn as though electricity had a positive charge. This is a nice way of thinking about things for physicists, but it's not what's really going on; electrons have a negative charge, and in that sense, those little dots should actually be travelling in the other direction. See if you can implement this change; it's a fairly easy one, to be made in the drawCurrent method of the CircuitElm class. Making the code change there will, handily, change this behavior in every element.
- For the motivated: Add a lightbulb element. This is a convenient element to add because, within the simulation, a lightbulb is very similar to a resistor. Copy and pase the ResistorElm class into a LightBulbElm class. Leave the initialization code and simulation-related code (for example, everything related to the stamp functions) alone, but redo the drawing functions so that instead of the same resistor image being drawn, you draw a lightbulb image (that you'll have to create), and perhaps a yellow glow with intensity that varies as the bulb receives more or less current. You can find out the amount of current running through the bulb at any time by just checking self.current.

