This is the third in a series of blog posts I’ve been working on during COVID isolation. It started with the idea of refreshing my systems design and software engineering skills, and grew in the making of it.
Part 1 describes ‘the problem’. A mathematics game designed to help children understand factors and limits which represents the board game Ludo. Part 2 takes you through the process I followed to break this problem down to understand the constraints and rules that players follow as a precursor to implementation design.
In Part 3 the building blocks for the design of the classes and methods are laid out in preparation for understanding each of the functions and attributes needed to encapsulate the game.
Get in touch on Twitter at @mr_al if you’d like to chat.
Implementation – Design
My major at University was a subject stream they called ‘Information Systems’. This provided both a fundamental understanding of what information is and how it is used, but also how it “flows” through any organisation or group of people. Early studies taught the logic and discipline behind ‘functional decomposition’. Or, in simpler terms, breaking a problem down into smaller, component parts until you get to a small enough, modular chunk of logic which can be more readily encapsulated into a coded program.
This is a really useful skill and can be applied to many facets of everyday life and work. It is counter-intuitive to some people who like to dive right in and start ‘cutting code’, but lends itself to more contemporary trends such as epic, story and sprint mapping in agile.
It is also the reason that learn-to-code tools such as Scratch, and groups like code.org do so well in providing children with an introduction to coding – they start by getting the learners to solve logic problems with steps, loops and condition.
So – back to work.
I chose this game as a way of exploring Object Orientated design and programming. I last did this formally around 20 years ago when completing my under-graduate degree (Bach. of Computing, Monash, 2000), where we dabbled mainly in Eiffel and C. I’d missed catching the Java train by a few years; after I graduated it was to become all the rage, replacing C++ and other stalwarts. Later, languages such as Python as Ruby also came along, and JavaScript matured from being a bit of fun to make crawlers on the bottom of your Mozilla browser, to something more serious and respected.
Again, I sat down with pen and paper and started to work through what a functional breakdown of Auto120 would look like, centered around three main classes: Players, Markers and the Game itself.
Fast forward to defining the classes and methods in an IDE – in this case, Visual Studio 2019 Community Edition, and you get this:
This class model is not perfect, but it’s a good start. In summary, the methods and attributes are:
Class – Player
An object describing an actor in the Game. They consist of the following attributes:
- p_playerid – an integer set to 1 or 2, identifying each Player
- p_pieces – an array of four Markers , being the playing pieces for that Player
…and the following methods, excluding the eponymous constructor:
- p_get_playerid – returns the Player’s identification number
- p_assignpiece – assigns an instance of Marker to the player
- p_check_game_status – checks to see if all the Player’s Markers have reached the end of the game
Class – Marker
An object describing the pieces (Markers) used by each Player in the Game. They consist of the following attributes:
- m_location – an integer indicating the Position the piece is on
- m_owner – [deprecated] an integer indicating which Player the Marker belongs to. [Not used in later versions as it was redundant; we already had a relationship established as you don’t have a Marker without a Player.]
…and the following methods, excluding the eponymous constructor:
- m_assignowner – [deprecated] assigns the Marker the id of the owning Player [see above]
- m_calclocation – returns the potential position of the Marker based on the current die roll value
- m_get_location – returns the current Position of the Marker
- m_get_status – returns a flag indicating if the Marker is active
- m_setlocation – updates the Position of the Marker
Class – Game
The major object encapsulating the methods and attributes for game play. It is driven by an external instantiation (see below).
It consists of the following attributes:
- g_dievalue – an integer containing the value of the current die roll
- g_gameover – a flag indicating that the game has concluded
- g_movecounter – an incremental counter used when logging the game moves
- g_movelog – an array of strings used to document game moves
- g_players – an array of two Player instances representing the state of each Player
- g_playerturn – an integer indicating which Player is currently having their turn
- m_location –[deprecated, used in Marker instead]
- m_owner –[deprecated, see above]
…and the following methods:
- g_detect_clash – Calculates if a Marker which has just been moved has landed on a Position occupied by one or more Opposition Markers. Bumps those Markers back to Position 1 if found.
- g_dieroll – updates g_dievalue with a random integer between 1 and 6 inclusive
- g_displaylog – dumps the game log to the standard output screen/document
- g_find_to_move_in_play – executes part of Scenario Set C, seeking candidate Markers which are on the board (i.e. >1) and choosing one to move
- g_find_to_move_onto_board – executes second half of Scenario Set D, seeking candidate Markers which have not yet moved into play (i.e. are on Position 1)
- g_flip_player – hand over the die to the other Player by flipping g_playerturn
- g_get_playerturn – return the integer value of the current Player
- g_logmove – write a string to the log array containing a description of the current move or decision commentary
- g_marker_move – move the selected Marker to the destination Position
- g_move_onto_board_set_D – driver for Scenario Set D, picking a Marker at random to move
- g_newgame – called by the constructor to set up Players and their Markers
- g_player_action – central driving game logic, cycling through the Scenario Sets until one executes successfully
- g_return_other_player – returns the instance of the Opposition Player (being the Player who’s turn it is not)
- g_return_player – returns an instance of the current Player
- g_return_random – returns a random integer between 1 and x inclusive, where x is supplied by the calling method
- g_target_magic_numbers – used by Scenario Set A and B to forecast Markers which are likely to land on penultimate or factor numbers, and to choose a Marker to move if found
- g_target_potential _clashes_set_C – driver for Scenario Set C, will forecast Opposition Player Markers that could get knocked out based on the die roll, and the Positions of the current Player’s Markers.
Main Driver (not shown)
The main driver program:
- Creates an instance of Game
- Inside of a loop, calls the g_player_action method and the g_flip_player method until g_gameover is flagged
- Displays the game log
OK. Paperwork is done. Time to cut some code.
NEXT POST… PHP, my tool of choice to fire this baby up and take it out for a run…