Entity Framework: Identity Errors

If you create a table with a PK that is not identity and then create a EF class from that and then try and load in an empty value, you get a System.Data.Update exception:

image

 

If you go ahead and change the server to identity without updating EF on your client, you still get a System.Data.Update exception, but with a different inner exception:

image

What you need to do is to fix it by changing to identity and then updating the EF on the client:

image

Volia: the change will now persist

However, if you create a PK on an existing table where there used to be a Implied key, you get an error. You need to drop the table and re-create.

What a drag

I am getting more into the details of the User Interface of the WinPhone7 game I am writing. I am using the ScrollViewer and the WindowPhone Toolkit.

Using the ScrollViewer_ManipulationStarted event handler, I check to see if there is a hex active. If it is, I call the e.complete() method so that we don’t scroll off the screen where the active hex is.

Using that model, I wanted to use the Tap and Drag completed events from the Toolkit. If the user taps a hex, that hex becomes active. They tap that active hex again, then the hex becomes inactive:

private void GestureListener_Tap(object sender, Microsoft.Phone.Controls.GestureEventArgs e) { Hex closestHex = GetClosestHex(e.GetPosition(this.MainCanvas)); if (Game.ActiveHex == null) { EnableGameActiveHex(closestHex); } else { if (Game.ActiveHex == closestHex) DisableGameActiveHex(); } }

That works fine:

image

I then wanted to code up the drag event. If there is not an active hex, then dragging should do nothing and the scroll viewer will allow the user to inspeact any part of the board. If there is an active hex and there is not a unit in that hex, then nothing should happen. If there is an active hex and there is an active unit in that hex, then the unit should “move” to the hex where the drag completed (and the hex becomes inactive).

To that end, I coded up a quick event handler:

private void GestureListener_DragCompleted(object sender, Microsoft.Phone.Controls.DragCompletedGestureEventArgs e) { if (Game.ActiveHex != null) { Hex closestHex = GetClosestHex(e.GetPosition(this.MainCanvas)); if (Game.ActiveHex.CurrentUnit != null) { MoveGameActiveUnit(closestHex); } DisableGameActiveHex(); } }

Toolkit does not have an e.complete() method so I couldn’t call that on the drag end – but since I don’t enter the drag unless the hex is active, I should be OK.

Next, I added movement allowances to the active unit based on the movement cost of each hex. Like last week’s post on recursion, I created a monster method and used the VS2010 extract method to make the code, well, suck less. To that end, I created a method that all of the movable hexes for the unit based on their max movement points.

private static List<Hex> GetMovableHexes(Hex startHex) { List<Hex> movableHexes = new List<Hex>(); List<Hex> tempHexes = new List<Hex>(); Unit currentUnit = startHex.CurrentUnit; int totalMovementPoints = currentUnit.BaseMovement; int unitMovementCost = 0; int pathMovementCost = 0; List<Hex> adjacentHexes = GetAdjacentHexes(startHex); startHex.PathMovementCost = pathMovementCost; foreach (Hex currentHex in adjacentHexes) { unitMovementCost = HexFactory.CalculateMovementCost(currentHex, currentUnit); pathMovementCost = pathMovementCost + unitMovementCost; if (pathMovementCost <= totalMovementPoints) { currentHex.PathMovementCost = pathMovementCost; movableHexes.Add(currentHex); } pathMovementCost = 0; } for (int i = 0; i < currentUnit.BaseMovement; i++) { DetermineMovableHexes(movableHexes, tempHexes, currentUnit, totalMovementPoints, ref unitMovementCost, ref pathMovementCost, ref adjacentHexes); } return movableHexes; }

 

I then determined if I could get to the hex from the current location (note the argument overload from VS2010 Extract Method):

private static void DetermineMovableHexes(List<Hex> movableHexes, List<Hex> tempHexes, Unit currentUnit, int totalMovementPoints, ref int unitMovementCost, ref int pathMovementCost, ref List<Hex> adjacentHexes) { foreach (Hex currentHex in movableHexes) { adjacentHexes = GetAdjacentHexes(currentHex); foreach (Hex tempHex in adjacentHexes) { unitMovementCost = HexFactory.CalculateMovementCost(tempHex, currentUnit); if (tempHex.CurrentTerrain.RiverInd == true && tempHex.CurrentTerrain.RoadInd == false) { unitMovementCost = 99; } pathMovementCost = currentHex.PathMovementCost + unitMovementCost; if (pathMovementCost <= totalMovementPoints) { if (currentHex.PathMovementCost < pathMovementCost) tempHex.PathMovementCost = pathMovementCost; tempHexes.Add(tempHex); } pathMovementCost = 0; } } foreach (Hex hex in tempHexes) { var q = (from Hex h in movableHexes where h.HexId == hex.HexId select h).FirstOrDefault(); if (q == null) { movableHexes.Add(hex); } } }

Basically, each hex has 2 movement points – the cost for the hex by itself and then the cumulative cost for the hex as part of a path. If the path is too much, the hex is not selected. By looping though each hex then its adjacent hexes, all possible paths are covered. The results look good:

image

Up next – having the unit attack another unit. Fun!

Visual Studio 2010 Extract Method

A common joke is that more CPU cycles are wasted than are actually used on a typical desktop computer.  Personally, I feel the same way about Visual Studio – I feel like I only use 25% of its capabilities.  I ran into a great refactoring problem over the weekend that demonstrated a really cool feature of VS2010 that literally saved me hours of wasted effort.

As you know, I am working on a Windows Phone 7 port of the timeless classic Panzer General.  I am have gotten the board set up with icons, but I want to know determine the acceptable movement and line of site for an individual unit.  To do so, I would need to loop over all adjacent hexes and see if they were close to the unit – and then loop over those hexes adjacent hexes until I was past an X distance.

I first tried to whip up a recursive method to do this – and after 1 hour or so, I was failing miserably.  I then decided to take a different approach – I hand-wrote each loop (hard coded in) like so:

private static List<Hex> GetTotalAdjacentHexes(Hex currentHex, Int32 maxDistance) { List<Hex> hexes = new List<Hex>(); List<Hex> tempList = GetAdjacentHexes(currentHex); foreach (Hex hex in tempList) { hex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex); var tempList2 = GetAdjacentHexes(hex); foreach (Hex hex2 in tempList2) { hex2.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex2); var tempList3 = GetAdjacentHexes(hex2); foreach (Hex hex3 in tempList3) { hex3.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex3); var tempList4 = GetAdjacentHexes(hex3); foreach (Hex hex4 in tempList4) { hex4.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex4); } } } } return hexes; }

The thing is – it works:

image

After an hour of trying to hand-write recursion, I went a different direction – parse out each piece and let VS2010 help me. I too the last for..each (hex4…) and put it into a new method

Just following the default naming conventions, I now have 4 methods that look eerily similar:

private static List<Hex> GetTotalAdjacentHexes(Hex currentHex, Int32 maxDistance) { List<Hex> hexes = new List<Hex>(); List<Hex> tempList = GetAdjacentHexes(currentHex); NewMethod(currentHex, hexes, tempList); return hexes; } private static void NewMethod(Hex currentHex, List<Hex> hexes, List<Hex> tempList) { foreach (Hex hex in tempList) { hex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex); var tempList2 = GetAdjacentHexes(hex); NewMethod2(currentHex, hexes, hex, tempList2); } } private static void NewMethod2(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> tempList2) { foreach (Hex hex2 in tempList2) { hex2.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex2); var tempList3 = GetAdjacentHexes(hex2); NewMethod1(currentHex, hexes, hex, tempList3); } } private static void NewMethod1(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> tempList3) { foreach (Hex hex3 in tempList3) { hex3.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex3); var tempList4 = GetAdjacentHexes(hex3); NewMethod(currentHex, hexes, hex, tempList4); } } private static void NewMethod(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> tempList4) { foreach (Hex hex4 in tempList4) { hex4.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(hex4); } }

You can notice that the 3 final methods all have the same signature. The first thing I did was to make the internal variables sufficiently generic, for example:

private static void NewMethod(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> currentList) { foreach (Hex tempHex in currentList) { tempHex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(tempHex); } }

I then realized that there are 3 groups of methods. Method Type 1 is for the 1st time through; Method Type 2 is for second to total-1 times through; and Method Type 3 is for the last time.

Concentrating on Type 2 for a second, you can see that they are identical except that 1 calls the other. That seems like a prime candidate for recursion:

private static void NewMethod2(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> currentList) { foreach (Hex tempHex in currentList) { tempHex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(tempHex); List<Hex> tempList = GetAdjacentHexes(tempHex); NewMethod1(currentHex, hexes, hex, tempList); } }

I changed this line:

NewMethod1(currentHex, hexes, hex, tempList);

To this:

NewMethod2(currentHex, hexes, hex, tempList);

And hit F5 and got this after a delay:

image

Which is another way of saying out of memory… Basically, there is no way out of the for…each without some kind of counter. So I threw a counter into the method and assigned a magic number of 2 (note the last time though, it only assigns and does not recurse. if I added the counter above the for..each, then the last time though would not assign):

private static void NewMethod2(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> currentList, int counter) { counter++; { foreach (Hex tempHex in currentList) { tempHex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(tempHex); if (counter < 2) { List<Hex> tempList = GetAdjacentHexes(tempHex); NewMethod2(currentHex, hexes, hex, tempList, counter); } } } }

Sure enough, it worked. I then tackled the 1st method by adding hat counter variable and a Hex parameter that is initially placed with the 1st loop though of the collection and then I renamed the method:

private static List<Hex> GetTotalAdjacentHexes(Hex currentHex, Int32 maxDistance) { List<Hex> hexes = new List<Hex>(); List<Hex> tempList = GetAdjacentHexes(currentHex); foreach (Hex hex in tempList) { GetAdjacentHexes(currentHex, hexes, hex, tempList, 0, maxDistance); } return hexes; } private static void GetAdjacentHexes(Hex currentHex, List<Hex> hexes, Hex hex, List<Hex> currentList, int distanceCounter, int maxDistance) { distanceCounter++; { foreach (Hex tempHex in currentList) { tempHex.MovementCost = HexFactory.CalcualteMovementCost(hex, currentHex.CurrentUnit); hexes.Add(tempHex); if (distanceCounter < maxDistance) { List<Hex> tempList = GetAdjacentHexes(tempHex); GetAdjacentHexes(currentHex, hexes, hex, tempList, distanceCounter, maxDistance); } } }

Voila. A working recursive method (that is begging to be refactored even more). Undoubtedly, VS2010 and its extract method refactoring saved me hours.

WP7 and the Phone Controls Toolkit

I started hooking up events to my Panzer General Port over the weekend.  There are some see events I want to capture and react to: a tap to activate a cell, a double tap to display information about the cell, a pinch to make the screen smaller or larger, and a swipe to move to a different location on the screen.  Of these event, the pinch was the easiest to handle:

private void GestureListener_PinchCompleted(object sender, Microsoft.Phone.Controls.PinchGestureEventArgs e) { if (e.DistanceRatio < 1) { if (Game.CurrentViewLevel > 1) { Game.CurrentViewLevel--; UpdateHexes(); } } else { if (Game.CurrentViewLevel < 3) { Game.CurrentViewLevel++; UpdateHexes(); } } }

with the UpdateHexes basically redrawing the hexes that make up the board:

private void UpdateHexes() { this.MainCanvas.Children.Clear(); Game.CurrentBoard = BoardFactory.GetBoard(1); foreach (Hex hex in Game.CurrentBoard) { this.MainCanvas.Children.Add(hex); } this.MainCanvas.Width = BoardFactory.BoardWidth; this.MainCanvas.Height = BoardFactory.BoardHeight; }

It works great – here is the same view with the different zoom levels.

image

One of the more annoying things is that the screen “bounces” when you drag it past its designated screen size.  Apparently, this is by design and no one has an easy way to disable this “feature”.  You can ready my dialog on AppHub here.

The next event was the tap.  This was easy to implement on the hex level, however, it was really hard to implement on the board level.  I need it at the board level because the Hex class is unaware of its surroundings and many of the units actions in the game are dependent on its surroundings – what hexes it can go to, can it attack, etc…  I solved this problem with alot of trial and error and my old friend, the Pythagoriem Theorem:

private static Hex GetClosestHex(Point point) { double testDistance = 0; double finalDistance = 99999; Hex closestHex = null; double a = 0; double b = 0; foreach (Hex hex in Game.CurrentBoard) { a = point.X - hex.CenterPoint.X; b = point.Y - hex.CenterPoint.Y; testDistance = Math.Sqrt(a * a + b * b); if (testDistance < finalDistance) { finalDistance = testDistance; closestHex = hex; } } return closestHex; }

The point is found in EventArgument for both Tap, Dopuble Tap, Drag Complete events:

private void GestureListener_Tap(object sender, Microsoft.Phone.Controls.GestureEventArgs e) { Hex closestHex = GetClosestHex(e.GetPosition(this.MainCanvas)); if (closestHex.CurrentUnit != null) UpdateHexes(closestHex); }

I finally added in a Kludge to determine the adjacent hexes for the selected hexes like so:

private static List<Hex> GetAdjacentHexes(Hex currentHex) { List<Hex> adjacentHexes = new List<Hex>(); //Above int targetColumnNumber = currentHex.ColumnNumber; int targetRowNumber = currentHex.RowNumber - 1; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); //Below targetColumnNumber = currentHex.ColumnNumber; targetRowNumber = currentHex.RowNumber +1 ; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); //Top Left targetColumnNumber = currentHex.ColumnNumber -1 ; if (currentHex.ColumnNumber % 2 == 0) targetRowNumber = currentHex.RowNumber - 1; else targetRowNumber = currentHex.RowNumber; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); //Bottom Left targetColumnNumber = currentHex.ColumnNumber - 1; if (currentHex.ColumnNumber % 2 == 0) targetRowNumber = currentHex.RowNumber; else targetRowNumber = currentHex.RowNumber +1; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); //Top Right targetColumnNumber = currentHex.ColumnNumber + 1; if (currentHex.ColumnNumber % 2 == 0) targetRowNumber = currentHex.RowNumber - 1; else targetRowNumber = currentHex.RowNumber; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); //Bottom Right targetColumnNumber = currentHex.ColumnNumber + 1; if (currentHex.ColumnNumber % 2 == 0) targetRowNumber = currentHex.RowNumber; else targetRowNumber = currentHex.RowNumber +1; adjacentHexes.Add(GetHex(targetColumnNumber, targetRowNumber)); return adjacentHexes; } private static Hex GetHex(int targetColumnNumber, int targetRowNumber) { Hex targetHex = (from hex in Game.CurrentBoard where hex.ColumnNumber == targetColumnNumber && hex.RowNumber == targetRowNumber select hex).First(); if (targetHex != null) return targetHex; else return null; }

 

Note how the LINQ makes for search for the correct hex a snap.  I know have a way of detecting the selected hexs, surrounding hexes for units, and moving units to an end of a swipe:

image

 

This is all very cool (and very easy in Silverlight).  Up next is how to handle 2 unit interaction….