There’s no doubt who the cool kid on the block is when it comes to the “one ASP.Net” stack – SignalR, a library created to simplify the process of creating responsive applications that push AND receive notifications from the server. It provides a wrapper around a range of technologies that can provide persistent or semi-persistent connections, choosing the best available when the full chain from browser to server is taken into account.
Wanting to look into this technology with a project that’s at least semi-real, I was inspired by an article in a recent edition of the digital magazine Dot Net Curry where the author created a game of noughts and crosses (or tick-tac-toe). Chess was going to be beyond me for sure, but I figured a game of Backgammon might be feasible to get running. Hence BackgammonR – for some reason all apps using the technology need to end with a capital R.
The application I’ve built so far so far is running here on Azure. And code should anyone want to look into it further is here on Github. Worth flagging from the outset that you certainly won’t play the best game of Backgammon of your life on the app... at least yet. But it’s definitely proved its worth in allowing me to get to grips with the technology.
I’ll explain the code a bit more in this and two further blog posts.
The Game Engine
I won’t actually mention SignalR further in this post though; instead will go through some of the features of the game engine itself.
The application is based on ASP.Net MVC 4 and consists of a single project, plus a project for some unit tests. The game engine I’ve set up in the Models directory and it consists of three key classes.
Manager is a class set up using a singleton pattern to maintain an application wide, static instance of a single object. It contains two lists – one of players and one of the games. As you’ll see there’s no backing store such as a database to persist this information which would be needed were this anywhere near a real application. Currently if the application restarts or the app pool recycles all the running games would be lost. But it’s a nice, quick and easy way to get some form of application state running.
public class Manager { private static readonly Manager _instance = new Manager(); private Manager() { Players = new List<Player>(); Games = new List<Game>(); } public static Manager Instance { get { return _instance; } } public List<Player> Players { get; set; } public List<Game> Games { get; set; } }
Player is a very simple POCO that holds properties of the player name, connection status and connection Id that’s used by SignalR to recognise each connection.
Game is where the core of the game engine logic is coded. It contains properties that describe a single instance of a game, for example which player is black and white, whose turn it is and with the state of the board and dice.
The last dice roll is modelled as a simple integer array with 2 elements – one for each die. And similarly the board – this is a two-dimensional integer array with one dimension containing an element for each player and the other dimension holding the number of counters for each point. I actually have 26 points – 24 for each of the points, with the first and last position used for the bar and pieces that have been beared off respectively.
As well as these properties are various public methods such as RollDice and Move, along with private ones for validating the moves are valid and updating the state of the board.
Unit Tests
The bulk – in fact currently all – of the unit tests have been written to design and test the Game class, as this is where the bulk of the back-end logic resides. When I’m working with unit tests I like to ensure I cover all classes and methods that are a) have some complexity to provide value for the tests b) not too hard to test in terms of tricky dependencies. I find that provides the most return on investment in testing effort.
This class falls squarely into that category – it has no dependencies so there is no need for mocking and it offered a nice way to work in a TDD fashion as I worked through the various rules for what makes a move valid or not. Here’s an example test:
[TestMethod] public void Game_MoveMatchesDiceButToOccupiedPoint_IsInvalid() { // Arrange var player1 = new Player { Name = "Player 1", }; var player2 = new Player { Name = "Player 2", }; var game = new Game(player1, player2); game.Dice[0] = 2; game.Dice[1] = 5; // Act var result = game.Move(new int[] { 1, 1 }, new int[] { 3, 6 }); // Assert Assert.IsFalse(result); Assert.AreEqual(1, game.CurrentPlayer); }
Authentication
To authenticate users again I’ve used something very simple just to get this working and move onto more interesting aspects of the project. The application uses Forms Authentication via a simple custom membership provider called AppMembershipProvider that merely checks that the name of the player is unique.
public override bool ValidateUser(string username, string password) { // All we care about for now is that user name is unique return !Manager.Instance.Players.Any(x => x.Name == username); }
The HomeController has methods for handling this flow before redirecting authenticated users to the Game method where the backgammon functionality lives.
Worth flagging an issue I ran into here – as did the author of this stack overflow post – which is that initially I looked to set up Forms Authentication from within the SignalR hub. This caused issues as the connection that SignalR recognised for each user was lost between the unauthenticated and authenticated states. So best to keep it separate.
Very nice project to model after. Thank you.
ReplyDelete