Monday 7 October 2013

Job Interviews - The Essay Test?

C# Coding tests.

Over the past couple of years testing prior to interview for roles has become more prevalent.  This has resulted in some interesting anomalies, most notably of how much of the question is open to interpretation.  Simple multiple choice test only test the knowledge that you have at your fingertips, and never the breadth and depth of understanding of that knowledge. Similarly, essay type scenario tests asking you to build a system based on some given facts, always miss vital parts or are open to interpretation. 

This is about the essay type question, in a normal requirements gathering phase of a project any anomalies, missing parts or clarifications can be ironed out at the start.  If an Agile process is being used then questions and clarifications can happen at any time.

Let’s examine a typical essay type scenario;
An object is moving across a 10 x 10 grid and you need to work out its final location.  Using a web service you will be provided with the movements of the object, Forward, Left (90 degrees) or Right(90 degrees). Each step is a single move.  After the first move the object is in position 1,0.  Once you have the location and final destination send this via web service.

If we examine this a bit closer, in other words the requirements gathering, and see if we have all the pieces to create a system.

An object is moving across a 10 x 10 grid.  How is this marked, 0 to 9 across the x and y axis, -4 to +5, mixture of both and do we need to care?  If we are given a location and movement then we need to know the reference points.  We can assume, as it is fairly common, that it would be 0 to 9.  Then we have the to decide where 0,0 is.  If we are told we can turn left or right and we start with 0,0 at the bottom left this would be completely different to stating at top left or bottom right.  Now the assumptions become a little more difficult.  Mathematically, you could assume the 0,0 would be bottom left as in most graphs.  However, if you are from a HTML5 canvas background where would you say 0,0 would be.  What about windows forms or apple ios, android Windows 8 mobile?

Movements of the object, Forward, Left (90 degrees) or Right(90 degrees). Each step is a single move. Not too difficult at first glance, but does this mean the object should just turn 90 and not move or turn and move?  Anyone ever played asteroids on the old Atari, I was in the navy in the eighties and this caused me to miss a lot of dates!  If we look at doing a Forward Left Right, does this mean that we have only moved one grid or three.  After years of asteroids I would assume one grid move many might assume three.

After the first move the object is in position 1,0.  There are two problems which we need to overcome with this statement.  Firstly, which grid did if move from?  It would be easy to assume 0, 0, but what if it was 2,0 or 1,1.  We know it only moves one grid per step, and we have assumed that a left or right is a turn not a move.  If we have made other assumptions, starting at bottom left of a 0-9 grid with x on the vertical axis and y on the horizontal axis.  Then moving from 0,0 to 1,0 turn left then forward would now mean our object would be in 1,-1 and as there is no -1 on the grid do we just assume that we stay at 0?

Let’s move onto the coding style.  

One thing I try and teach junior developers is that there is more than one way to write and piece of code, however, consistency is the key.  Not just consistency in how we individually code but in the way we code as a team.  I’ve had enough experience to know that in every project something will go wrong!  If it is all done the same way then at least the fix should be easier.  There are some principals which are always good to follow, and I will cover this in a few moments, but this is entirely down to the company and the team.  Each company, especially if using a process, should be following a set of guidelines.  Now just the ones similar to Microsoft’s best practices or SOLID principals but ones that have been adapted to suit the requirements of the business.

When an essay test is provided it rarely comes with the companies coding principals, leaving it to the whim of the marker to decide if his principals are better than yours so all you can do is follow your instinct, training and skill – follow both the Microsoft best practice and SOLID principals, throw in a bit of defensive programming and hope the person on the other end is looking for breadth and skill of an developer rather than someone who ticks boxes.  This is always going to be the difficult bit as the feedback from the company will never provide the solution they were looking for as a comparison tool.

Let me ask a few questions;

1)      Would you make a Console application, web application, widows application, class library or mix?
2)      What assumptions would you make?
3)      What would your design look like, not the code, just the design?


Saturday 7 September 2013

Running IIS Express Remotely

IIS express usually runs under local host. To allow this to be seen by external computers you need to add binding information to the applicationhost.config file in
C:\Program Files (x86)\IIS Express\config

 
               
                   
               

               
                   
               

           


Important parts of this are the application pool, the name and the ID.  The application pool has to be the same for all the sites running in IIS8 express.

The name has to be unique and the ID has to be incremented.

Allow incoming connections.

Open command prompt and add rule

> netsh http add urlacl url=http://192.168.1.27:90/ user=everyone

In command prompt add a firewall rule

netsh advfirewall firewall add rule name="IISExpressWeb" dir=in protocol=tcp localport=90 profile=private remoteip=localsubnet action=allow

If running windows authentication alter the to deny anonymous authentication and allow Windows.

Running multiple sites.
Start iisexpress from the command prompt


"C:\Program Files (x86)\IIS Express\iisexpress.exe" /apppool:Clr4IntegratedAppPool 


 
 
 

Monday 8 July 2013

Random Thoughts

When you working i'ts not always possible to just stop what your doing and blog and Idea or a train of thought.  This post is random  in it's creation with snippits of code, no explanations and no real flow.  However, this is where the useful bits start off - so if it's in here, at some point in the future it will become a blog.



Data Access Layer

A way of creating a common DAL for use in many project where ADO crud operations are used instead of Entity framework or NHibernate.


 using System.Collections.Generic;  
 using System.Data;  
 namespace Jannersoft.Common.DAL  
 {  
   public interface IDbManager  
   {  
     DataProvider ProviderType { get; set; }  
     string ConnectionString { get; set; }  
     IDbConnection Connection { get; }  
     IDbTransaction Transaction { get; }  
     IDataReader DataReader { get; }  
     IDbCommand Command { get; }  
     List<IDbDataParameter> ParameterList { get; }  
     void Open();  
     void BeginTransaction();  
     void CommitTransaction();  
     void AddParameters(IDbDataParameter param);  
     IDataReader ExecuteReader(CommandType commandType, string commandText);  
     DataSet ExecuteDataSet(CommandType commandType, string commandText);  
     object ExecuteScalar(CommandType commandType, string commandText);  
     int ExecuteNonQuery(CommandType commandType, string commandText);  
     void CloseReader();  
     void Close();  
     void Dispose();  
   }  
 }  
 using System;  
 using System.Data;  
 using System.Data.Odbc;  
 using System.Data.OleDb;  
 using System.Data.SqlClient;  
 namespace Jannersoft.Common.DAL  
 {  
   public static class DbManagerFactory  
   {  
     public static IDbConnection GetConnection(DataProvider providerType)  
     {  
       IDbConnection iDbConnection;  
       switch (providerType)  
       {  
         case DataProvider.SqlServer:  
           iDbConnection = new SqlConnection();  
           break;  
         case DataProvider.OleDb:  
           iDbConnection = new OleDbConnection();  
           break;  
         case DataProvider.Odbc:  
           iDbConnection = new OdbcConnection();  
           break;  
         case DataProvider.Oracle:  
           throw new NotImplementedException();  
         default:  
           return null;  
       }  
       return iDbConnection;  
     }  
     public static IDbCommand GetCommand(DataProvider providerType)  
     {  
       switch (providerType)  
       {  
         case DataProvider.SqlServer:  
           return new SqlCommand();  
         case DataProvider.OleDb:  
           return new OleDbCommand();  
         case DataProvider.Odbc:  
           return new OdbcCommand();  
         case DataProvider.Oracle:  
           throw new NotImplementedException();  
         default:  
           return null;  
       }  
     }  
     public static IDbDataAdapter GetDataAdapter(DataProvider providerType)  
     {  
       switch (providerType)  
       {  
         case DataProvider.SqlServer:  
           return new SqlDataAdapter();  
         case DataProvider.OleDb:  
           return new OleDbDataAdapter();  
         case DataProvider.Odbc:  
           return new OdbcDataAdapter();  
         case DataProvider.Oracle:  
           throw new NotImplementedException();  
         default:  
           return null;  
       }  
     }  
     public static IDbTransaction GetTransaction(DataProvider providerType)  
     {  
       IDbConnection iDbConnection = GetConnection(providerType);  
       IDbTransaction iDbTransaction = iDbConnection.BeginTransaction();  
       return iDbTransaction;  
     }  
     public static IDataParameter GetParameter(DataProvider providerType)  
     {  
       IDataParameter iDataParameter = null;  
       switch (providerType)  
       {  
         case DataProvider.SqlServer:  
           iDataParameter = new SqlParameter();  
           break;  
         case DataProvider.OleDb:  
           iDataParameter = new OleDbParameter();  
           break;  
         case DataProvider.Odbc:  
           iDataParameter = new OdbcParameter();  
           break;  
         case DataProvider.Oracle:  
           throw new NotImplementedException();  
       }  
       return iDataParameter;  
     }  
   }  
 }  
 using System;  
 using System.Collections.Generic;  
 using System.Data;  
 namespace Jannersoft.Common.DAL  
 {  
   public sealed class DbManager : IDbManager, IDisposable  
   {  
     private IDbCommand idbCommand;  
     private DataProvider providerType;  
     private IDbTransaction idbTransaction;  
     public DbManager(DataProvider providerType)  
     {  
       this.providerType = providerType;  
     }  
     public DbManager(DataProvider providerType, string connectionString)  
     {  
       this.providerType = providerType;  
       ConnectionString = connectionString;  
     }  
     public IDbConnection Connection { get; private set; }  
     public IDataReader DataReader { get; set; }  
     public DataProvider ProviderType  
     {  
       get { return providerType; }  
       set { providerType = value; }  
     }  
     public string ConnectionString { get; set; }  
     public IDbCommand Command  
     {  
       get { return idbCommand; }  
     }  
     public IDbTransaction Transaction  
     {  
       get { return idbTransaction; }  
     }  
     public void Open()  
     {  
       Connection =  
         DbManagerFactory.GetConnection(providerType);  
       Connection.ConnectionString = ConnectionString;  
       if (Connection.State != ConnectionState.Open)  
         Connection.Open();  
       idbCommand = DbManagerFactory.GetCommand(ProviderType);  
     }  
     public void Close()  
     {  
       if (Connection.State != ConnectionState.Closed)  
         Connection.Close();  
     }  
     public void Dispose()  
     {  
       GC.SuppressFinalize(this);  
       Close();  
       idbCommand = null;  
       idbTransaction = null;  
       Connection = null;  
     }  
     public void AddParameters(IDbDataParameter param)  
     {  
       ParameterList.Add(param);  
     }  
     public void BeginTransaction()  
     {  
       if (idbTransaction == null)  
         idbTransaction =  
           DbManagerFactory.GetTransaction(ProviderType);  
       idbCommand.Transaction = idbTransaction;  
     }  
     public void CommitTransaction()  
     {  
       if (idbTransaction != null)  
         idbTransaction.Commit();  
       idbTransaction = null;  
     }  
     public IDataReader ExecuteReader(CommandType commandType, string commandText)  
     {  
       idbCommand = DbManagerFactory.GetCommand(ProviderType);  
       idbCommand.Connection = Connection;  
       PrepareCommand(idbCommand, Connection, Transaction,  
               commandType,  
               commandText, ParameterList);  
       DataReader = idbCommand.ExecuteReader();  
       idbCommand.Parameters.Clear();  
       return DataReader;  
     }  
     public void CloseReader()  
     {  
       if (DataReader != null)  
         DataReader.Close();  
     }  
     private static void AttachParameters(IDbCommand command, IEnumerable<IDbDataParameter> commandParameters)  
     {  
       foreach (var idbParameter in commandParameters)  
       {  
         if ((idbParameter.Direction == ParameterDirection.InputOutput)  
           &&  
           (idbParameter.Value == null))  
         {  
           idbParameter.Value = DBNull.Value;  
         }  
         command.Parameters.Add(idbParameter);  
       }  
     }  
     private static void PrepareCommand(IDbCommand command, IDbConnection        connection, IDbTransaction transaction, CommandType commandType, string commandText,  
  IEnumerable<IDbDataParameter> commandParameters)  
     {  
       command.Connection = connection;  
       command.CommandText = commandText;  
       command.CommandType = commandType;  
       if (transaction != null)  
       {  
         command.Transaction = transaction;  
       }  
       if (commandParameters != null)  
       {  
         AttachParameters(command, commandParameters);  
       }  
     }  
     public int ExecuteNonQuery(CommandType commandType, string commandText)  
     {  
       idbCommand = DbManagerFactory.GetCommand(ProviderType);  
       PrepareCommand(idbCommand, Connection, Transaction,  
               commandType, commandText, ParameterList);  
       var returnValue = idbCommand.ExecuteNonQuery();  
       idbCommand.Parameters.Clear();  
       return returnValue;  
     }  
     public object ExecuteScalar(CommandType commandType, string commandText)  
     {  
       idbCommand = DbManagerFactory.GetCommand(ProviderType);  
       PrepareCommand(idbCommand, Connection, Transaction,  
               commandType,  
               commandText,  ParameterList);  
       var returnValue = idbCommand.ExecuteScalar();  
       idbCommand.Parameters.Clear();  
       return returnValue;  
     }  
     public DataSet ExecuteDataSet(CommandType commandType, string commandText)  
     {  
       idbCommand = DbManagerFactory.GetCommand(ProviderType);  
       PrepareCommand(idbCommand, Connection, Transaction,  
               commandType,  
               commandText,  ParameterList);  
       var dataAdapter = DbManagerFactory.GetDataAdapter(ProviderType);  
       dataAdapter.SelectCommand = idbCommand;  
       var dataSet = new DataSet();  
       dataAdapter.Fill(dataSet);  
       idbCommand.Parameters.Clear();  
       return dataSet;  
     }  
     public List<IDbDataParameter> ParameterList  
     {  
       get { return parameterList ??   
 (parameterList = new List<IDbDataParameter>()); }  
     }  
     private List<IDbDataParameter> parameterList;  
   }  
 }  
 namespace Jannersoft.Common.DAL  
 {  
   public enum DataProvider  
   {  
     Oracle,  
     SqlServer,  
     OleDb,  
     Odbc  
   }  
 }  


Implementation


   public class TestHarness  
   {  
     public IEnumerable<IPerson> GetAllPeople()  
     {  
       var dbManager = new DbManager(DataProvider.SqlServer);  
       dbManager.ConnectionString = Properties.Settings.Default.Connection;  
       try  
       {  
         dbManager.Open();  
         dbManager.ExecuteReader(CommandType.StoredProcedure, "sp_GetPersons");  
         while (dbManager.DataReader.Read())  
         {  
           Mapper.CreateMap<IDataReader, Person>();  
           var persons = Mapper.Map<IDataReader,IEnumerable<Person>>(dbManager.DataReader);  
           return persons;  
         }  
       }  
       finally  
       {  
         dbManager.Dispose();  
       }  
       return null;  
     }  
   }  

Testing


 [TestFixture]  
   public class TestHarnesTests  
   {  
     private Jannersoft.common.DALTestHarnes.TestHarness harness;  
     [SetUp]  
     public void SetUp()  
     {  
       harness = new TestHarness();  
     }  
     [TearDown]  
     public void TearDown()  
     {  
       harness = null;  
     }  
     [Test]  
     public void GetAllPeople_Return_ListOfPeople()  
     {  
       //Arrange  
       //Act  
       var output = harness.GetAllPeople();  
       //Assert  
       Assert.GreaterOrEqual(output.Count(), 0);  
     }  
   }  


Enum Extension


  public static class AttributesHelperExtensions  
   {  
     public static string GetStringValue<TEnum>(this TEnum value)  
     {  
       var type = value.GetType();  
       var fieldInfo = type.GetField(value.ToString());  
       var attribs = fieldInfo.GetCustomAttributes(  
         typeof(StringValueAttribute), false) as StringValueAttribute[];  
       return attribs.Length > 0 ? attribs[0].StringValue : null;  
     }  
   }  



Sunday 9 June 2013

HTML5 and MVC4 Board Game (Uckers)

Initial Thoughts

I was asked some time ago if I could make a game for some old Royal Naval friends. Uckers is a popular board across many services but appears to be more popular in the Naval Services around he would. Although the origins are somewhat unknown, it is thought to be based on an old Indian game called Patrisi. Essentially it's a pumped up game of Ludo, but the fun in playing the game is not just the game, it's the interaction of the people.
Initially I created the game in Flash as a single player version, using some very simple AI. Now it's time to look at a multiplayer version using HTML5 Canvas. Again building in stages and using C# MVC and updates via JSON. The reason for using C# web service is to separate the game engine from the presentation layer, allowing a more complex AI for single player usage later on, removing the requirement for one user to run their game as a server, opening sockets so client can connect.

Building the Game


Setting up the frameworks

First things first, I want to make sure that this goes as smoothly as possible so I opted for VS2010 and MVC 4.  Although I was thinking of installing Html5 Boilerplate, I opted to just use the standard Html5 and use the latest JQuery (at the time was 2.0).

Setting up the initial connectivity to social media is already part of the framework, but I did make a few enhancements with thanks to Pranav Rastogi blog post
Integrate OpenAuth/OpenID with your existing ASP.NET application using Universal Providers

Unit testing was done using NUnit and Rhino Mocks.

Board Layout

I like the use of JavaScript Closure but there is no reason why you can't just write this out in a script. This is not a live or commercial version, just demo code.

  
var Uckers = Uckers || {};
Uckers.Gameboard = Uckers.Gameboard || {};
Uckers.Gameboard.Common = $.extend(Uckers.Gameboard.Common || {}, function () {

....

    return {
        Initialise: initialise
    };
} ());  

  
Defining the co-ordinate system which will be used throughout the code was an important first step.

       var coordinate = function (x, y) {
        this.x = x;
        this.y = y;
    };  
Next was to define what a ucker was, although this will change in the next few parts we can still define the basic structure.


      var ucker = function (coord, target, radius, color) {
        this.x = coord.x;
        this.y = coord.y;
        this.targetx = target.x;
        this.targety = target.y;
        this.radius = radius;
        this.color = color[0];
        this.shadow = color[1];
        this.colors = color;
    };  

I also wanted to define the start locations for each of the uckers, the colours and it's shadows


   var uckers = [];

    var uckerRadius = 15;


 
    //Colour - Shadow colour

    var green = ['#397D02', '#45623C'];
    var blue = ['#42C0FB', '#35586C'];
    var red = ['#F08080', '#6F4242'];
    var yellow = ['#FCB514', '#8E6B23'];

    var uckerColours = [green, blue, red, yellow];
    //Ucker Starting Positions  

    var greenStart = [new coordinate(90, 100), new coordinate(90, 165), new coordinate(165, 100), new coordinate(165, 165)];  

    var blueStart = [new coordinate(445, 445), new coordinate(445, 515), new coordinate(515, 445), new coordinate(515, 515)];  

    var redStart = [new coordinate(90, 445), new coordinate(90, 515), new coordinate(165, 445), new coordinate(165, 515)];  

    var yellowStart = [new coordinate(445, 100), new coordinate(445, 165), new coordinate(515, 100), new coordinate(515, 165)];  


    var uckerStart = [greenStart, blueStart, redStart, yellowStart];  
 

 
 
 
By using arrays we can then loop through and create the complete set of uckers and store them in a new array.


 
  var uckerSetup = function () {  
         for (var j = 0; j < uckerStart.length; j++) {  
             for (var i = 0; i < uckerStart[j].length; i++) {  
                 uckers.push(new ucker(uckerStart[j][i], uckerStart[j][i], uckerRadius, uckerColours[j]));  
             }  
         }  
     };  

 
 
When laying out the board we can then draw the uckers using their own object information.


  for (var i = 0; i < uckers.length; i++) {  
    drawUckers(context, uckers[i]);  
 }  
  
var drawUckers = function (ctx, u) { // draw circle function  
         ctx.fillStyle = u.color;  
         ctx.shadowOffsetX = 5;  
         ctx.shadowOffsetY = 5;  
         ctx.shadowBlur = 4;  
         ctx.shadowColor = u.shadow;
         ctx.beginPath();  
         ctx.arc(u.x, u.y, u.radius, 0, Math.PI * 2, true);  
         ctx.closePath();  
         ctx.fill();  
     };  

The background is a little simpler, we just add an image of an uckers board.


     var boardImage = new Image();  
     var bgReady = false;  

 
     boardImage.onload = function () {  
         bgReady = true;  
     };  

 
     boardImage.src = "/Images/uckersboard.png";  


     var loadBoard = function () {  
         theCanvas = $("#gameboard").get(0);  
         var context = theCanvas.getContext("2d");
        if (bgReady) {
            context.drawImage(boardImage, 5, 5); 
        } 
   }; 
 

Facebook, Twitter, Google+ and Microsoft Authentication.

Using MVC 4 makes this a lot simpler than it used to be.  But to ensure that it goes smoothly we need to make some simple changes.  The default MVC4 EF5 setup means that when we first run the program several files are used to initialise the database.  We can change this later using the package manager, but initially I created a blank database and changed the connection string.



Old


connectionstring="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-Uckers-20130606091131;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-Jannersoft.Demos.Uckers-20130606091131.mdf" name="DefaultConnection" providername="System.Data.SqlClient"

New

connectionstring="Data Source=.\sqlexpress;Initial Catalog=Uckers-Dev;Integrated Security=True" name="DefaultConnection" providername="System.Data.SqlClient"



The next stage is to add our keys to the Facebook auth config. In App_Start edit the AuthConfig.cs file and enable the FAcebook OAuth.


            OAuthWebSecurity.RegisterFacebookClient(
                            appId: "169767096406585",
                            appSecret: "c180be059c784d8cba0eb44379b34c11");

A large amount of creating an initial database and creating the new tables is done by the InitializeSimpleMembershipAttribute.cs class in the filters folder, with the AccountController.cs taking a lead role in handling the authentication either via site registration or via facebook.

It is also worthwhile before doing anything to have a look at the AccountModel.cs file.  This is where the UserContext is initialised and the stucture of the UserProfile.  It is worthwhile noting that changing the UserProfile class will have no effect on the table.  It will not add any extra colums nor will it work correctly if altered.  It is tied directly into the InitializeSimpleMembershipAttribute.cs file.  We will cover how to change this file later, but it involves playing with the package migration manager and adding code to the seed method.

Run this now and trying to login via facebook will fail, we need to tell facebook to allow the url we will be using.  I am using iis8 express, so I have changed the properties of the program.


Once you login via facebook new tables are created in the database.

Later on we are going to do more with the social media connection, but for now I want to concentrate on the game.  

The next stage would be to store details of the games and the players, to do this we are going to use the Code First approach to creating the tables.

Models And Enums


   [Table("Games")]  
   public class GameModel  
   {  
     [Key]  
     [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]  
     public Guid GameId { get; set; }  
     public List<Player> Players { get; set; }  
     public DateTime StartDate { get; set; }  
     public DateTime? EndDate { get; set; }  
   }  
   [Table("Players")]  
   public class Player  
   {  
     [Key]  
     [DatabaseGenerated(DatabaseGeneratedOption.None)]  
     public Guid PlayerId { get; set; }  
     public UserProfile User { get; set; }  
     #region EF4 method of Enum Handling  
     //public int PlayerSelectedColourEnumValue { get; set; }  
     //public SelectedColorEnum PlayerSelectedColor  
     //{  
     //  get { return (SelectedColorEnum)PlayerSelectedColourEnumValue; }  
     //  set { PlayerSelectedColourEnumValue = (int)value; }  
     //}  
     #endregion  
     public SelectedColorEnum PlayerSelectedColor { get; set; }  
   }  

Generating the Table (Code First)


This provided a basic initial setup, with a tweak or two, and it does build the tables

   public class GameDbContextInitializer : DropCreateDatabaseIfModelChanges<GamesContext>  
   {  
     protected override void Seed(GamesContext context)  
     {  
       var db = new UsersContext();  
       var userProfile = db.UserProfiles.FirstOrDefault();  
       var players = new List<Player>{ new Player{  
          PlayerSelectedColor = SelectedColorEnum.Blue, PlayerUser = userProfile}};  
       var games = new List<GameModel>  
       {  
         new GameModel{ StartDate = DateTime.UtcNow,  
            GameUser = userProfile, Players = players}  
       };  
       players.ForEach(p => context.Players.Add(p));  
       games.ForEach(g=> context.Games.Add(g));  
       context.SaveChanges();  
     }  
   }  

This does work if you are only using a single context that doesnt have complex joins to other databases.  In his example we are using the defaultConnnection to set up the database for UserProfile.

To get this to work on a single context just put the following code in the Glbal.asax Application_Start;

       Database.SetInitializer<GamesContext>(new GameDbContextInitializer());  

Using Package Manager Migration - Cleaner and recommended

http://msdn.microsoft.com/en-us/data/jj193542.aspx
Open the Package Manager Console.


run > Enable-Migrations -ContextTypeName Jannersoft.Demos.Uckers.Models.GamesContext.

This creates a new file configuration and folder migration.  This forms the basic structure required to allow the migration code and the update.  It also aids in the moving of the database from dev to prod.

run > Add-Migration InitialGameTables

Creates a migration class, which we need to make a few changes. Firstly, we need to remove the UserProfile table creattion as this has alread been created when we did the facebook part.

       CreateTable(  
         "dbo.Games",  
         c => new  
           {  
             GameId = c.Int(nullable: false, identity: true),  
             StartDate = c.DateTime(nullable: false),  
             EndDate = c.DateTime(),  
             GameUser_UserId = c.Int(),  
           })  
         .PrimaryKey(t => t.GameId)  
         .ForeignKey("dbo.UserProfile", t => t.GameUser_UserId)  
         .Index(t => t.GameUser_UserId);  
      // CreateTable(  
      //   "dbo.UserProfile",  
      //   c => new  
      //     {  
      //       UserId = c.Int(nullable: false, identity: true),  
      //       UserName = c.String(),  
      //     })  
      //   .PrimaryKey(t => t.UserId);  
       CreateTable(  
         "dbo.Players",  
         c => new  
           {  
             PlayerId = c.Int(nullable: false, identity: true),  
             PlayerSelectedColor = c.Int(nullable: false),  
             PlayerUser_UserId = c.Int(),  
             GameModel_GameId = c.Int(),  
           })  
         .PrimaryKey(t => t.PlayerId)  
         .ForeignKey("dbo.UserProfile", t => t.PlayerUser_UserId)  
         .ForeignKey("dbo.Games", t => t.GameModel_GameId)  
         .Index(t => t.PlayerUser_UserId)  
         .Index(t => t.GameModel_GameId);  

run > Update-Database

Then check the database for the tables.

Now that we have been able to generate the tables we can make changes to increase the usefulness of the UserProfile object..

Add new columns to the UserProfile object then run > Add-Migration UserProfileUpdate

  [Table("UserProfile")]  
   public class UserProfile  
   {  
     [Key]  
     [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]  
     public int UserId { get; set; }  
     public string UserName { get; set; }  
     public string FirstName { get; set; }  
     public string Surname { get; set; }  
     public string Email { get; set; }  
   }  
   public class RegisterExternalLoginModel  
   {  
     [Required]  
     [Display(Name = "User name")]  
     public string UserName { get; set; }  
     public string ExternalLoginData { get; set; }  
     public string FirstName { get; set; }  
     public string Surname { get; set; }  
     public string Email { get; set; }  
   }  


Making a dice

Making and handling the dice can be carried out with a separate JavaScript file, this separation allows later re-usage of the dice.

One of the important parts of this is understanding the business logic surrounding it.  The dice will become part of the canvas animation and as such the animation should take care of the final number to display.  the dice should only care about its own properties, dimensions and the number it should display.

It is also worthwhile noting that the click, and mouse are not events but true or false returns, perhaps I need to rename these.  With HTML5 the event is handled by the canvas.

 var Uckers = Uckers || {};  
 Uckers.Gameboard = Uckers.Gameboard || {};  
 Uckers.Gameboard.Dice = $.extend(Uckers.Gameboard.Dice || {}, function () {  
   var dx;  
   var dy;  
   var diceArray = [];  
   var horizontalLayout;  
   var diceGap = 100;  
   var radius;  
   var dheight;  
   var dwidth;  
   var dcanvas;  
   var faceStyle;  
   var die = function (posx, posy, num) {  
     this.dicex = posx;  
     this.dicey = posy;  
     this.num = num;  
   };  
   // posx = 630 posy = 50 height = 60 dotradius = 5 width = 60 face = #009966  
   var loadDice = function (canvas, posx, posy, width, height, dotradius, face, dieCount) {  
     for (var i = 0; i < dieCount; i++) {  
       diceArray.push(new die(posx, posy, 1));  
     }  
     radius = dotradius;  
     dheight = height;  
     dwidth = width;  
     dcanvas = canvas;  
     faceStyle = face;  
     setLayout(true);  
     drawDice();  
   };  
   var setLayout = function(isHorizontal) {  
     horizontalLayout = isHorizontal;  
   };  
   var drawface = function (n) {  
     var ctx = dcanvas.getContext("2d");  
     ctx.lineWidth = 5;  
     ctx.clearRect(dx, dy, dwidth, dheight);  
     ctx.strokeRect(dx, dy, dwidth, dheight);  
     ctx.fillStyle = faceStyle;  
     switch (n) {  
       case 1:  
         draw1(ctx);  
         break;  
       case 2:  
         draw2(ctx);  
         break;  
       case 3:  
         draw2(ctx);  
         draw1(ctx);  
         break;  
       case 4:  
         draw4(ctx);  
         break;  
       case 5:  
         draw4(ctx);  
         draw1(ctx);  
         break;  
       case 6:  
         draw4(ctx);  
         draw2Mid(ctx);  
         break;  
     }  
   };  
   var drawDice = function () {  
     for (var i = 0; i < diceArray.length; i++) {  
       //Get random dice number  
       diceArray[i].num = 1 + Math.floor(Math.random() * 6);  
       //check if vertical or horizontal layout  
       if (horizontalLayout) {  
         dx = diceArray[i].dicex + (diceGap * i);  
         dy = diceArray[i].dicey;  
       } else {  
         dx = diceArray[i].dicex;  
         dy = diceArray[i].dicey + (diceGap * i);  
       }  
       drawface(diceArray[i].num);  
     }  
     return diceArray;  
   };  
   var isMouseOnDice = function(e) {  
     var mouseX = e.offsetX || 0;  
     var mouseY = e.offsetY || 0;  
     for (var i = 0; i < diceArray.length; i++) {  
       if (mouseX > diceArray[i].minX && mouseX < diceArray[i].maxX && mouseY > diceArray[i].minY && mouseY < diceArray[i].maxY) {  
         return true;  
       }  
     }  
     return false;  
   };  
   var draw1 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + .5 * dwidth;  
     doty = dy + .5 * dheight;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw2 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + dheight - 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw4 = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + dheight - 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + dheight - 3 * radius; //no change  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + 3 * radius;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   var draw2Mid = function (ctx) {  
     var dotx;  
     var doty;  
     ctx.beginPath();  
     dotx = dx + 3 * radius;  
     doty = dy + .5 * dheight;  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     dotx = dx + dwidth - 3 * radius;  
     doty = dy + .5 * dheight; //no change  
     ctx.arc(dotx, doty, radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   };  
   return {  
     Initialize: loadDice,  
     Roll: drawDice,  
     DiceGap: diceGap,  
     IsHorizontalLayout: setLayout,  
     Click: isMouseOnDice,  
     MouseOver: isMouseOnDice,  
     MouseDown: isMouseOnDice,  
     MouseUp: isMouseOnDice,  
     Dice:diceArray  
   };  
 }());  

calling a dice

dice = Uckers.Gameboard.Dice;
        dice.Initialize(theCanvas, 630, 50, 60, 60, 4, '#009966', 2);

Adding a Dice Button

We could easily set up a small area to test for a mouse event but to be able to extend this button we can be a little more adventurous.

 Uckers.Gameboard.CanvasButton = $.extend(Uckers.Gameboard.Button || {}, function() {  
   var ctx;  
   var minX;  
   var minY;  
   var boxX;  
   var boxY;  
   var text;  
   var textColor;  
   var fillColor;  
   var lineColor;  
   var lineWidth;  
   var font;  
   var width;  
   var height;  
   var btn = function() {  
     this.canvas = arguments[0].canvas || $("canvas").get(0);  
     this.ctx = arguments[0].ctx || this.canvas.getContext("2d");  
     this.text = arguments[0].text || "Submit";  
     this.textColor = arguments[0].color || "#5E5E5E";  
     this.fontSize = arguments[0].fontSize || 18;  
     this.fontTypeFace = arguments[0].fontTypeFace || "sans-serif";  
     this.font = arguments[0].font || this.fontSize + "px " + this.fontface;  
     this.ctx.font = this.font;  
     this.width = arguments[0].width || this.ctx.measureText(this.text).width;  
     this.height = arguments[0].height || this.fontSize;  
     this.minX = arguments[0].posx || this.canvas.width;  
     // this.maxX = this.minX + this.width ;  
     this.minY = arguments[0].posy || this.canvas.height;  
     // this.maxY = this.minY + this.height ;  
     this.id = arguments[0].id || "undefined";  
     this.active = true;  
     this.lineColor = arguments[0].linecolor || "#FFFF00";  
     this.lineWidth = arguments[0].linewidth || 1;  
     this.fillColor = arguments[0].fillcolor || "00FFFF";  
     this.borderWidth = arguments[0].boarderwidth || 2;      
     ctx = this.ctx;  
     minX = this.minX;  
     minY = this.minY;  
     text = this.text;  
     textColor = this.textColor;  
     fillColor = this.fillColor;  
     lineColor = this.lineColor;  
     lineWidth = this.lineWidth;  
     font = this.font;  
     width = this.width + 15;  
     height = this.height + 4;  
     drawLabel();  
     this.click = function(e) {  
       var mouseX = e.offsetX || 0;  
       var mouseY = e.offsetY || 0;  
       return mouseX > boxX && mouseX < (boxX + width) && mouseY > boxY && mouseY < (boxY + height) && this.active;  
     };  
   };  
   var settext = function() {  
     text = arguments[0].text || "Submit";  
     textColor = arguments[0].color || "#5E5E5E";  
     this.fontSize = arguments[0].fontSize || 18;  
     this.fontTypeFace = arguments[0].fontTypeFace || "sans-serif";  
     font = arguments[0].font || this.fontSize + "px " + this.fontface;  
     ctx.font = font;  
     width = (arguments[0].width || ctx.measureText(this.text).width) + 15;  
     height = (arguments[0].height || this.fontSize) + 4;  
     drawLabel();  
   };  
   var drawLabel = function() {  
     ctx.lineWidth = 2;  
     boxX = minX - 5;  
     boxY = minY - 15;  
     ctx.clearRect(boxX, boxY, width, height);  
     ctx.strokeRect(boxX,boxY, width, height);  
     ctx.fillStyle = fillColor;  
     ctx.lineWidth = lineWidth;  
     ctx.fillStyle = textColor;  
     ctx.lineStyle = lineColor;  
     //calculate the center position for the text  
     // width of the box minus the width of the text divide by two then add to the posx  
     var textPos = (width - ctx.measureText(text).width) / 2;  
     ctx.fillText(text, minX + textPos, minY);  
   };  
   return {  
     Button: btn,  
     Text : settext  
   };  
 }());  

Setup the button

diceButton = new Uckers.Gameboard.CanvasButton.Button({ ctx: context, posx: 660, posy: 135, text: "Stop!" });

Placing the Uckers

The initail placement of the uckers is a two stage process.  Trying to keep this to the client model update and instantiate the uckers from the javascript.  We could make a call to the server and request the locations and update from a Json response, but we need to think about the number of server calls during the initial setup.  We could lso make it part of the model and load this onto the page, but again it come to decide on where the balance of saving this information is kept.  In this case we are going to save this as part of the javascript and do all the work in a single hit.

  var uckers = [];  
   var uckerRadius = 15;  
   //Colour - Shadow colour  
   var green = ['#397D02', '#45623C', "green"];  
   var blue = ['#42C0FB', '#35586C', "blue"];  
   var red = ['#F08080', '#6F4242', "red"];  
   var yellow = ['#FCB514', '#8E6B23', "yellow"];  
   var uckerColours = [green, blue, red, yellow];  

In the section above we layout the basic information about an ucker, we then send this to an ucker object and save this in an array of uckers.
   var ucker = function (coord, target, radius, color, name) {  
     this.uckerId = 0;  
     this.name = name;  
     this.x = coord.x;  
     this.y = coord.y;  
     //target [4,1] target A = [0,0] = x, [0,1] = y, Target B = [1,0] = x, [1,1] = y  
     this.target = target;  
     this.selectedtargetx;  
     this.selectedtargety;  
     this.radius = radius;  
     this.color = color[0];  
     this.shadow = color[1];  
     this.colors = color;  
     this.boardPosition = 0;  
     this.IsActive = false;  
   };  

We use a couple of extra object in this, but one of the things that spring out is the Target.  This is a set of co-ordinates for this ucker.  As there are two dice, an ucker could have the potential to move to either.  Once an ucker is selected (after the dice is selected) the it is moved to the selected target.

Here is the JavaScript in it's full.

 var Uckers = Uckers || {};  
 Uckers.Gameboard = Uckers.Gameboard || {};  
   
 Uckers.Gameboard.Ucker = $.extend(Uckers.Gameboard.Ucker || {}, function () {  
   
   var coordinate = function (x, y) {  
     this.x = x;  
     this.y = y;  
   };  
   
   //Ucker Starting Positions  
   var greenStart = [new coordinate(90, 100), new coordinate(90, 165), new coordinate(165, 100), new coordinate(165, 165)];  
   var blueStart = [new coordinate(445, 445), new coordinate(445, 515), new coordinate(515, 445), new coordinate(515, 515)];  
   var redStart = [new coordinate(90, 445), new coordinate(90, 515), new coordinate(165, 445), new coordinate(165, 515)];  
   var yellowStart = [new coordinate(445, 100), new coordinate(445, 165), new coordinate(515, 100), new coordinate(515, 165)];  
   
   //Colour - Shadow colour  
   var green = ['#397D02', '#45623C', "green"];  
   var blue = ['#42C0FB', '#35586C', "blue"];  
   var red = ['#F08080', '#6F4242', "red"];  
   var yellow = ['#FCB514', '#8E6B23', "yellow"];  
   
   var uckerStart = [greenStart, blueStart, redStart, yellowStart];  
   
   var uckerRadius = 15;  
   
   var uckers = [];  
   
   var ucker = function (coord, target, radius, color) {  
     this.uckerId = 0;  
   
     this.radius = radius;  
     this.x = coord.x;  
     this.y = coord.y;  
   
     this.boardPosition = 0;  
     //target [4,1] target A = [0,0] = x, [0,1] = y, Target B = [1,0] = x, [1,1] = y  
     this.target = target;  
     this.selectedtargetx;  
     this.selectedtargety;  
   
     this.colors = color;  
     this.color = color[0];  
     this.shadow = color[1];  
     this.name = color[2];  
   
     this.IsActive = false;  
   };  
   
   var uckerSetup = function () {  
     for (var j = 0; j < uckerStart.length; j++) {  
       for (var i = 0; i < uckerStart[j].length; i++) {  
         uckers.push(new ucker(uckerStart[j][i], uckerStart[j][i], uckerRadius, uckerColours[j]));  
       }  
     }  
   };  
   
   var drawUckers = function (ctx, u) { // draw circle function  
     ctx.fillStyle = u.color;  
     ctx.shadowOffsetX = 5;  
     ctx.shadowOffsetY = 5;  
     ctx.shadowBlur = 4;  
     ctx.shadowColor = u.shadow;  
     ctx.beginPath();  
     ctx.arc(u.x, u.y, u.radius, 0, Math.PI * 2, true);  
     ctx.closePath();  
     ctx.fill();  
   
     //reset shaddows so it doesnt affect teh background  
     ctx.shadowOffsetX = 0;  
     ctx.shadowOffsetY = 0;  
     ctx.shadowBlur = 0;  
   };  
   
   var getUckerColor = function (c) {  
     for (var i = 0; i < uckerColours.length; i++) {  
       if (uckerColours[i][2] == c) {  
         return uckerColours[i];  
       }  
     }  
     return null;  
   };  
   
   var uckerEvent = function (mouseX, mouseY) {  
     for (var j = 0; j < Ucker.uckers.length; j++) { // checking through all circles - are mouse down inside circle or not  
       var uckerX = Ucker.uckers[j].x;  
       var uckerY = uckers[j].y;  
       var radius = uckers[j].radius;  
       if (Math.pow(mouseX - uckerX, 2) + Math.pow(mouseY - uckerY, 2) < Math.pow(radius, 2) && uckers[j].IsActive) {  
         //Check to see if the selected ucker is home  
   
         var coord = new coordinate(uckerX, uckerY);  
         uckers[j] = new ucker(coord, target, radius, uckers[j].colors);  
         break;  
       }  
     }  
   };  
   
   var getAllUckers = function () {  
     return uckers;  
   };  
   
   var drawUckers = function (ctx) {  
     for (var i = 0; i < uckers.length; i++) {  
       drawUckers(ctx, uckers[i]);  
     }  
   };  
   
   var initialise = function () {  
     uckerSetup();  
   };  
   
   return {  
     Initailize: initialise,  
     GetUckerColor: getUckerColor,  
     Uckers: getAllUckers,  
     DrawUckers: drawUckers,  
     Ucker: ucker,  
     UckerEvent: uckerEvent  
   }  
   
 }());  


In Part two we will be doing a lot more with the following:

Setting up Players

Sending JSON

Responding to JSON

Storing Data

End of Turn