My thoughts on HTML5 at Microsoft TechDays 2011

I’m beginning to neglect this blog as much as the Year of Frugal Gaming that I also write for (check it out, our glorious leader Frugal Dave recently picked up a stylish blogger award! I’m thrilled to be in such company!) and I’ve written a post over there on what I’ve been up to gaming wise.

I’ve been lucky enough to go to TechDays in London again this year – I’m definitely the “community” guy in our team, seeking out user groups, conferences, blogs and podcasts. I’m of the mind that you need to be plugged into all these things to know what’s available. When all you have is a hammer everything looks like a nail, as the old saying goes, and I want to have as many different types of hammer as possible. It does come at a slightly bad time, however, as my wife is expecting to drop another baby in just over two weeks (and last night was a sleepless one of false alarms, before a 4:15 alarm in order to head to London for TechDays…) and I’m planning on staying in the capital tonight rather than travel all the way back to Bristol, and return to London again tomorrow. If I get “that call” I’ll have to race for the tube station and get back in time!

Anyway, I’ve already been to the Monday event on “The Web” (a discussion of HTML5, CSS3, IE9 and other sequels). I’m very impressed, but also a little melancholy. What I took away from there is that I can now create great looking sites without having an abundance of <div> elements and interlocking images to create a box with rounded corners, I can just do it in CSS. Except, for almost anything, our designers want their design to appear in every browser. This means that we can’t use the new hotness because it won’t show up in IE8 and below, which still have a considerable market share. We’re only now convincing people to let us build sites that degrade “gracefully” in IE6, since it takes a disproportionate amount of time to make a site look like it should in IE6. Now we’ve got the luxury of saying “That’s a bit too hard, I’m just going to make it square.” We can’t use the same excuses for IE8, which is the default browser for Windows 7 – only a couple of years old.

On a personal site, or if we had trendier clients – the kind who care more about seeming new and cutting edge, with things floating all over the page, the sort of thing that grinds to a halt on a slow PC – there would be plenty of scope for this new technology. But as it stands, HTML5 compliance is low enough that we won’t be able to pick it up just yet.

Microsoft did put on a great show though, getting in experts on CSS and HTML from outside their own company (heck, they had a speaker from Opera – probably because Mozilla or Google turned them down!) and giving a little poke at themselves about IE6. Oh, IE6.

I’m keen to get to use HTML5, but the day job isn’t going to be the place to do that. I’m still working on an intranet app that breaks – actual functionality breaks, not just styles – if it’s not used in IE7 (compatibility mode in 8 and 9 are fine), and our external websites need to look the same across browsers. We can’t just pretend that all IE users are on version 9, that’s not realistic and won’t make customers very happy. It doesn’t matter if it degrades gracefully, the design decisions would be so different in most cases (three <div> tags with separate background images for a repeated news item to give it rounded corners, or one <div> and no images to do it all with fancy CSS3?) that it can’t look “correct” without major javascript hacks which probably involve inserting all the HTML that we were going to in the first place, and still work in the newer HTML 5 browsers. The only difference is that it won’t have such pleasant markup for the developers (or the geeks who view source on websites they visit) to read.

This problem isn’t going to go away – Vista shipped with IE7, so that’s going to be supported for a fair while yet. IE6 shipped with XP, and since XP is still supported until about 2014 at last count. That means that IE6 is still officially supported by Microsoft until 2014. Vista won’t roll off until 2019 (at a guess), and Windows 7 (which contains IE8) will probably be into 2022 or so. For another five years (being optimistic), we have to assume that non-technical people (the majority of those that visit our company’s sites) will be using the browser they installed with their operating system and never upgrading, and the majority of market share will be held by non-HTML5 compliant browsers. Hopefully, Microsoft will make more websites like www.theie6countdown.com, which tells us when we can officially ditch IE6 country by country. It won’t be long, and we can assume that anyone hitting our sites from IE6 will be Chinese and therefore unlikely to buy our products!

Learning Unit Testing XI – Difficult Terrain Is Difficult

As the title clearly states, difficult terrain is going to be hard. It will involve a replacement of the ‘get distance’ code that takes into account that strict distances are not the same as movement distances – the idea that four inches of distance may cost five, six or more inches of movement (which is what counts for running, charging, and moving in general).

Because of this difficulty, my current inability to devise a solution, and my need to get moving on other things immediately (time on this project is limited, and I would rather move on than get stuck in design hell that maybe I should have sorted out sooner) I will be abandoning the Movement phase for the infinitely more interesting Shooting phase. It actually looks slightly easier, but I’m sure that’ll be remedied when I get to the rules for weapons and skills.

Unlike movement, which started to bog down the Model class, I’m going to try and keep all shooting related code in the shooting manager. Again, having an inkling of what the skills and weapons rules are going to do later, I believe this will make things a lot easier.

The first thing written down is defining who can shoot – Any model can shoot as long as it’s armed with a missile weapon, is not in hand-to-hand combat, can see a target, didn’t run or charge and is not hiding. This seems like a sensible thing to write a checking method for, and a little raft of tests. Time for a new test class, and also (finally) a test helper.

class TestHelper
{
public static IGameManager GetMockGameManager(IModel testModel, IObjectManager objectManager, int numberOfEnemies, int numberOfAllies)
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
List<IModel> modelList = new List<IModel>();
modelList.Add(testModel);
for (int i = 0; i < numberOfAllies; i++)
{
modelList.Add(new Model(testModel.Player, mockGameManager.Object, objectManager));
}
for (int i = 0; i < numberOfEnemies; i++)
{
modelList.Add(new Model(testModel.Player + 1, mockGameManager.Object, objectManager));
}
mockGameManager.Setup(item => item.Models).Returns(modelList);
return mockGameManager.Object;
}
}
[TestClass]
public class ShootingManagerTests
{
[TestMethod]
public void CanShoot_ReturnsTrue_IfEverythingCorrect()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsTrue(shootingTest.CanShoot(model));
}
}

Right, a lot of ‘generate class’ and ‘generate stub’ later (the ctrl+. shortcut is my friend) and the library compiles again. I intend for all missile weapons (that need special functionality not covered by the basic rules) to inherit from MissileWeapon, which ought to cover the majority of things. Weapons is a list of IWeapon (implemented by MissileWeapon), Direction is just an integer describing the angle the model faces (assuming a top-down view), and ShootingManager is quite an empty class at the moment. Following TDD pretty strictly, to pass this test it becomes:

public class ShootingManager
{
public bool CanShoot(Model model)
{
bool canShoot = true;
return canShoot;
}
}

But of course, that’s not quite right. Here’s a few more tests.

[TestMethod]
public void CanShoot_ReturnsFalse_IfRunning()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = true;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfCharging()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = true;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfHiding()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = true;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And what do all those lines of code need to make them pass?

public bool CanShoot(Model model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
return canShoot;
}

It’s almost insulting. The next one should be a bit more of a challenge:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoMissileWeapon()
{
Model model = new Model(1, null, null);
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}
[TestMethod]
public void CanShoot_ReturnsFalse_IfOnlyMeleeWeapons()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MeleeWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And these are solved by:

public bool CanShoot(Model model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

Linq makes things a little bit too easy these days… The next test checks if the model can see an opponent:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoEnemyInSight()
{
Model model = new Model(1, null, null);
model.Weapons.Add(new MissileWeapon());
TestHelper.GetMockGameManager(model, null, 1, 0);
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 0;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

As expected, it fails. The only difference to the original ‘everything is fine’ test case is the direction that the model is facing – a model can only see in a 90 degree arc to it’s front, so by turning it completely around it should be unable to see the enemy properly. The calculations on the abstract ObjectManager should reflect this, so an extra method in ObjectManager that is exposed (slightly) through Model will help out.

First off – a lot of tests break. This is because the models have been set up with null object managers, which obviously throw exceptions when the call to check them for models in sight occurs. In refactoring to get the first test (pass if all clear) passing, references and parameters were shifted from Model to IModel, things were added to IModel,and in general a bit of housekeeping took place. Here is the new ‘all clear’ test:

[TestMethod]
public void CanShoot_ReturnsTrue_IfEverythingCorrect()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(gameManager.Models);
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsTrue(shootingTest.CanShoot(model));
}

With similar ‘setup’ code to the subsequent tests to get them all passing. The improved ‘new’ test:

[TestMethod]
public void CanShoot_ReturnsFalse_IfNoEnemyInSight()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(new List<IModel>());
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 0;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And finally, the code to pass it:

public bool CanShoot(IModel model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
if ((from target in model.GetModelsInSight(90)
where target.Player != model.Player
select target).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

With one small addition to the Model class:

public List<IModel> GetModelsInSight(int angleOfSight)
{
List<IModel> modelsInSight = new List<IModel>();
modelsInSight = _objectManager.GetModelsInSight(this, _gameManager.Models, angleOfSight);
return modelsInSight;
}

Finally, one more test and the ‘who can shoot’ question is completely answered. Models cannot shoot if they’re already in hand-to-hand combat. A simple boolean property (the exact circumstances of being able to set it will be complicated, but that’s a problem for later) on the Model and IModel, adding it as an explicit ‘false’ parameter in the other CanShoot tests, and it’s own test case:

[TestMethod]
public void CanShoot_ReturnsFalse_IfModelInHandToHandCombat()
{
IModel model = new Model(0, null, null);
IGameManager gameManager = TestHelper.GetMockGameManager(model, null, 1, 0);
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockObjectManager.Setup(item => item.GetModelsInSight(It.IsAny<IModel>(), gameManager.Models, 90)).Returns(gameManager.Models);
model = new Model(1, gameManager, mockObjectManager.Object);
model.Weapons.Add(new MissileWeapon());
model.Location = new LocationPoint(0, 1, 0);
model.Direction = 180;
model.IsCharging = false;
model.IsHiding = false;
model.IsRunning = false;
model.IsInHandToHandCombat = true;
ShootingManager shootingTest = new ShootingManager();
Assert.IsFalse(shootingTest.CanShoot(model));
}

And the complete CanShoot code to pass it:

public bool CanShoot(IModel model)
{
bool canShoot = true;
if (model.IsRunning == true || model.IsHiding == true || model.IsCharging == true || model.IsInHandToHandCombat == true)
{
canShoot = false;
}
if (model.Weapons.Where(item => (item as MissileWeapon) != null).Count() == 0)
{
canShoot = false;
}
if ((from target in model.GetModelsInSight(90)
where target.Player != model.Player
select target).Count() == 0)
{
canShoot = false;
}
return canShoot;
}

And it leaves me at a good point to finish off for this section. The next section will be the Closest Target rules, which I’ve already given some thought to – but my word count here is already over 1500, so it’s probably best to clock off!

Book Review – Pride and Prejudice and Zombies

Product DetailsI recently finished reading Pride and Prejudice and Zombies by Seth Grahame-Smith and Jane Austen (allegedly), which I’d found brand-new and mint condition in a charity shop for £1.50. That’s definitely worth a punt!

Overall, I found it a good read. I have read the ‘original’, and even seen TV adaptations of it, but to be totally honest that was in school and I’m not even sure there was any work or essay involved in it beyond just going through the motions of reading it as a class, and/or watching the television. I can sum up my total knowledge of it before I read this book as “Many Bennett sisters want to get married, there is a mean guy named Darcy who Elizabeth hates.” Which is probably the ground-state of knowledge, like what everyone knows about Superman, Romeo and Juliet, or Macbeth.

There were parts of And Zombies that made me think they were poking fun at or paying homage to the original in a way that is opaque to outsiders but absolutely obvious to someone familiar with the work. One chapter, which was only a paragraph long, summed up a whole journey as essentially not worth writing about. Does the original book go into lavish detail of the countryside passed and the entire trip’s trivia? I know Tess of the D’Urbervilles was far over the top as a traveller’s almanac, but I honestly can’t remember enough of Pride and Prejudice to say the same.

In some places, I had to scoff and thought it was going a little over the top – Elizabeth ripping out the still beating heart of a ninja in front of a noblewoman, for instance. But it was still entertaining, and as much as the action scenes were exaggerated and a little foolish, I found that I was getting bored and restless if it went too long between them. That’s the only thing that has stopped me from trying to find a cheap/borrowed copy of the original to read, because although my interest has been raised – I want to know how close this version is to the original – the ‘zombie-less’ parts of the book were, at times, a bit of a chore.

The only major criticism I have of the book is that the zombies are mentioned often, but always using one of a small handful of period-consistent terms. When used once, these terms are an interesting look at how zombies may have been seen in that sort of world, but each one is repeated over and over again. One of the least appealing is the word ‘unmentionables’ – since they are called that often, and while some characters talk of nothing else, Mrs Bennett is the only person I can think of off the top of my head that might not have mentioned zombies at all. They are far from unmentionable, people talk about them all the time! And while Mrs Bennett rarely (if ever) talked about zombies, she talked about her daughters fighting abilities – which is itself a direct consequence of the zombie plague.

Zombie references also feel shoe-horned in many places – the best uses are more subtle, like the fact that mail is expected to be delayed, as coaches must be more heavily armed when crossing the countryside, and even then may be attacked and require a better provisioned coach to recover mail and deliver it. The turning of Miss Lucas was most interesting when it was at a distance – the frequency and quality of her letters dropping, Elizabeth wondering when (or if) the next one would arrive, or whether her disease has been discovered and what fate befell her.

Learning Unit Testing X – Finishing Hiding

Last time, I got the tests for Charging out of the way, and got through a raft of simple checks for Hiding. This time, a few of the more complicated checks.

First off, a model can move around while hiding as long as it remains out of sight. I’m not sure how to be checking every point along the move, but I can check at the end of the movement whether it’s still out of sight.

[TestMethod]
public void Hide_ThrowsExceptionIfInSightAfterMove()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
bool exceptionThrown = false;
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Hide();
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
Assert.IsTrue(testModel.IsHiding);
try
{
testModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
Assert.IsFalse(testModel.IsHiding);
}

The best way to check this is probably to call the Hide method at the end of MoveModel – any change in the model’s visibility will be picked up. Code re-use: excellent!

if (this.IsHiding)
{
this.Hide();
}

But I still don’t get a pass… I also need to set IsHiding to false in the Hide method, when it throws an exception. Then the test goes green.

The next test is that after an enemy model has moved, it might force a model to stop being hidden. I will keep the current action of throwing an exception – this will let the imaginary UI show that hiding has ceased.

[TestMethod]
public void Hide_StopsHidingIfInSightAfterEnemyMove()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Movement = 4;
bool exceptionThrown = false;
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Hide();
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
Assert.IsTrue(testModel.IsHiding);
try
{
enemyModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
Assert.IsFalse(testModel.IsHiding);
}

The code to pass this test should be just adding the following check to the end of MoveModel (as long as Hide is added to the IModel interface).

foreach (IModel enemyModel in (from models in _gameManager.Models
where models.Player != this.Player
select models))
{
enemyModel.Hide();
}

But this doesn’t work – not only does it not work, but it breaks other tests! Now, Charge_SetsIsChargingFlag, MoveModel_CannotMoveFurtherThanModelsMovement and NewTurn_SetsIsChargingToFalse throw exceptions and this test fails on the penultimate assert that the exception was thrown. I believe the error with this test is that the Mock GameManager I’m using is only returning the enemyModel – not the testModel. When I added the testModel to the setup, this test at least passes. The other tests all throw exceptions. This is probably due to the fact that the GameManager is not being correctly set up in each case, to return an empty List<IModel> – as a mock object, it returns null instead and the above code to check for other models fails when passed a null.

By adding in the required setup line to each of those tests, I get 31 passes again.

Finally, a model is automatically forced out of hiding if an enemy model is within it’s Initiative range of the hiding model. This one needs to be checked when the model chooses to hide, and also whenever it moves or the enemy model moves. Since all three of these cause the Hide method to be called, that should probably be where it sits. The following tests should cover off those three situations:

[TestMethod]
public void Hide_CannotHideIfEnemyInInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Location = new LocationPoint(1, 0, 0);
enemyModel.Initiative = 2;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_StopHidingIfModelMovesIntoEnemyInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Location = new LocationPoint(5, 0, 0);
enemyModel.Initiative = 3;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
testModel.IsHiding = true;
testModel.Movement = 4;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_StopHidingIfEnemyMovesWithinInitiativeRange()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
Model enemyModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0);
testModel.Location = new LocationPoint(5, 0, 0);
enemyModel.Location = new LocationPoint(0, 0, 0);
enemyModel.Initiative = 3;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel, testModel });
testModel.IsHiding = true;
enemyModel.Movement = 4;
bool correctExceptionThrown = false;
try
{
enemyModel.MoveModel(4, 0, 0);
}
catch (HidingException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}

The passing code sits in Hide, and is very pleasantly simple. Hide becomes very long:

public void Hide()
{
if (this.IsCharging || this.IsRunning)
{
HidingException ex = new HidingException("Cannot hide if charged or ran this turn.");
throw ex;
}
else
{
List<IModel> enemyModels = (from models in this._gameManager.Models
where models.Player != this.Player
&& (this._objectManager.GetLineOfSight(models, this) > 0.6 || this.GetDistanceFrom(models.Location.X, models.Location.Y, models.Location.Z) <= models.Initiative)
select models).ToList();
if (enemyModels.Count > 0)
{
this.IsHiding = false;
HidingException ex = new HidingException("Cannot hide in sight or Initiative range of enemy models.");
ex.EnemyModels = enemyModels;
throw ex;
}
else
{
this.IsHiding = true;
}
}
}

But this breaks several other tests. The reason is that some of the previously written tests are not setting locations for the enemy and test models, and the distance between them (zero) is always equal to or less than the default Initiative value (also zero). Changing the tests to give them a bit of space fixes this problem.

Since a model can remain hidden for several successive turns, it doesn’t need to reset the IsHiding flag – Hiding for all hidden models is checked whenever a model is moved, so it will be taken out of hiding when a player wishes or when it is chosen.

Next time, I move off of page 11, but I’m not sure where to yet…

Forest Dragon Crystal

I got a game of Warhammer in this weekend- the first of the year! To inspire me to paint more, I chose to forego the Dark Elves (many of which remain unpainted) in favour of the Wood Elves (only a couple of special characters unused). The army was planned on the assumption that I’d be fighting Chaos but there was a surprise twist with my opponent, who decided to bring his Bretonnians instead.

Still, after the initial panic attack, I realised that we had a lot of forests that could be put down and I’d just have to stay out of reach of the nasty nasty lances.

dryad2Terrain was set up pretty much as a straight line down the middle of the table, consisting of a tower, a wall, four forests (after the Wood Elf free forest was placed) and an interesting candle holder that was sat near the scenery shelves, shaped like a dragon holding a crystal. On the agreement that we first remove the candle, we decided that it would make a great centrepiece for the game, and the story went roughly along the lines of “Bretonnian lord wants forest dragon crystal to bling up his castle, Wood Elves don’t like people wandering around the forest”. Nothing too major.

Using the forests to funnel the lances into really obvious traps didn’t quite work – they were a bit too obvious. Slowly, over the game, I picked off all the peasants and foot troops but failed to make much of a dent on the knights – including a combined charge from Wardancers, Dryads and Glade Riders. It reinforced my belief that Wood Elves should never, ever engage to the front of a unit. And that I should probably have used the Killing Blow dance. Also, angles of possible fleeing should be considered, as my Warhawk Riders drew a combat and automatically fled – though they would have rallied automatically too, they went through a block of peasant halberdiers and were wiped out. They could have quickly reached the other side of the battle (the one with all the knights) and helped with some rear charges to destroy a knight unit or two.

That being said, not too much of the army was destroyed – Wood Elves are very, very good at staying out of the way.

At the final tally, there were only 70 victory points between us (Wood Elves very slightly ahead) for an extremely solid draw. Hopefully we’ll have a rematch at some point, since that Bretonnian lord still wants his bling, and the Elves didn’t do enough to put him off yet – all they did was clear out the riff-raff from his army!

What I Did On My Holidays

I’ve just had one of my regular el-cheapo holidays to visit family. They even bought a new bed for us to sleep on while we were there, since Fred is now in a ‘big boys’ bed.

Most of the week was spent relaxing – we drove past a beach, potty trained the little guy (mostly successful, though still in nappies when we go out or for bed) and visited many friends in the pub. I managed to get started on a new book (Pride and Prejudice and Zombies, by Jane Austen and Seth Grahame-Smith) and an old book (Monstrous Regiment, by Terry Pratchett). I barely thought about work at all.

We even squeezed in a game of Necromunda against my very first opponent and his Redemptionist gang. I took out my Delaques, and realised that the roster is over ten years old. Impressive. Jen took some Eschers. He set up a three-player scenario, where we had to get to the top of a tower before anyone else to win a prize. He and Jen got into early fighting, shooting each other off of walkways and so on. I snuck in through the other side, managing (somehow) to avoid all attacks, until my leader was caught by an executioner one-shot flamer. He caught fire, and luckily ran straight across the walkway and past two guards (one wielding a rather nasty-looking double-handed chainsaw) towards the Redemptionist base. The following turn, a Redemptionist brother reached the top of the tower, while my Delaque Juve was a level below and held up by an Escher heavy… The Redemptionists only had to wait one turn at the top to be the winners. Luckily, my leader doused the flames and ran into the Redemptionist base (undefended, they were all off picking on Eschers) and what had been a forgone conclusion shifted very suddenly – and again, as my Juve finished off the Escher. He was now at least five floors above anyone else, and only one below the top. That’s the first game of Necromunda I’ve won against that opponent – as most of his gangs have an incredibly high rating, I’m always the ‘underdog’. This scenario limited all players to four models at a time, so there was some opportunity to fight fairly there.

With the underdog bonus, and hitting the button, plus a few lucky shots on the way, that Juve managed to pick up 37 experience points (from 0!) and got instant promotion. Awesome.

Unusually for such a long stay away, I didn’t get any painting done. I almost packed some models as I left, but couldn’t get them fixed and protected for the journey in time. I decided to take it easy instead.

I did get a lead on my family tree – my aunt has done a lot of research already, with the things I had been making assumptions about previously. I think she’s gone even further back than I could, and told me that the family had originally come from France (to settle on the Isle of Wight). She’ll dig out what she can find, and I can see how it fits what I’ve discovered. Although it’s not a resolution, I’m still going to be following the family tree this year. I’ll just pick it up as and when I can.

Speaking of family trees, one of the benefits of going away was meeting the two new additions – my cousins have had babies! There are a few more expected this year, which is always fun. We’re expecting to be the last, in June. I think that the new babies are my first cousins once removed, and Freddy’s second cousins. Here’s a diagram, showing the new babies in relation to Freddy. It is restricted down to just my mum’s family, and only as far back as her parents (my grandfather, Freddy’s great-grandfather, is also the new babies great grandfather). These diagrams don’t make things in exactly the easiest format to read, but that’s something I can play around with later.

family-tree-new-babies

Learning Unit Testing IX – Moving On With Movement

Having gotten those knotty problems with world management, distances, directions, etc all out of the way I can finally move off of page 10. So what’s next? Page 11! Hooray!

It begins with a description of a charge move. A charge works like a run, at double-move rate, with the model (hopefully) ending up in contact with an enemy, or with a low wall that is also in contact with the enemy. The movement side of things should be fairly easy, but describing ‘base contact’ might be slightly more difficult.

In the real game, a model’s base is usually a circle 25mm in diameter. This is close enough to one inch to be treated as one of the arbitrary units I’m using for movement and measurement, so a model can be described as having a width of 1. If I choose the location to describe the centre-point of a model’s base, then ‘base contact’ would be a point equal to half the charger’s width plus half the target’s width, to allow for future models that may be bigger or smaller than a normal one (I’m fondly thinking of Ogryns!)

I started skirting around the issue slightly in the last post, but I need to seriously consider scenery and models as things with width and height, more than points on a virtual graph. The scenery will also need a different method of determining base contact, since it won’t often have a circular base.

It’s taking me a while to work out exactly which direction (no pun intended) to go with this. A charge sounds exactly like a regular run move, except you can (and are expected to!) get within 8” of an enemy model without stopping, and it declares that the model “Can do nothing for the rest of the turn.” To that end, I believe that only three new tests are needed, on a ‘charge’ method – one that makes sure a charging model can approach within 8” of an enemy, one that checks that an ‘isCharging’ flag is set so that the model can’t take any more actions this turn, and one that checks that that flag is removed at the beginning of a turn.

The first test – that the model doesn’t stop moving close to an enemy – is almost identical to the one that checks that it does stop moving close to an enemy, but with a different expected final position and no exception thrown.

[TestMethod]
public void Charge_CanGetWithin8InchesOfEnemy()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
mockObjectManager.Setup(item => item.GetPointOfIntersection(testModel.Location, It.IsAny<LocationPoint>(), enemyModel.Location, 8)).Returns(new LocationPoint(1, 0, 0));
mockObjectManager.Setup(item => item.GetLineOfSight(testModel, enemyModel)).Returns(1);
testModel.Charge(8, 0, 0);
}
catch (MovementException ex)
{
exceptionThrown = true;
}
Assert.IsFalse(exceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}

The code to pass this test is extremely simple:

private bool _isCharging = false;
public void Charge(float positionX, float positionY, float positionZ)
{
_isCharging = true;
MoveModel(positionX, positionY, positionZ);
}

And a quick change to the ValidateMove method to check if the model is charging before validating the ‘within 8” of an enemy’ rule:

if (this.TotalDistanceMoved + distanceToPoint > this.Movement && _isCharging == false)

I almost feel silly for thinking it would be any harder than that, but then I was originally worrying about the base sizes, low wall restriction, etc, that is all part of ‘being in base contact’ – as far as Movement is concerned, it doesn’t matter if the models are in base contact after a charge, only that a charge was attempted. The next test, then, checks that the flag is set:

[TestMethod]
public void Charge_SetsIsChargingFlag()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
testModel.Charge(8, 0, 0);
Assert.IsTrue(testModel.IsCharging);
}

The code only needed to change the private _isCharging to a public IsCharging property, and again – straight into the pass. To make sure the NewTurn method resets the charging flag:

[TestMethod]
public void NewTurn_SetsIsChargingToFalse()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Charge(8, 0, 0);
Assert.IsTrue(testModel.IsCharging);
testModel.NewTurn();
Assert.IsFalse(testModel.IsCharging);
}

Code to pass that test is just insultingly simple. At this time, I realised that the IsRunning flag might not have been set back to false at the beginning of a new turn – there’s no test for it, so I’ll add that in now.

[TestMethod]
public void NewTurn_SetsIsRunningToFalse()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.MoveModel(8, 0, 0);
Assert.IsTrue(testModel.IsRunning);
testModel.NewTurn();
Assert.IsFalse(testModel.IsRunning);
}

And as I predicted – it fails! The passing code should, again, be fairly easy to figure out. So I now have all the basics of charging, without the ‘is in base contact’ checks which will mostly be mathematical functions, and abstracted out without really implementing them (as I decided earlier).

The next challenge is Hiding, then we can move away from page 11 – much faster than getting away from page 10 was, at any rate! As I see it, the following things are necessary to check for hiding:

  • A model can choose to hide if it ends it’s turn in ‘reasonable’ cover
  • A model can move about and stay hidden, as long as it doesn’t leave the ‘reasonable’ cover.
  • A model cannot run or charge and hide in the same turn.
  • If an enemy model moves to a position it can see the hiding model, it ceases to be hidden.
  • A model ceases to be hidden if an enemy is within it’s Initiative value in inches of the model.

I will define ‘reasonable’ cover as being in at least 40% cover – this value could easily be tweaked later. I had decided while brainstorming before that line-of-sight shouldn’t return a boolean value, rather a percentage of the target that is visible. In systems that can determine only ‘visible’ and ‘not visible’, the IObjectManager would obviously return 0 and 1 and nothing in between. More subtle systems would give a range of values, meaning that cover saves (when I get to shooting) will take account of partial cover, heavy cover, etc. The first test then will check line of sight from every enemy, to make sure that it is not more than 60% visible to any of them.

[TestMethod]
public void Hide_SetsFlagIfInReasonableCover()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(0.5f);
testModel.Hide();
}
catch (HidingException ex)
{
exceptionThrown = true;
}
Assert.IsFalse(exceptionThrown);
Assert.IsTrue(testModel.IsHiding); }

Code to pass this test:

public void Hide()
{
List<IModel> enemyModels = (from models in this._gameManager.Models
where models.Player != this.Player
&& this._objectManager.GetLineOfSight(models, this) > 0.6
select models).ToList();
if (enemyModels.Count > 0)
{
HidingException ex = new HidingException();
ex.EnemyModels = enemyModels;
throw ex;
}
else
{
this.IsHiding = true;
}
}

Using some lovely LINQy goodness! The next test:

[TestMethod]
public void Hide_ThrowsExceptionIfInSight()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
bool exceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetLineOfSight(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(1);
testModel.Hide();
}
catch (HidingException ex)
{
exceptionThrown = true;
Assert.AreEqual(enemyModel, ex.EnemyModels[0]);
}
Assert.IsTrue(exceptionThrown);
}

Needs no modification. Maybe I went a bit too far with the code writing, since I knew what the test would be in advance? I played with the figures to make sure that the test fails when it should.

The following tests should prevent the Hiding flag staying set when running or charging:

[TestMethod]
public void Hide_RemoveHidingFlagWhenRunning()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsHiding = true;
testModel.Movement = 4;
testModel.MoveModel(6, 0, 0);
Assert.IsFalse(testModel.IsHiding);
}
[TestMethod]
public void Hide_RemoveHidingFlagWhenCharging()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsHiding = true;
testModel.Movement = 4;
testModel.Charge(6, 0, 0);
Assert.IsFalse(testModel.IsHiding);
}

The code for both these tests is simple – change MoveModel and Charge to look like:

public void MoveModel(float positionX, float positionY, float positionZ)
{
try
{
ValidateMove(ref positionX, ref positionY, ref positionZ);
}
catch (Exception ex)
{
throw;
}
finally
{
this.TotalDistanceMoved += GetDistanceFrom(positionX, positionY, positionZ);
this.Location.X = positionX;
this.Location.Y = positionY;
this.Location.Z = positionZ;
if (this.TotalDistanceMoved > this.Movement)
{
this.IsHiding = false;
this.IsRunning = true;
}
}
}
public void Charge(float positionX, float positionY, float positionZ)
{
IsHiding = false;
IsCharging = true;
MoveModel(positionX, positionY, positionZ);
}

The next two tests check that a model can’t hide if it charged or ran this turn:

[TestMethod]
public void Hide_CannotHideIfRanInSameTurn()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsRunning = true;
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void Hide_CannotHideIfChargedInSameTurn()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.IsCharging = true;
bool correctExceptionThrown = false;
try
{
testModel.Hide();
}
catch (HidingException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(testModel.IsHiding);
Assert.IsTrue(correctExceptionThrown);
}

I’m really liking how simple these tests are to pass at the moment. The code to solve both of those tests goes at the top of the Hide method, and is just a quick check:

if (this.IsCharging || this.IsRunning)
{
HidingException ex = new HidingException("Cannot hide if charged or ran this turn.");
throw ex;
}

This is getting a bit too long (I’m thinking that 2000 words, including code, should be a maximum limit on these). I’ll continue more Hiding tests next time!

Resolutions for 2011

Wow, 2011. When did that happen? Probably sometime around the end of December, it’s usually that time of year.

With Christmas all wrapped up (ahaha), I can turn to the new year, and think about my resolutions. I was pleased with the progress last year even though I did slow down a bit in the summer. The clear lesson was to have a plan – a definite method of attack, and some measure of progress.

I’m picking some of the “traditional” resolutions that I hear about every year – get fit, save money, etc. But I intend to keep at it for longer than a month, and with some hard work, longer than six months too! I’ve had a few weeks trying out what I think I can do, and I’m ready to announce these plans in full.

This year, I aim to improve myself a bit. I’ve kept myself healthy this year, but I could do better. My first resolution then: to go swimming every week. I’ve identified a local swimming pool, and we can take Freddy at the weekend. He likes swimming, and splashing, and will enjoy it. It will require some assistance (it’s the wife’s turn to drive at the weekends), but if I aim to go every week, even if I fail one week there should be enough to have raised my general fitness by the end of the year. I might keep a record of how many lengths I do, and see if it rises appreciably over the year.

I failed my resolution to paint all my Dark Elves last year. That was because there was no plan. The new plan is to do at least forty-five minutes of painting a week. I can probably get that in pieces on weekday evenings, or catch up at the weekend while Freddy has a nap. Why forty-five minutes? Because I can stick something on the DVD player (a Babylon 5 commentary, an iPlayer episode of something) and have the background noise I need when painting. Since this is a target like the “filing” one last year, I can do the same as I did then and catch up if I fail one week. This should (hopefully) get the Dark Elves finished, and maybe even some of the scenery.

Last year, a number of big expenses got in the way of saving – we needed to replace the cooker, buy a car and get it insured. This all added up to quite a nasty sum, and on examination, I ended with no more in savings than I started the year with. I’ve not got a specific plan in place on how to save money, other than not to spend it, but my goals are to put away an as-yet-undetermined amount each month. My ultimate aim is to have at least increased my savings slightly, and overpaid an extra month on the mortgage. I calculated the other day that at the start of this year, there’s only around 343 months left to pay on it. If I manage to knock that down slightly, then terrific!

An easy one now – I’ve realised that I very, very rarely put pictures on here. Some of them were even only Flickr/Google Image searches, and I didn’t even do that one as often as I could/should have. I can put pictures of Fred on when I talk about him, or of models when I talk about them (the only one I have actually done!).

Finally, a triple-whammy resolution – do more of the Frugal Gaming thing. Play more, spend less, and blog about games. I will try to play a major game once a month, unless I hold a games night – of which I will attempt to organise more. I only managed a couple last year, which just wasn’t as many as I wanted. I’ll also be imposing a £5 monthly limit on games – computer games, wargames, etc. It should be reasonably easy to keep this one in control, there’s only a few things I’m interested in and I recently joined an RPG group which aims to meet weekly – and RPGs are notoriously cheap! As the final part of this one, I’ll be aiming to blog on A Year of Frugal Gaming at least once a month too. I feel I let them down a bit last year, so I’ll be trying harder to waste people’s blog-reading time with games reviews, games night tips, and any frugal gaming tips I can find.

In summary then:

  1. Go swimming once a week
  2. Paint for forty-five minutes a week
  3. Save money, overpay at least a month on the mortgage
  4. More pictures on this blog!
  5. Spend no more than £5 a month on games
  6. More games and games nights.
  7. Blog on A Year of Frugal Gaming once a month

This seems to me to be a good range of things, easy goals and milestones along the way to hit, and I should be able to get a feel for whether or not I’m getting anywhere with them.

Learning Unit Testing VIII – Emergent Design

I’ve been bracing myself for this moment since I started the project – I’m coming to believe that I’ve been heading in a slightly wrong direction.

Part of TDD is the idea of ‘emergent design’, and letting the correct design emerge from the process of writing minimal code to pass tests. At the same time, it’s necessary to keep an eye on the bigger picture so you know where exactly the code should be written.

I’ve been making the MoveModel method into a huge monster, that checks all sorts of things, and as I started investigating how to implement line of sight, I realised that this functionality should probably be moved out into some sort of utility class. MoveModel itself is now checking distances between two points (this will be duplicated later), proximity detection (probably to be used later), and as I said – was about to take on line of sight. All these details could be worked out mathematically as I was doing them, but some frameworks (such as XNA) might provide better ways to calculate them, with things such as Rays, or… something else XNAish.

The best way to handle that would be to refactor all the ‘utility’ calculations into a separate class, exposed via an interface so that it can be swapped out. That way, I can abstract out and mock all the calculations in MoveModel to deal more with the situation parameters and appropriate responses and less about the calculations themselves. At the same time, I can write tests for this new utility class so that I can test the purely mathematical aspects of the same calculations. The interactions become easier (true, false, and integer responses rather than the broad spectrum of mathematical output) since I don’t have to test multiple configurations and situation-specific responses, just the two separate things that should be behaving.

The other benefit will be that if I eventually do take this library over to an XNA frontend, I can swap out that mathematical calculator for something more efficient for the framework to use. But the basic mathematical way will still be available if I choose instead to port it to Silverlight.

I also took this opportunity to move the X, Y and Z co-ordinates into a separate class – LocationPoint.

Here’s the set of tests for MoveModel:

[TestClass]
public class ModelTests
{
[TestMethod]
public void NewTurn_SetsDistanceMovedToZero()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.TotalDistanceMoved = 4;
testModel.NewTurn();
Assert.AreEqual(0, testModel.TotalDistanceMoved);
}
[TestMethod]
public void MoveModel_PositionHasChanged()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 2;
float newY = 2;
float newZ = 2;
testModel.MoveModel(newX, newY, newZ);
Assert.AreEqual(2, testModel.Location.X);
Assert.AreEqual(2, testModel.Location.Y);
Assert.AreEqual(2, testModel.Location.Z);
Assert.IsFalse(testModel.IsRunning);
}
[TestMethod]
public void MoveModel_TotalMovementInASingleTurnCannotExceedModelMovement_ThrowsMovementException()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
try
{
testModel.MoveModel(0, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_MakeTwoSmallMovementsWithoutGoingOverMovementRate()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 1;
float newY = 1;
float newZ = 0;
try
{
testModel.MoveModel(newX, newY, newZ);
testModel.MoveModel(0, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_CannotMoveFurtherThanModelsMovement()
{
bool correctExceptionThrown = false;
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
float newX = 5;
float newY = 6;
float newZ = 3;
try
{
testModel.MoveModel(newX, newY, newZ);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsTrue(correctExceptionThrown);
}
[TestMethod]
public void MoveModel_MovesDistanceOverMovementRateAndSetsIsRunningFlag()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>());
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
float newX = 5;
float newY = 4;
float newZ = 3;
testModel.MoveModel(newX, newY, newZ);
Assert.IsTrue(testModel.IsRunning);
}
[TestMethod]
public void MoveModel_StopsRunningWithin8InchesOfEnemyModel()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
mockObjectManager.Setup(item => item.GetDistanceBetween(testModel.Location, It.IsAny<float>(), It.IsAny<float>(), It.IsAny<float>())).Returns(8);
mockObjectManager.Setup(item => item.GetPointOfIntersection(testModel.Location, It.IsAny<LocationPoint>(), enemyModel.Location, 8)).Returns(new LocationPoint(1, 0, 0));
mockObjectManager.Setup(item => item.GetLineOfSight(testModel, enemyModel)).Returns(1);
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
Assert.AreEqual(1, ex.FinalPosition.X);
Assert.AreEqual(0, ex.FinalPosition.Y);
Assert.AreEqual(0, ex.FinalPosition.Z);
}
Assert.IsTrue(correctExceptionThrown);
Assert.AreEqual(1, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithEnemyMoreThan8InchesAway()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 18;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesMovingWithin8InchesOfEnemyModelNotRunning()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 9;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(3, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(3, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithin8InchesOfFriendlyModel()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model friendlyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
friendlyModel.Location.X = 9;
friendlyModel.Location.Y = 0;
friendlyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { friendlyModel });
Model testModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
[TestMethod]
public void MoveModel_ContinuesRunningWithin8InchesOfEnemyModelIfOutOfSight()
{
Mock<IGameManager> mockGameManager = new Mock<IGameManager>();
Mock<IObjectManager> mockObjectManager = new Mock<IObjectManager>();
Model enemyModel = new Model(1, mockGameManager.Object, mockObjectManager.Object);
enemyModel.Location.X = 12;
enemyModel.Location.Y = 0;
enemyModel.Location.Z = 0;
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
Mock<IScenery> mockScenery = new Mock<IScenery>();
mockScenery.Setup(item => item.IsBlocking(It.IsAny<IModel>(), It.IsAny<IModel>())).Returns(true);
mockGameManager.Setup(item => item.Models).Returns(new List<IModel>() { enemyModel });
mockGameManager.Setup(item => item.SceneryObjects).Returns(new List<IScenery>() { mockScenery.Object });
Model testModel = new Model(2, mockGameManager.Object, mockObjectManager.Object);
testModel.Movement = 4;
testModel.Location.X = 0;
testModel.Location.Y = 0;
testModel.Location.Z = 0;
bool correctExceptionThrown = false;
try
{
testModel.MoveModel(8, 0, 0);
}
catch (MovementException ex)
{
correctExceptionThrown = true;
}
Assert.IsFalse(correctExceptionThrown);
Assert.AreEqual(8, testModel.Location.X);
Assert.AreEqual(0, testModel.Location.Y);
Assert.AreEqual(0, testModel.Location.Z);
}
}

And the code needed in MoveModel itself:

public void MoveModel(float positionX, float positionY, float positionZ)
{
try
{
ValidateMove(ref positionX, ref positionY, ref positionZ);
}
catch (Exception ex)
{
throw;
}
finally
{
this.TotalDistanceMoved += GetDistanceFrom(positionX, positionY, positionZ);
this.Location.X = positionX;
this.Location.Y = positionY;
this.Location.Z = positionZ;
if (this.TotalDistanceMoved > this.Movement)
{
this.IsRunning = true;
}
}
}
private bool ValidateMove(ref float positionX, ref float positionY, ref float positionZ)
{
double distanceToPoint = GetDistanceFrom(positionX, positionY, positionZ);
if (distanceToPoint + this.TotalDistanceMoved > this.Movement * 2)
{
MovementException ex = new MovementException("The model cannot move further than it's Movement rate.");
ex.FinalPosition.X = this.Location.X;
ex.FinalPosition.Y = this.Location.Y;
ex.FinalPosition.Z = this.Location.Z;
throw ex;
}
if (this.TotalDistanceMoved + distanceToPoint > this.Movement)
{
foreach (IModel enemyModel in _gameManager.Models.Where(item => item.Player != this.Player))
{
LocationPoint intersectionPoint = _objectManager.GetPointOfIntersection(this.Location, new LocationPoint(positionX, positionY, positionZ), enemyModel.Location, 8);
if (intersectionPoint != null)
{
if (_objectManager.GetLineOfSight(this, enemyModel) > 0)
{
MovementException ex = new MovementException("The model cannot run within 8\" of an enemy model.");
ex.FinalPosition = intersectionPoint;
positionX = intersectionPoint.X;
positionY = intersectionPoint.Y;
positionZ = intersectionPoint.Z;
throw ex;
}
}
}
}
return true;
}

The lesson I’ve learned from this as far as emergent design goes is that I should be more willing to abstract something out if it doesn’t look like it belongs, and be prepared to program against interfaces that are not implemented yet. I believe that’s the way TDD works, and will keep code exactly where it needs to be and not spread around (as it was starting to do in the Model class…)