Rock,Paper,Azure

I started playing Rock,Paper,Azure today – a great code contest sponsored by Microsoft.  I ran into some trouble with their out-of-the-box bits (more on that later) but I had some fun once I got a successful deployment going.

First, the problems.  I could not get the local emulator working.  Rather, I can get the Oct 2012 Azure Toolkit emulator running on my local Win7 machine,. but the RPA emulator solution does not work.  I got this weird exception:

image

That no one at Microsoft can figure out.  After about 3-4 hours of changes, I gave up and decided to just use the Azure site to test my Bots (is the plural of Bot “Botts” or “Bots”?).

Second, the logistics.  It was pretty painless setting up an Azure account for this context.  All I had to do was to follow the instructions on their website and I got almost all of the way there.  The one omission from their directions is that once you have your cloud service running,

image

you need to upload the BotLab so you can test your bots before entering them into the contest.  There are not any instructions on the RPA site.  What you need to do is onmce your provision your site, you click on its name to navigate to the upload page:

image

You then need to click on the Upload A New Production Deployment.  You then click on “From Local” for the package and configuration files that you created when you followed this RPA step.

image

Once the files are loaded, Azure spins for a couple of minutes and then you get your lab that you can navigate to and upload your bots.

image

I then loaded up a “Brick Only” Bot to my BotLab:

image

and then pushed it to the actual contest site:

image

Third, the code.

So now that I can upload to my lab and push to the contest, I thought about how to make a better Bot.  Instead of diving right into the code, I set up a new solution with a single project that had a single class.  I added the necessary references and coded up a Rock-only Bot with an associated unit test:

image

With the unit test like this:

[TestMethod()]
public void MakeMoveTest()
{
    RockOnlyBot target = new RockOnlyBot(); 
    IPlayer you = null; 
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.Rock;
    Move actual = target.MakeMove(you, opponent, rules);

    Assert.AreEqual(expected, actual);
}

And the class implementation like this:

public Move MakeMove(IPlayer you, IPlayer opponent, GameRules rules)
{
    return Moves.Rock;
}

Before writing my killer Bot, I then put several new classes that correspond to the examples included in the RPA bits into the project with associated unit tests.

image

An interesting thing is that for random moves, my unit test just checks to see if the move is not null (for now)

[TestMethod()]
public void MakeMove_ReturnsInstiantiatedObject_Test()
{
    RandomBot target = new RandomBot(); 
    IPlayer you = null; 
    IPlayer opponent = null; 
    GameRules rules = null;
    Move actual;
    actual = target.MakeMove(you, opponent, rules);
    Assert.IsNotNull(actual);
}

Another interesting thing is that the API that comes with the download does not include any implementations of the interfaces.  So for the BigBangBotTests, I need a instantiation of IPlayer you so I can keep track of you.NumberOfDecisions.  I thought, what a great place to use a Mocking Framework.  Since I am using VS2010, I decided to use MOQ to stub the IPlayer.

[TestMethod()]
public void MakeMove_ThrowsDynamiteOnFirstMove_Test()
{
    BigBangBot target = new BigBangBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.NumberOfDecisions).Returns(0);
    IPlayer opponent = null; 
    GameRules rules = null;
    Move expected = Moves.Dynamite;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);
    
    Assert.AreEqual(expected, actual);
}

 

So to be safe, I should implement a test for moves 1-5 to make sure that dynamite only comes back.  But I am not safe.  What about moves 6+? For a mocking framework, I need to implement the Random method or just increment the mocked property.  The later seems easier, so that is where I started.  I first injected the Stub only returning NumberOfDecisions = 1 and I got red:

image

I then removed all of the individual runs and put the setup in the for..each loop:

[TestMethod()]
public void MakeMove_DoesNotOnlyThrowDynamiteAfterFifthMove_Test()
{
    BigBangBot target = new BigBangBot();
    var mockYou = new Mock<IPlayer>();
    IPlayer opponent = null;
    GameRules rules = null;

    int numberOfDynamites = 0;
    for (int i = 0; i < 95; i++)
    {
        mockYou.Setup(y => y.NumberOfDecisions).Returns(i);
        Move currentMove = target.MakeMove(mockYou.Object, opponent, rules);
        if (currentMove == Moves.Dynamite)
        {
            numberOfDynamites++;
        }
    }

    Int32 notExpected = 95;
    Int32 actual = numberOfDynamites;
    Assert.AreNotEqual(notExpected, actual);
}

And the test ran green.  As a side not, this test really rests the Random function.  After all, if it turns red, then the random function has returned 95 consecutive dynamites.

I then implemented unit tests for CycleBot like so (only the 1st test is shown):

[TestMethod()]
public void MakeMove_LastMoveRock_ReturnPaper_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.LastMove).Returns(Moves.Rock);
    IPlayer opponent = null; 
    GameRules rules = null;

    Move expected = Moves.Paper; 
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);
    
    Assert.AreEqual(expected, actual);
}

Note that there is a condition in the implemntation if the last moves is Sissors – if the player still has dynamite.  I created tests for both conditions:

[TestMethod()]
public void MakeMove_LastMoveSissors_HasDynamite_ReturnDynamite_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.HasDynamite).Returns(true);
    mockYou.Setup(y => y.LastMove).Returns(Moves.Scissors);
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.Dynamite;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);

    Assert.AreEqual(expected, actual);
}

[TestMethod()]
public void MakeMove_LastMoveSissors_DoesNotHaveDynamite_ReturnWaterBaloon_Test()
{
    CycleBot target = new CycleBot();
    var mockYou = new Mock<IPlayer>();
    mockYou.Setup(y => y.HasDynamite).Returns(false);
    mockYou.Setup(y => y.LastMove).Returns(Moves.Scissors);
    IPlayer opponent = null;
    GameRules rules = null;

    Move expected = Moves.WaterBalloon;
    Move actual = target.MakeMove(mockYou.Object, opponent, rules);

    Assert.AreEqual(expected, actual);
}

And the battery of tests run green:

image

With the battery of tests done, I then wanted to deploy to Azure.  To that, I needed to add a BotFactory to my project and have it return the class that I am interested in competing:

public class BotFactory : IBotFactory
{
    public IBot CreateBot() { return new MyBot(); }
}

I then loaded the Bot to Azure and sure enough, I got it to compete:

image

With this framework in place, I am ready to start coding my killer bot!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: