In the previous part I wrote on how I’ve leant the basics of IronPython programming. In this post I will show the first lines I wrote as part of the project I decided to write in order to learn IronPython.
Before I div into the code I’d like to take a moment to explain about the project I’m coding.
I’ve wanted to refresh some of the materials I’ve learnt at university in “Introduction to AI” course and for my IronPython project I choose to use Minimax algorithm. In case you’ve never heard of Minimax before - don’t worry, basically it’s an algorithm to choose the preferred move in a zero sum game of two players.
I’ll dedicate a post about it in the future but for now I’d like to cover the “prerequisite” for the algorithm – a working board game implementation.
Because I needed a simple board game with clear rules I choose to implement Mancala.
What is Mancala?
Mancala is a board game played by two players. This is what my Mancala board looks like:
Playing Mancala is easy:
- The board has two stores (also called Mancala) one for each player and the goal of the game is to collect as many stones as possible.
remark – if you don’t see the stores in the board above don’t worry my board doesn’t have any. instead I keep the seeds/stones won at the sides of the board.
- Each player has six pots he can play from (the ones closer to his side) in the board above my side is the six lower pots.
- Players alternate turns, in his turn a player choose one of his pots, takes all of the stones from that pot and places them one by one on every pot he passes in counter clockwise order. When the player passes his store (Mancala) he places a stone there as well.
If the last stone placed in the player’s store he gets another turn.
If the last stone is placed in an empty pot he captures the stones on the opposite pot and places them in his store along with the capturing stone.
And finally the game continues until one of the players clears all of his side (and cannot “move”).
Classes of the game
- Board – has most of the game logic along with the board representation
- Store – represent the player’s stores and has a counter for the number of seeds in store
- Pot – represent a simple pot along with the amount of seeds in it
- MancalaException – game specific exception
Implementing MancalaException is simple, just define a new type that inherits from the Exception class:
This how I would have implemented a similar class in C#:
No big difference between there - both the implementations are short and to the point. Notice that I’ve use pass after the class definition tells IronPython not to expect anything more from the class.
Both Store and Pot classes are similarly implemented:
In both classes the “cost” of creating a simple class is notably less then what we’ve used to from C#/VB.
Both classes has a simple “constructor” - Python’s __init__, __init__ is one of Python’s special methods - For a full list of other special method used in Python (and IronPython) see Python Magic Methods Reference courtesy of Michael Foord.
Notice how we pass self to the class methods. Python uses the 1st parameter to access the current instance. In this example I’ve used self to set the initial number of seeds (4 in each pot and 0 in each store).
Because IronPython is a dynamic language I do not need to declare the “seeds” field before using it, in fact if I would have declared it in the class definition it would have been a static field which would have been the same for all instances for the class – this took some getting used to.
The Board class
Board is the main class of our game. This class represents the game’s board and has the (very simple) game logic.
The Board class has one major method, and several small “helper” methods.
Let’s start with the constructor:
Because Python does not declare class fields before they’re used I’ve used the this method to create the board’s fields:
- a list that contains two stores (line 3). No new needed to create a new class just write it down
- a list that has two lists of 6 pots each (4-10)
- set the current player turn to 0.
Python does not have the same for loops I’ve been used to have in other languages, in fact Python’s for is more similar to the foreach loop of C#/VB so in order to create a list of N pots I’ve used a trick:
- Create a list of N objects using the range keyword.
- Iterate on each object and do something.
The added bonus is the list created have N elements 0 to N-1 so I can implement a proper for loop this way
In this example I use for and range to iterate of a list of 6 elements and create a new pot class and add it to a list (line 9/10).
The play method drives the game. It contains the main game logic and is responsible to act a single player turn:
Like all other the other methods it has the self parameter that represent the current instance (similar to this/me) and it also receives the pot that the player choose to move.
In line 4-5 I wrote simple check to make sure the player choose a valid pot (one that has seeds in it). Raising exception in Python is very similar to what I’m used to although passing is message was a bit different. In fact it seems that in Python I choose an exception type and a message and not create a new class with the message and an argument.
Lines 11 and 12 has the actual game play using the method __playSingleMove, this method marked by two underscores that tells Python that its a “private” method. this method cannot be called outside for the class and is used here to make play more readable.
I’ve used a PlayContext class to pass several arguments into this method, I needed to pass several arguments to the method that change each move. Instead of using this OO way I could have written the following:
Python can return multiple values but it seemed just wrong writing a line like that.
After all of the seeds have been distributed I have several more actions to do:
If the last seed has not been placed in the player store (14)
- Check if the last pot was empty and capture the opposite pot’s seeds (15-16)
- Change the current player to the next player (18)
If the current player cannot move – the game ends (20-21).
The code is readable I especially liked using indentation instead of curly brackets although it can be confusing at the beginning.
the full code of the Mancala classes is available here for download. This is the first time I’m writing Python/IronPython code so if I’ve missed anything or if you know of a better way to do something I did – please let me know either by email or by writing a comment.
That’s it for now – stay tuned for the next post where I’ll write about how I’ve unit tested my application.
[Mancala – by sinsofthedove]