Reversi, also known as Othello, is a board game. Odummo is named so because I want to include the option of an AI in it, I doubt the AI will be very good as it’s my first try, hence it’s a dummy. Odummo!
This series of posts will follow the creation of a game of Othello. It’ll be designed to work within Pyramid but as little of the code as possible will use the framework to make it as easy as possible to use elsewhere. I will assume an understanding of Python and a rough understanding of Pyramid. If you’ve use SQLAlchemy before then excellent, if not it should be hopefully quite self-explanatory.
I’m no expert so please feel free to critique my work.
All we’re doing at this stage is setting up the scaffolding and framework for our program. We’ll look at what different parts of the program will do and how it will all fit together. The first commit made is on my GitHub
Our project is broken into a few main areas.
/lib holds modules with functions useful for running the game. It has two placeholder files for now.
/templates holds all the .pt template files. If you’re using a different setup you’ll probably want to tweak these somewhat. It’s currently empty.
/tests will be holding all our testing files for our unit and functional tests. Currently it’s empty.
/views will hold our view related files. These are the files that will be most tied into the Pyramid framework and thus I will try to place as little code in them as possible. It currently has two placeholder files.
/config.py is a file used to store handlers for things specific to the application as a whole. I know how my user objects work but I’m not sure how other people’s might. In this case it’s also got a handler for a default template layout.
/models.py is the file holding the SQLAlchemy models. We’ll come back to this shortly.
/tables.sql holds the SQL queries required to create our tables. I use Postgres myself however they’re simple enough it should be easy to convert to any other database type.
Building our models
Relevant files: /models.py
I’m starting this project by looking at the objects I’ll need to be working with. From this starting point I can then design how the paths of execution can work and the program runs. I’ve designed three different objects: User profiles, Odummo Games and Game moves.
The first model defined is OdummoProfile. We’re making the assumption our application already has a users table (called “users”) and that we can pull certain information from that using our config.py file. Thus we don’t have an ID as a serial (auto-increment for MySQL), instead we just link it straight to the users table.
preferred_colour – We’ll be using this to allow the player to decide if they’re rather play as black or white. If they’ve got several games on the go then they don’t want to have to check what colour they are every time.
matchmaking – Not everybody will want to take part in matchmaking, we’ll default it to no and then the eager players can enable it and have games created for them.
last_move – This will be used in conjuction with Matchmaking to work out if they are eligible for a match. We could do a sub-query on the moves table but I found this to be a much simpler solution.
wins, losses – Same principle here as with the last_move, we want to track the win/loss ratio without having to manually add up a load of rows. If we’re doing it for a single player then it’s not a big deal but when matchmaking we want to have the win/loss ration nice and easy to get to.
The purpose of the OdummoProfile object is mostly just to track settings and scores for our players.
Next up we’ve got the OdummoGame object. As suggested by the name, it will be the object used to identify a given game of Odummo. I’ll cover the various columns and their purpose.
turn – While we can count the number of moves a given game has it’s easier to increment this by one rather than running a sub-query. This is the same thinking as from the OdummoProfile table. It is breaking a rule of database normalisation makes it easier to have inconsistent data as a result.
started – Since a game starts with 0 moves we have to have this if we want to know how long it was since the last move. We could later remove this by saying a game is never actually created until a move is made.
player1, player2 – Tracking the two players in the game, both are foreign keys to the users table though we could just as easily use the profiles table.
winner – As suggested it tracks the winner, when Null it means the game is still in progress meaning we can easily find games still in progress.
current_state – We will never need to reference an individual square on the board without needing to do so in the context of looking at the whole board, thus we can store the board as a 64 character string. Spaces represent empty tiles and then 1 and 2 can represent players 1 and 2.
rematch, source – We plan to have the ability to rematch people and might want to track where the game came from and where it’s going. I’ve included them because I used them in Wordy2 and UltimateOX. I might remove them later as a refactor if they’re not of use.
Lastly we have the OdummoMove objects. These each represent a move made by a player on a game. We thus start by tracking the game and player in question with relevant foreign keys.
move – This will track the square number we’re placing a tile in. 0 is the top left and 63 the bottom right. We’ll be counting left to right then down so the top right corner will be covered as tile 7
timestamp – Simply so we can determine the order of the moves made and when they were made (e.g. is this game abandoned?)
Next post will cover the views.