We’re Ready to Rock…
… but there are some changes to Rock, Paper, Azure we need to discuss based on our test week. First things first: I highly recommend you download the latest Bot Lab and MyBot project here.
For the most part, old bots bots will continue to work, but since this was a test round anyway, I highly recommend you upgrade – there are a few edge cases that might break bots, or cases where a bot doesn’t do what you think it would. Let’s discuss all of these changes we’ve made. I’ll save the best for last.
CanBeat and LosesTo – Don’t Use
We re-scoped the CanBeat and LosesTo methods from the Move class to internal (from public). Most people weren’t using them, and they weren’t really intended for outside consumption and we received a couple of questions on behavior. The reason for the change is this – and some of this is historical: the way the engine works is that it goes through a series of steps to determine a winner. It will first look if a move can beat another move:
1: internal bool CanBeat(Move move)
2: {
3: if (!ValidMoves.Contains(GetType().Name))
4: return false;
5:
6: if (!ValidMoves.Contains(move.GetType().Name))
7: return true;
8:
9: return CanBeatLegalMove(move);
10: }
So the RockMove implementation returns true if the move is scissors which is implemented in the RockMove class. The original game had moves in different assemblies for multiple rounds, so the win determination path had to waterfall through, and examine rules to the game – such as whether or not you have any dynamite remaining. The short answer here is there are cases where this will return unexpected results, so it’s best to just not expose them. Performance wise, it’s better to have your own implementation, anyway. If your bot is currently using this, sorry to say this is a breaking change.
Game Summary
At the top of the log file, you’ll now see a game summary that is helpful for info-at-a-glance. It looks like this:
Game Summary bhitney JohnSmith
Points 953 (L) 1000 (W)
Dynamite Used 45 100
Time Deciding (s) 0.04885 0.06507
Time deciding shows how much time your bot has used for the entire round. This is interesting to see how your bot compares to others, but, it’s also useful for timeouts which is below.
Timeout
The server has some strict timeouts – we’re always tweaking the exact logic and we’re hesitant to give too much information because, in a multithreaded environment, the time slice each bot has isn’t exclusive. But, your bot has a maximum of 1 second (subject to change) per match. Typically that is no problem, as you can see in the game summary. Once your bot crosses the 1 second timeout, your bot will stop making moves (essentially forfeiting the rest of the moves).
Server Messaging
In the log file, you’ll now see more clear messaging if something happened – for example, if a player threw dynamite but was out of dynamite, the log will indicate this next to the score.
ExceptionMove
We standardized the error moves to “ExceptionMove.” If a player times-out or throws an exception, their last move will be an ExceptionMove. This is visible in the log, and detectable like so:
if (opponent.LastMove is ExceptionMove)
{
//player threw an exception or timeout
}
This is a good time to mention that the opponent’s LastMove is null on the first move.
Fresh Upgrade
One of Azure’s strengths is flexibility in deployment – when deploying, you have an option for an in-place upgrade, or can deploy to staging and do a VIP (virtual IP) swap that allows you to seamlessly move a new deployment into production.
Because of the significant changes to our Bot Lab and new features, we recommend deleting the old deployment first, and then deploying the new package and not doing an in-place upgrade.
Player Log
And now the best part! There’s a private player log you can write to. This information will be appended to the bottom of the game log – but it’s only visible to you. We’re still testing this feature, but it should be helpful in isolating issues with your bot. To write to your log, you can do something like:
1: if (!you.HasDynamite)
2: {
3: you.Log.AppendLine("I'm out of dynamite!");
4:
5: //opponent's log is always null!
6: if (opponent.Log == null) { }
7: }
Note: Your opponent’s log is always null, so don’t try it! Also, logs are limited to a total of 300k – this should be more than enough, but once the log passes this mark, the engine won’t write to the log (but no exception is raised).