Last November I started learning to code python[I]. In 5 weeks I hope to have finished creating a card game.
Learning python
Briefly: codecadamey, Learn Python The Hard Way, The Python Game Book, Foundations in Python Networking, reddit, stackexchange, python standard library documentation, prolog challenges, codewars, checkio.
A review of this process needs to wait for another day.
What sort of game?
Or: What are the goal features of the game?
- A card game
- Two player
- Plays over a network
- Graphical interface
I don’t play any card games, so can’t comment on similarities. Maybe, generically, comparisons can be made to Magic, insofar as it is a battle-type card game in which players take turns playing their cards.
Designing the game
I didn’t. I took a game plan made by someone who plays many card and board games, and have been working to convert it into computer form.
I first did this because it gave me a working game – I played it with the creator using print-outs and a pencil and pen. And also because I trusted that the creator was far more competent than me in this domain. It also freed me up from actually having to sit down and try and make a game (which probably would have resulted in something akin to an Asteroids clone).
In retrospect, this choice forced upon me another valuable lesson:
Separate the game design process from the coding process.
Sometimes when brainstorming an algorithmic implementation of a particular mechanic, the thought would arise, “Argh”. There were certain features of the game’s design that I never would have included because they seemed “too” unique, or integrated “too” many other features.
By too unique, I mean something like this example: If all cards change a health value, but one card changes the amount that the dice are rolled when defending, then I can’t simply use a function that returns a health value to be changed… Except that I can. Although this example is simple, it illustrates the next point as well. I can use a function that returns a value-category to be changed, together with a value with which to change it. This can occur at all levels of game/coding abstraction.
By too integrated, I mean something like this example: If one card changes the health of the enemy only when a dice roll of 6 occurs under any circumstance except if a new turn starts with either player having less than 4 cards in which case the lowest cost card of either player needs to be discarded… then it looks like parts of the program which otherwise never needed to communicate directly, now do… Except that they don’t. Once again, a novel solution can be found (in my case creating dictionaries of keys (which function needs to read the value) with list values that can accumulate lambda functions for tests that modify other dictionary key entries, all the details of which are localized to the card object’s function, while every other function of the game simply checks the dictionary before running).
These challenges forced me to be more creative and versatile in my coding, and ensured that creative principles were never compromised to ease of coding.
Starting to write code
Once I had a design, there was a sense of being overwhelmed by the complexity of the task.
I had read some other simple game codes, so had a few generalizable prompts. The most significant was to use a “Controller” acting object, which was responsible for hosting all the game objects, and telling them what to do. I also knew that I had to make good use of classes. But beyond that…
I started by writing, and got as far as having a graphical interface with a background that could display cards (nothing more than images), exchange them, and keep some scores. But then I needed to make some major changes to the way the objects operated, and the entire thing broke down into a mess.
My second start began with coding the controller, and trying to work out how the game flow would operate. First, the controller would create the objects, then it would loop through turns. But, some tasks were passive, whilst some required player input. I solved this by creating Stages objects, and the controller would scroll through these, activating, in turn, each of the stages’ active() and passive() functions. But then I started coding the cards, and I realized I had to give every single object access to the controller. I didn’t like this.
My third start began more intelligently. I wrote out a pseudocode for the game as a whole, and for all the card functions. I wrote a skeleton Controller, and Player, and then started coding the Card objects. As I worked out what functions that Player needed to have to serve the Cards, I wrote these too. I also started doing unit testing, writing a test for each generic function as I wrote it. But certain challenges started to interfere with my design. Exceptions and idiosyncratic checks started to build up, and once again I was reduced to giving certain cards access to the Controller. I didn’t like this.
My fourth start began with a list of cards and their functions. I went through each function and wrote out how I would do it. I looked for solutions that were universal, so that all cards could be accessed equivalently without worrying about exceptions. I also made a major decision about the flow of information through the program. The Controller could talk to the Player. The Player could talk to all of the objects it owned, and they could talk back to it. The Controller would (generally) not talk to the Player’s objects, instead, it would ask the Player to do it for itself. There were also few epiphany solutions that I could now implement from the ground up. I still started by writing the skeleton for the Controller and Player, then by writing the hierarchy of classes, then by writing the cards and the functions they would need the Player to have.
I had completely separated the front/back-end of the program, and have left the front-end to be completed once the back-end is done. I hope this won’t be a problem.
Looking forward
So that’s where I’m at now. I’m confident that I know how to do (nearly) everything (I’m still working out the details for what socket library I’ll use). I plan to finish rewriting the code, playing the game in text-based form, then working on the socket objects and functions, and the GUI objects in parallel (since they are independent). #Excitement and #Trepidation.
[I] “Python is an interpreted high-level programming language for general-purpose programming”. For further details see https://en.wikipedia.org/wiki/Python_(programming_language).