I designed and created a small game to demonstrate several techniques. First, I demonstrated how to contain the scope of a project to ensure it gets out the door. While this was only a tiny project, my goal was to create a working game over the span of a weekend or possibly a week (It took me about 24 man-hours of labor in total over a span of 5 or 6 days). Technically, I did not track my hours and I did not estimate the development time of this project. For any projects taking more than a week, estimates should also be included. Also, if you review the design specifications and match it with the actual game, you’ll notice a few missing features. Notably, there are not armor units, it’s legal to move past enemy units and the “next phase” indicator is not very visually appealing. Chalk it up to time constraints. I wanted to get this out the door so I could blog about it. If this were a real game, I’d have to spend much more time polishing it to make it more visually appealing.
About the Game
One important thing I forgot to do in my last blog post was explain how to play the game. It’s somewhat trivial to figure out, but for those who have never played any Avalon military board games, it goes like this:
- The game phase controls what can be done on the board, starting with the allied move phase.
- When in the move phase, you can move your units. Each unit that has been moved will have their movement allocation decremented to zero. So you can’t move the unit again for the current turn.
- Once you are satisfied with your unit moves or you have no more units to move, you can click the “next” button to advance to the allied attack phase.
- During the allied attack phase you can attack any enemy unit that is next to one of your allied units. If you are not next to any enemy units, then you must skip the attack phase. Each unit can only attack once for this turn.
- Once you are satisfied with this phase, you can click the “next” button to advance to the next phase, which is the axis movement phase.
- Now it’s the computer’s turn to move its units. The computer will move units around the board and automatically advance the phase to the axis attack phase.
- When the computer is in the axis attack phase it will attack any allied units that are next to one of its own units. Then it will advance the phase to the allied movement phase.
- Continue to step 2 until an end condition is met.
Game End Condition
The game ends when either all 4 cities are captured or all units on the allied or axis side are eliminated.
Weaknesses in the Current Game
If you play this game a few times you’ll notice that it’s about as difficult to play as tic-tac-toe. It becomes predictable and it’s easy to formulate a strategy to beat the computer almost every time. One problem is that the dice roll is biased toward the defense. This is due to the fact that all units have an offense of one and a defense of two. If you look at the ComputeBattleResult method of the GameClass object, you’ll notice that it’s just hard-coded at the moment. I did that because there is only one type of unit on the board. To expand this game, it will be necessary to use the unit index parameters to lookup the offense and defense of the two units and use a lookup table (or a formula) to compute the odds.
The second problem is that the enemy only has one strategy. Divide its units into 4 groups of units and march them to each of the four cities. Attacking allied units along the way. If you manage to destroy the 3 units heading to one particular city, the enemy will not dispatch additional units to reinforce the hole in its strategy.
Options for Fixing the Game Play
One option to fix the game play is to introduce a variety of different units. Many of the methods that assume there is only one type of unit will need to be altered to make sure the defense and offense are accounted for. New units should maintain the single movement allocation and range of one to keep this under control for now.
A second option is to add a mask to the play field. This could be done by creating black hexagon images that can be written over the board positions not explored by the allied units. Obscuring what has not been seen yet. This will only have minimal impact for those who play the game more than once because they don’t need to re-explore a map they already have memorized.
An alternative or addition to the second option is to create a mask of areas not currently visible by allied units. This can be accomplished by dimming the hex areas where allied units cannot see and not rendering any enemy units under the dimmed areas. The background will be visible but enemy units not in visual range will not be seen. Using this technique in combination with alternate enemy strategies has the potential to make the game more challenging.
Other Possible Enhancements
- Allow stackable units. The top unit could contain an icon with the word “stack” in it to indicate that it is a stack of different units. Offense and defense numbers should be totaled for the top unit. Complications arise from the fact that units must now be stacked and un-stacked. Moving a stack needs to be accounted for. Attacking an enemy unit should account for the entire stack. I would propose doing the stack bookkeeping in the C# code and replacing all the units in the stack with a special unit in the JavaScript. There is also the issue of attack. This should be changed to provide a partial kill instead of all or nothing. Offense and defense number would need to be decremented as the attack is occurring and units in the stack need to be destroyed if the defense level is too low to support them.
- Combine attack and movement phases together. There really is no reason to have a separate attack phase. If the allied unit is moved into an enemy unit, then it would be considered an attack. There is one possible issue: If the range factor is used and a unit has an attack range of 2 or more, then there needs to be a control to determine if that unit is attacking an enemy.
- Enhance enemy strategy. The enemy AI can be expanded to provide 2 or more different strategies. Even a un-sophisticated algorithm could use a random number at the beginning of the game to choose a strategy and then use that throughout the game. Each strategy can be designed and tested one by one and then randomized when each strategy is completed for the final version. Also, each strategy can have some intelligence built in. For instance, in the current strategy of marching to each city, if a group of units is destroyed, then one unit from each other group can replace them. if the enemy has too few units to hold all cities, then the AI can switch strategy to attempt to hold one city or just battle the allied units in the hope of destroying all allied units.
- Allow longer movement allowances. This is tricky because now we’ll need to implement the ability to block units so they can’t just slide past allied units (and vice versa).
- Add terrain effects. One weakness of the map board is that it only has flat grassy fields with a movement factor of 1. Adding roads with double movement factors can make the game more interesting. Also, a river with bridges. Units can be blocked by rivers and must use a bridge. Rivers can be used to form natural boundaries and choke points. This will complicate the destination problem of the AI because now a path finding algorithm must be implemented (like the A* algorithm). Mountains can be used as a 1/3 movement factor and forests a 1/2 movement factor, allowing for more choke points.
- Weather factors. Most physical board games have a random weather factor that changes for each turn. Weather factors can modify movement (like snow, all movement cut in half) and offense effectiveness or visibility.
- If a visibility mask is used, then scouts should be added to the game. These would be fast units with long visibility, but possibly a zero defense and offense.
- Random map boards. Civilization does this very well. A completely random map can be generated at the beginning of the game. This would improve the enhancement of obscuring the map until explored, since there is no way to be certain what terrain is under the obscured areas. This also increases the challenge of the game for repeat players. Every game is unique.
Conclusion
I think I’ve indicated how fast the scope of this game can expand to occupy all available free time of any programmer. I’m sure anybody can think up other features to add to this game that would make it more interesting to play. The best way to tackle a project like this is to prioritize the desired enhancements and focus on one enhancement at a time. This will keep the game playable while each enhancement is added rather than attempting to do it all and working endlessly for months on a game that doesn’t work (not to mention attempting to debug it all at once).