Saturday, June 15, 2013

The Game (Part 4)

I have implemented the mask and view capabilities.  I'm calling this version 2.  Here's a sample screenshot of how it looks in action:

The first thing you'll notice about this map is that unexplored areas are colored in black.  These will uncover as allied units are moved around the map.  The darker areas are areas that are not visible but have been explored.  These areas could have enemy units hiding there.  Every time an allied unit is moved the view map is recomputed in JavaScript (and a duplicate array is maintained in C# in case the player refreshes their browser).  The unexplored areas are initialized at the beginning of the game and are cleared as units are moved.  Both the JavaScript and C# code have functions/methods to deal with this mask.  The difference is that the JavaScript doesn't maintain an array of cells that are explored because they are just set to hide the mask whenever a unit passes by and they are never set back during the game.

The two masks are identical and use the same image to paint over top of the entire board.  I set the opacity to 0.3 for the view hex pictures so the player can see the terrain under it.  I also manually set the display value of each enemy unit to match the value of the view mask.

Here's the code: Battlefield One Code V2

You can go directly to my website to play the game as is: (temporarily down).

I've played the game a few times and it is a bit more challenging than the first version without the masks.  I think my next enhancement will be adding a variety of different unit types.  I might have to enlarge the playing board to allow more playing pieces.

Stay tuned...

Note: I have recently upgraded my website to use MVC4 and .NET 4.5. I have refactored my code to make the game work on MVC4.  Click here to try it out.

The Game (Part 3)

So I'm working on the visibility and mask of the game I wrote in the last two blog posts.  Here's a problem that I ran into right away and it involves not paying attention to detail.  What I'm referring to here is the hex board layout.  If you look at the documentation:

Battle Field One Specifications

You'll see a page titled "Unit Movement" and at the bottom is the definition for finding the surrounding 6 cells.  What I didn't verify is that my game has the cells shifted the exact same way.  You see, there are two different ways a hex-board can be drawn (actually there are rotated arrangements too, but I'm going to ignore that).  If the first column is started lower than the second column , then it follows my specification.  However, if you look at the actual game, you'll see that I drew the map starting with the first column higher than the second column.

Old Documentation:

So that means that the game was designed wrong to begin with.  Now the choice is to change the documentation and fix the calculations inside the game or change the game board and leave everything else clean.

I'm choosing to change the specification for the game and I'm going to have to fix the even/odd test inside version 1 to make sure I am searching the right surrounding cells.  If you're just downloading the specification, then you'll noticed that it's already been corrected.

These things happen and it's fortunate that I was able to catch this before getting any deeper into the game code. 

Thursday, June 13, 2013

Follow-Up on Designing a Game

So 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:

1. The game phase controls what can be done on the board, starting with the allied move phase.
2. 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.
3. 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.
4. 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.
5. 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.
6. 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.
7. 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.
8. 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

1. 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.

2. 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.

3. 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.

4. 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). 

5. 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.

6. 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.

7. 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.

8 . 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.


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).

Monday, June 10, 2013

Designing a Game

It's been a while since I posted something new.  That's due to the fact that I've been working on a small game.  My intent was to design and build a fully-functional game to demonstrate AJAX, C# and SVG.  The trick to completing something like this is to make sure the scope is small enough that it can be completed in a short time.  I chose a turn-based game to keep the code simple.  This game is a basic Axis-vs-Allies type board game using a hex board layout.  I chose the hex layout to make the a game a bit more challenging and the hex board has 6 directions instead of 4 primary and 4 diagonals. 

I named the game "Battlefield One."  Not overly creative, just a temporary name.  Here's the basic design document:

Battlefield One

Feel free to download and thumb through the details.  There's mention of two types of units in the game, but I trimmed it down to just infantry.  No tanks at this time.  That's easy to add though, since there is an object called "Unit" that I used to contain the defense, offense, movement, etc.  This object can easily be expanded to represent other units.

Follow this link to play the game:

Battlefield One Game

Here's a screenshot of part of the game board:

The first task I performed was rendering the playing board.  There are a lot of decisions that can be made here, but I chose to render the beehive grid with lines on top of a background picture.  The trick was getting the picture to line up.  So I wrote some SVG code to paint one hexagon and repeated a grid of these shapes.  As I've mentioned in a previous post, this board is really no more than an offset checkerboard, where every other column is offset by 1/2 the height of the previous cell.  Once I had a grid printed on the screen I had to make sure my browser was set to 100% (yup, I forgot that step and had to redo this next step).  Next I took a snapshot of the entire screen and put it inside Photoshop.  You can use any paint program you like, I'm comfortable with Photoshop and this problem just screamed "layers!" to me.  After I put the screenshot on a layer in Photoshop, I filled in the green areas for all the cells except the four cities.  I made up an easy pattern of city building roofs and roads and then I just copied to all 4 city locations.  Then I put my background into the SVG code before rendering the beehive cells.

That pretty much completed the background picture.  In future versions of this game, I hope to add roads and make the movement factor double when a unit uses a road.  But for now, it's just a green field.

Next I defined a unit and worked out the rendering portion.  For units, the center icon is just a PNG file that I created.  The unit type will define which PNG file will be rendered in the center of the unit box.  The four corners are numbers representing the defense, offense, movement and fire range.  The top center number is a number that I added for troubleshooting purposes.  I left it in for now.  It represents the unique unit number.  This was a snafu that I ran into when I was debugging a deleted unit problem.

The unit objects are grouped into a list:

private List<Unit> AllUnits = new List<Unit>();

The only issue with using a list is that deleting a unit causes the list to compress and the indexes to each item is now changed (at least for units after the deleted unit).  So I inserted a variable in the Unit class called "Number" which represents the unique unit number:

public class Unit
   public int Number { get; private set; }
   public int Defense { get; set; }
   public int Offense { get; private set; }
   public int Movement { get; private set; }
   public int Range { get; private set; }
   public int UnitType { get; private set; }
   public int X { get; set; }
   public int Y { get; set; }
   public NATIONALITY Nationality { get; private set; }
   public UNITCOMMAND Command { get; set; } // used by enemy units only
   public int DestX; // used by enemy units only
   public int DestY; // used by enemy units only

I created a couple enum's for NATIONALITY and UNITCOMMAND.  There's nothing fancy going on here, it's just my way of keeping track of what is set.  It also helps in the "if" statements to see what is being compared.  The enums are as follows:

public enum NATIONALITY { Allied, German };
public enum UNITCOMMAND { None, Wait, Destination, Defend };

At the moment, I'm only using the "None" and "Destination" status of the UNITCOMMAND variable.  I initialize the Unit class to a Command of "None" and then I change the command to "Destination" once I have set a unit DestX and DestY for enemy units. 

The Game AI

I managed to crank out enough C# and JavaScript to allow the allied units to move around the map board.  The computer player was still dead (i.e. not moving or attacking).  I decided to work on the enemy move phase of the game.  I kept the game AI as simple as possible.  Basically, the enemy will count the total number of units, divide by 4 (which is the number of cities on this map), then set the destination for each group to a different city. 

That was all I setup initially.  I didn't bother with attacking or detecting any end game results.  The movement of units included a method to force move restrictions on the desired movement (I called this the SnapTo method).  This method will make sure the unit only travels one unit from its current location, it can't overlap another unit and they can't go off the edges of the map. 

There was a problem that I ran into.  My algorithm computed which units would move and did the SnapTo operation inside the C# code, then sent it back through an AJAX return to the calling JavaScript that performed the actual move.  The problem is that the order that the units are moved can determine if there is another unit in the square that will be moved to.  So I decided to just send the data to the JavaScript in no particular order, then I looped through a queue of move orders.  If the unit was blocked, I swapped that unit to the back of the queue and then continued moving other units.  After a few attempts to move a unit and passing it over, eventually the space it was destined to move into will be empty (vacated by another unit just moved). 

Next, I did the enemy attack phase.  I decided that if the enemy bumped into an allied unit, it would just attack during the attack phase.  So I wrote a method to search for allied units that are one hex away from a German unit, then send both unit numbers and the battle result back to the JavaScript from the calling AJAX. 

Last, I completed the code for the allied attack phase.  The JavaScript that triggers this sends and AJAX command to the C# code which does the battle calculation, sending back the results.  The return JavaScript function deletes the unit object from the SVG code.

Game Goals

There are 2 possible goals that can be achieved to win or lose the game.  The first goal is to capture all 4 cities.  The German or Allied side needs to capture all 4 to win the game.  If either side has only 3 units or less, then that goal is not achievable.  The second goal is to destroy all the enemy units (or the enemy must destroy all the allied units).  When one team or the other destroys the other's units, the game is won.

The game can become a draw due to the fact that the enemy AI splits groups of units for each city.  Once the group of units reaches the destination city, they just sit there waiting for something to happen.  Unfortunately, it doesn't do the enemy much good to have 3 or 4 units sitting on one city while the allied player sits on another city with one remaining unit.  The enemy will not seek out and destroy the allied unit.  This is a weakness that I'll be fixing next.

Game Code

I'm going to spend some time and refactor the code to clean up all the scraps I left on the floor of the sausage factory.  Once I do that, I'll post the code for anybody to download and examine.  Though I haven't completely tested this on an iPad, I have done some preliminary testing and it works pretty good.  The total amount of code for this game is about 860 lines of JavaScript and 730 lines of C# code.  Just a little something I do on a weekend.

Update 6/12/2013:

I performed a few bug fixes while refactoring the code.  Now that I have been able to play the game several times in a row without a hiccup, I feel confident that it's pretty close to bug free.

Update 6/13/2013:

Here's the entire project for download: BattleField One Project.

Tuesday, June 4, 2013

Cross-browser Testing

I subscribed to the "Code Project" daily build email.  I have found these daily emails to contain some real gems.  Today, I was looking at an article titled: "HTML4 - we're done" which peaked my interest because I've been focused on HTML5 for the past couple of years. 

Click here for the article

As I read down toward the section called "Multi-browser testing options" I started to click on the links to check out the tools that the author was using.  The last tool called "Modern.IE" took me to this website:


The top part goes to a tool called "Browser Stack" and it has a list of OS's to test against.  These are emulators that are run in a virtual environment:

It also has a selector for available browsers which are real browsers executed inside the virtual environment:

Signing up gives the user a 3 month free trial and it costs $19 a month for one person.  Which means that this tool is primarily for use by a business or those who are programming for a price and are concerned about compatibility.

Still, I'm happy to see that there are tools out there that can test on multiple platforms.  I typically only test the top 5 browsers, which are installed on my PC and the iPad Safari (because I have an iPad).  I rarely get the opportunity to test against an Android device due to the fact that I don't have one on-hand.  Having the ability to test against a virtual device is better than not testing at all.