SystemFreak is written in Python and Tk. It is hosted on Sourceforge, and code is managed using CVS.
All code is thoroughly documented using pydoc. Typing "pydoc modulename" on the command-line gives a nice overview over any module in the project.
All the modules are written using TDD. That is, first write the test, then write the code. Pyunit is used for testing. TDD not only reduces bugs, it is also more effective and more fun!
SystemFreak is copyrighted by me, Anders Schau Knatten. It is released under the GNU General Public License (GPL). SystemFreak should not use any copyrighted material whatsoever, unless it is licenced to us (by GPL or another licence). This goes for code, graphics, anything.
See the main documentation for an introduction to the game, and the System Wright's Guide for instructions on how to write your own systems. You do not have to be a developer to write your own systems, but you are encouraged to send them to me by email so I can include them in future releases. That is, the systems you write. Not the developers. Developers should be shipped in a cage to my appartment in Oslo.
I will describe all the modules and their relationship here, in what I feel is the most pedagogical order. To see detailed documentation for a module, use pydoc. See below for a UML-diagram.
This is the main excecutable. For now it just launches the tk-interface (playgui.py), but in the future it could launch an ncurses-interface, an OpenGL-interface, and what not.
This is just the GUI for the game. No game-logic is in here. playgui.py creates a game-object, and uses this to get information about the game.
This is the core of the game. The module takes care of everything that happens in the game. It has methods for trying to play a card, setting up a game, and so forth. It does not care about user-interfaces, and its methods can be called from any type of interface. Ping some guys in Bergen Linux User Group, and I am sure we can use carrier pigeons as a UI.
The player-module takes care of a player. At the moment we only have single-player-support, but the game-module still has an array of one player. I want to add multiplayer-support in the future. The player-module takes care of what cards the player has on her hand, how many turns she has used etc.
This is a pretty simple module. It takes care of a card. It has methods to retrieve information about the value, suite, color, if it is a face card, etc. I have also overloaded a bunch of operators, in order to be able to compare card-values in an easyer way (e.g. "if card > 10" ). It also has an __str__-method that outputs a textual representation of the card.
A deck is a collection of cards. It implements a list of cards, and has methods to draw a card, insert cards and shuffle the deck.
Now it is getting interesting. This module takes care of the system, probably what you might call the most important thing in the game. A system is a set of rules dictating what cards can be played at a given time. The system-module looks at a card and the table, consults all the rules in the system, and determines if a card is playable or not. It is also responsible for loading in a system from file at startup. Consult the System Wright's Guide for more information on the syntax and possibilites of systems. When asked if a card is playable, the system asks all its rules (see the rule-module) if the card is playable. If noone objects, it allows the card to be played.
A system is built from rules. This module takes care of a single rule, and a system will typically consist of a list of rules. A rule is built by a series of conditions (e.g. "the previous card is black, higher than 7 and odd") and one requirement (e.g. "the card to be played must be red") (this is not actual syntax). When asked if a card is playable, the rule-module consults its list of conditions, and its requirement. If all the conditions match, the requirement must also match if the rule is to say "go ahead" to its system.
As said, a rule can consist of a series of conditions. The condition-module only knows about one conditon. Everytime the rule-module is asked if a card is playable, it will ask all its condition-objects. In the example above, there will be three condition-objects. The condition-module will look at the cards on the table, and return true if it's condition is met.
As opposed to condition, each rule can only have one requirement. (If you need more, just use more rules.) When a rule finds that all its conditions are met, it asks the requirement-module if the requirement is met. The requirement-module then takes a look at the card which the player tries to play, and tells the rule-module wether it meets the requirement or not.
The parserlib is quite a boring story. It just contains some common functionality used by the condition-module and the requirement-module, which I didn't want to have in separate places. Use pydoc for more info, it really isn't important in the big picture.
This modules contains the grammar used in the rule-regexes.
UML-diagrams can actually be quite nice to look at when trying to get an overview of the system. So guess what, here it is. You will notice that the diagram only deals with the core system, the GUI-module is omitted.
Valid xhtml 1.0 strict and css