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.
Mancala is a board game played by two players. This is what my Mancala board looks like:
Playing Mancala is easy:
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”).
I have four classes in my Mancala implementation:
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.
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:
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:
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)
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]
Labels: IronPython