Contents

It’s been a while since I last dabbled with Windows 8, so I thought I’d have a go at creating a simple game app - and in this article, I’ve shared what I came up with. This article describes the MVVM structure of the game, but also covers a real mixed bag of topics including:

How to efficiently handle the various layout requirements of a Windows 8 app.

The Reversi game is ‘backed’ by the GameBoardViewModel which exposes the game state via a set of properties such as the current score, the player whose turn it is next, and the state of the board itself as a collection of GameBoardSquareViewModel instances:

The ViewModelBase class is a pretty standard view model base class that simplifies the process of creating classes that implement INotifyPropertyChanged, via the SetField method. The GameBoardViewModel constructor creates the 8x8 board squares, whilst the InitialiseGame method sets the initial state (see Wikipedia for the rules on the game including the initial set-up)

The GameBoardSquareViewModel exposes the row, column and current state of an individual board square:

The prevailing style used for Windows 8 apps is the flat ‘metro’ style. However, for this Reversi game I wanted to create something more visually rich, so I opted for the kind of faux-reality that is more often found on the iPad. What can I say? Sometimes I like the look of wood, leather, drop shadows and brushed metal!

I designed the app UI using the free GIMP painting application. GIMP is a cross-platform graphics package that provides many of the core features found in PhotoShop. I have included the XCF files which shows the various layers that make up the finished imagery. Within this article I’ll provide a brief outline of steps I took to create the graphics.

The first step was to find the wooden background for the board. This was achieved via a Google Search for ‘mahogany’, after browsing the results, I found the background I was looking for:

The next step was to ‘cut out’ the border for the border. This involved selecting a rectangular region, the using the ‘rounded rectangle’ and ‘shrink’ features to create a selection that could be used to cut out the border from the background. The border was pasted as a new layer, then some subtle colour adjustments applied to lighten the wood, and a drop shadow added:

The background of the board was created as a new layer, which was filled green within the same selection used to construct the border. Also a subtle noise rendering was applied to give a felt texture to the board:

A layer containing a radial gradient was added on top of the board to give the following shading effect:

The grid pattern was created by constructing an 8x8 pixels layer, then manually filling the alternate pixels with black in order to create a grid. This layer was then scaled to the board size (without smoothing) in order to create a grid of the correct size. The opacity of the grid layer was reduced to about 20% giving the following effect:

The various game texts were rendered using the “Script MT” font, with a drop shadow. Finally, a couple of playing pieces were drawn using a combination of circular selections, drop shadows and embossing.

Because Windows 8 devices cover a range of different screen sizes, it is not possible to use a single image as the view for your application. In order to construct the view for the Reversi board I dis-assembled the various components of the game graphics, re-assembling them using a grid layout.

A further requirement of Windows 8 applications is that they gracefully handle the various application view states, which include portrait, landscape, snapped and filled. For the Reversi game in order to elegantly accommodate these various states I wanted to change the position of the various components. For example in landscape mode displaying the scores to the right of the board, whilst in portrait mode displaying the scores beneath the board.

The Windows 8 sample applications have a class, LayoutAwarePage, that translates view state changes into visual states making it possible to handle these various states entirely within XAML via the VisualStateManager.

In order to make re-usable UI components typically you would construct user controls. However, if you simply want to re-use the same XAML markup, without adding any extra functionality or behavior, there is a simpler approach available via the ContentControl.

Each of these templates defines a re-usable UI component, each of which uses a PNG file which is rendered using a number of different layers from the GIMP graphics. Note that a few of these templates make use of the Viewbox control which is very useful for scaling your application UI in order to accommodate different screen sizes.

As you can see in the above code the application has three distinct layouts, where the VisualStateManager shows / hides each layout based on the current application view state. The use of ContentControls ensures full re-use of the view components, it also allows you to clearly see the various layouts.

With Visual Studio you can test the states via the device panel. Here is the game in landscape mode:

And here it is in portrait mode where you can see the different layout that has been applied:

It is also advisable to test your application against all the different display resolution, again this is possible via the ‘Display’ property on the Device panel.

Each square on the board is rendered using a BoardSqureView. You might have noticed the use of an ItemsControl bound to the Squares property of the view model within the ReversiBoardTemplate. This ensures that a BoardSquareView is constructed for each of the 64 squares on the board. The BoardSquareView simply shows/hides the black or white playing piece based on the state of the square it is bound to.

The ItemsControl creates a ContentPresenter to host each BoardSquareView instance. It is these ContentPresenter instances that are added to the Grid which is specified as the ItemsPanel. In order to correctly arrange each square within the Grid the Grid.Row and Grid.Column must be correctly set on each ContentPresenter. With WPF this is possible by specifying an ItemContainerStyle with bindings for the attached Grid properties. Unfortunately Windows 8 Store apps do not support this feature.

As a workaround for this problem, the BoardSquareView sets up the required bindings in code:

The GameBoardViewModel keeps track of the score for each player, which player has the next turn and whether the game has finished - these are all pretty simple tasks. The more complex tasks this view model performs relate to enforcing the logic of the game of Reversi.

When a player taps on the board, this is picked up by the Button that is rendered by the tapped BoardSquareView. This button is bound to a command that is exposed by the GameBoardSquareViewModel, which then informs the GameBoardViewModel that the player has attempted to make a move. All pretty straightforward stuff.

When the player taps a cell, the following sequence of events occurs:

Check if the move is valid (if not … abort!)

Set the state of the tapped cells.

Flip any of the opponent’s counters that were surrounded.

Swap turns

Check that the opponent can make a turn – if not swap back.

Check to see if the game has finished

Updated the scores

This all takes place within the following method expose by GameBoardViewModel:

We’ll have a look at how the view model determines whether a move is valid, within IsValidMove, in a bit more detail.

With the game of Reversi a move is valid if it surrounds one or more of the opponent’s counters either horizontally or diagonally. This means that the view model must search in 8 different directions in order to look for surrounded counters. Rather than write the same logic 8 times over, I decided to decouple the logic that determines whether counters are surrounded from the logic which navigates the board in each direction.

Firstly I defined a delegate which is used to update the row and column that is passed to it. The view model creates 8 instances of this delegate, one to represent each direction that the board can be navigated in:

As you can see in the above code, the GameBoardViewModel has a handy copy constructor which allows the computer opponent to perform the required what-if analysis.

The ScoreForBoard method is an interesting one, before we get into that, we’ll introduce the minimax algorithm.

The computer could choose its next move based on the difference in score that each potential move would make, picking the best one. As an example, if the computer determines that there are three different moves that it can make, then it will pick the one with the highest score as illustrated below:

However, if you look at the next turn, the opponent (i.e. you!) will be trying to minimize the exact same score that the computer is trying to maximize. In the example below, if you look at what happens on the next turn, the situation will be a bit different:

With the one-step look ahead model, the computer would have picked the move that resulted in a score of ‘5’, i.e. the move marked ‘A’. However, on the next turn, a skilled human opponent would pick the move that gives the minimum score for the computer, and thus would select move ‘B’.

You can see that by looking ahead to the next round of moves, it’s easy to determine that ‘C’ is the move that will result in the best score, with the expectation that the next move after that will be ‘D’.

But why stop there? The computer, it its infinite wisdom and computing power, can continue to analyze the tree of potential moves and game states, even all the way to the end of the game! In comparison, a human competitor will struggle to look more than a few steps ahead.

The approach described here is a minimax algorithm where one player seeks to maximize their game score, while their opponent seeks to minimize this same score.

In order to make use of the minimax algorithm, the ScoreForBoard computes the score for each move recursively:

You can see in the above code that the algorithm used to compute the score is inverted when depth%2==0, i.e. on alternating turns. This reflects the previous description where one player is maximizing the score whilst the other player minimizes the same value.

Putting the computer into action is as simple as creating an instance of this class:

I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.

Eek! I'll give Chess a miss. I love the game but have nothing particular to add to the multitude of programs already out there.

I'm thinking of doing Holdem, only the "AI" side for that is pretty fiendish so we'll see. It would seem that most people who make a capable poker opponent put it to work on online tables rather than opening the source.

Anyway, thanks again.

Check out my latest article: Celerity: How it was all done.
A complete how-to on our sensor-driven head-tracking virtual reality tunnel game in C#.