RPA Grand Tournament Complete!

We had a GREAT time running the RockPaperAzure Grand Tournament Wednesday.  We had a total of 302 players from around the world, and the top players in the finals were: We saw some amazing strategies, and learned a lot along the way.  We intend to keep the site running with more contests along the way – if you have any interest in running a competition for a user group, conference, or other activity, we’d be happy to create a round for you on the site.  Contact us for info. Server Load Nothing exposes bugs faster than a system under load!  And load it had.  Here’s an example of the load on the game engine in terms of the number of bots submitted during the competition: Now, that’s just a linear look at submissions.  With over 3000 bots flooding in (mostly during the afternoon), we kept our game engine farm quite busy.   As you may have seen in our webcasts, as the number of players increases, the number of player matches goes up significantly: The above graph illustrates the number of matches to players – and this only goes up to 50 players.  Expand this to 300 players, and the load is tremendous.  (That’s one of the excellent points about Azure – we’re able to hit a button and handle the load.) We’re going to continue some experimental open rounds so stay tuned!

Top Reasons for Bot Rejection

Just a quick tip for those in the Grand Tournament.  There are 2 very common reasons we’re seeing bots get rejected – we’ll call it the red text of death that appears when you submit a bot, but it fails code analysis.  If all you see is “Bot Successfully Uploaded,” then move along, nothing to see here. The most common are coders adding debugging statements into their code.  We do block the Diagnostics namespace (among a few others), so it’s quite likely any debugging code will trigger a failure.   If you’re deep into a bot with a lot of debug code, I recommend an #ifdef around these sections to remove them from release builds. The second most common reason are locks.  Locks, as you likely know, are syntactical sugar around a Monitor, which resides in the System.Threading namespace.  We don’t allow that, either.   But many may ask, “Why no locks?  Is it not a good practice to do this around a critical section of code?”   Not in this case.  Your bot shouldn’t be using statics since we can’t guarantee when or how many instances of your bots will be loaded at any given time, and I can guarantee this will burn you.   Your bot also can’t create threads, so locking is irrelevant in this case and would only slow things down. In many cases, these errors are triggered in bots where folks are rolling their own random number generator.  While you don’t have to use it, we highly recommend you use the Moves.GetRandomNumber() method.  It works the same way, but we guarantee unique generation for bots and we do the locking in the engine to ensure this.  There’s a fun story behind that one. Good luck!

Top Failed Bots

During a presentation the other day to the Charlotte ALT.NET group,  I made a joke that Rock, Paper, Azure is doing something completely ridiculous: we invite people to write code and we’ll run it arbitrarily.  (Well, not really arbitrarily, but it does present a unique security challenge.) We’ve naturally had a few interesting submissions, so I’m posting some of them here for interest sake. First up: Thread.Sleep(...);   We see this one fairly often.  In a game where you have very limited time, I’m puzzled why some people would intentionally sleep their bots.   Next – this one is fairly innocent: 1: if (dataset.Tables.Contains(opponent.TeamName)) 2: { 3: DataTable table = dataset.Tables[opponent.TeamName]; 4: table.Rows.Clear(); 5: foreach (Round round in rounds) 6: { 7: ... … but in a short run game like this, I’d steer away from datasets.  (Plus, we have LINQ!)  This one gets caught in the filter not because it poses a specific threat, but we don’t allow anything from System.Data. Third: 1: try 2: { 3: StreamWriter writer = new StreamWriter(@"C:\RPSLog.txt", append); 4: writer.Write(builder); 5: writer.Close(); 6: } 7: catch (Exception) 8: { 9: } WOW a lot of people are trying to write text files.  Not allowed. And now for my all time favorite … an obvious hack attempt: 1: StringBuilder builder = new StringBuilder(); 2: using (SqlConnection connection = new SqlConnection(ConfigurationManager. 3: ConnectionStrings[0].ConnectionString)) 4: { 5: using (SqlCommand command = new SqlCommand("SELECT * FROM sys.Tables", connection)) 6: { 7: SqlDataReader reader = command.ExecuteReader(); 8: while (reader.Read()) 9: { 10: builder.Append(reader["[name]"]); 11: builder.Append(","); 12: } 13: } 14: } 15: you.Log.AppendLine("Here: " + builder); This last one actually raises a legitimate issue and security threat – so much so that we can ban players (or worse) for this kind of thing.  Still, though, not much of a threat:  the code can’t get through, but even if it could, connection strings aren’t available to the app domain running the round, and even so, the engine only has execute permissions on the procedures necessary to insert the results. I’m curious to see what else comes through!

RPA: Burned by Static Cling

In a previous post about locking in Rock, Paper, Azure, I said this somewhat offhand: In this case, there’s no reason to use such code in a bot. The only time you’d need to is if your bot has a static method/object reference, but that’s a bad idea in a bot because it will lead to unpredictable results. Your bot should have only instance members. I should’ve called that out more, and in this case, we have a player who lost because of it. It’s especially tough because things seemingly worked fine, until the final tournament round. Here’s why, and here’s some information on static variables (shared in VB) for those who haven’t used them before. In short, a static modifier on a method or variable makes the member part of the type instead of the class. This is really useful on helper methods in particular, because a static member can be used without instantiating the type to which the member belongs. Static objects (variables) – in any code – should be a red flag. They have very specific advantages and lower overhead (only 1 is created no matter how many objects of that type are created) – BUT, they can burn you easily if you’re not certain how the object is loaded and used. (Static methods, as a general rule, tend to have less risk than static objects/variables.) Unfortunately, that’s what happened in last Friday’s competition to one of our players. So how can they burn you? For one, they’re not thread safe. Of course, they _could_ be thread safe, but you’d have to be cognizant of what they are doing to make them thread safe. (Non-statics might not be thread safe either, however, using statics implies global reuse so it heightens the exposure of thread safety issues and can be hard to track down.) One example: we modified the original engine to do multithreading and the original log had a static method that used a StringBuilder to build a log file. This caused problems because the StringBuilder is not thread safe – so we had to add locking. The problem was always there (even if it wasn’t static), but the problem never manifested because the core was single threaded. Another way they can burn you is that two or more objects may be accessing the objects in an nondeterministic way, leading to unpredictable results. The unfortunate part about this in particular was that the issue didn’t manifest until the main tournament round – so everything appeared fine until the final round. The game engine runs two types of rounds: player rounds, and full rounds. In either case, the engine will spin up many threads to execute the games – but during a player round, the engine loops the new bot against everyone else. As other players submit their bots, the engine will load your bot only once. Because your bot is loaded only once, there’s really no chance of static variables causing a problem, much like the StringBuilder example above. But during the tournament round, all of a sudden many more games are played. Consider that with 50 players, only 49 games are played when a new bot is uploaded. But in a full round, 1,225 games are played! There is a much stronger chance your bot will have multiple instances loaded concurrently, and modifying static variables will cause the bots to go haywire. So, the lesson of the week is: don’t use statics in a bot! Question or comment about a bot? Let us know…

RPA Game History Available

You spoke, we listened.   Rock, Paper, Azure is going well, but one thing we’ve heard from many people is that they would like a history of their games.   The main reason for this is the “attack and retreat” approach  some people have taken – that is, they submit a bot with their main game playing skill, quickly observe/download the results, then resubmit a weak bot.   Because the MyBot page shows only the current results, odds are the other players won’t see the interim results.   We originally thought the current results would be all people would want to see, as game history (aside from taking a lot of space) could potentially be a lot of data to go through.  But, we’ve been proven wrong, so we decided to keep the history for players to go through.  We wanted to incorporate this in a non-breaking way, so it’s optional data to look at. On the MyBot page, you’ll still see the current games: Under that, you’ll see game history that shows all interim games: The filter allows you to select a single player to look at.  The number of games you see depends on the number of times your or your opponent’s bot was uploaded.  We haven’t quite decided how long we’ll keep history, but at the very least, it’s there to use!  Thanks for the feedback!

RPA Winners, Losers, and Eligibility

Over the past few weeks, we (the dev team of Rock, Paper, Azure) have gotten to be best friends with our internal legal department.  It’s been an educational experience, and this is where things stand with Rock, Paper, Azure. When one player wins a round, he or she is ineligible to win a future round.  If you don’t win, you are eligible to keep playing in subsequent weeks to try to win.  We’ve received a number of very good questions and concerns, so, I’ll try to summarize them here. 1. What if I win second or third place, and I want to keep playing to try to in the first place prize?  Can I do that? Players do have the option to refuse their prize.  If you come in second or third, you may reject it, forfeit your place, and continue playing.   Please note though that you assume the risk for doing this and the decision is final.  As weeks go by, I would expect the competition to get more difficult, so you may do worse and not win any prize at all, and also give up your place should there be a change in eligibility (see next paragraph). In addition to a player purposefully choosing to remove him or herself from claiming the prize, a player may also be found ineligible.   In either case, the prize goes to the next person in line.  So, hypothetically speaking, if the first place player was found ineligible, the second/third/fourth players become first/second/third.  Had player 2 already decided to refuse his place … yep, that’s right – the top three are now third/fourth/fifth from the leaderboard. It’s a bit confusing, but as you can imagine there are legalities involved here. 2. Why are previous winners still playing?  I thought they were ineligible!? Past winners are ineligible to win a prize again.  We’ll remove ineligible players as we can – as you might imagine, there’s a little delay because we’re sorting out the winners from week 1.   But rest assured, before we run the final round on Fridays, we vet all players and then rerun the entire round.  Remember that during the week, the “continuous integration” of your bot is primarily for fun and strategy – it’s only the final round that counts! 3. So, who won week 1? We had no idea it would be this volatile, but it turns out players 2 and 3 (Serplat and marsh) have been removed – one for his choice to keep playing, the other because of, unfortunately, eligibility.  (I wish that wasn’t the case, but laws are laws.)  That means that players 4 and 5 slide up to 2 and 3 – s7orm and AttnSystem now become 2nd and 3rd place, unless they too decide to keep playing and give up their place.  So just remember – you’re never out of it!

Can’t Lock() in RPA

For security and performance reasons, we often review what bots are doing and review any rejected bots to see how things are going.   When a bot is rejected, it is typically easy to spot the exact reason when looking at the code, but sometimes it’s not so apparent.  By far, the biggest case that I see is using the Lock keyword.  For example: 1: lock (someobject) 2: { 3: //synchronized code 4: } On the surface, it’s not apparent this would be a rules violation, and in the vast majority of cases, it is fine.  But under the covers, it calls Monitor.Enter() in the System.Threading namespace (known as compiler syntactical sugar), and we don’t allow anything in that namespace to be called.  The question we have internally is:  should we review the rule and make exceptions to specific calls? In this case, there’s no reason to use such code in a bot.  The only time you’d need to is if your bot has a static method/object reference, but that’s a bad idea in a bot because it will lead to unpredictable results.  Your bot should have only instance members.    So what’s the correct way?   Locking is a typical pattern (and a good habit) in object creation where there’s a risk of concurrency causing an issue.  Even if there is no risk, many developers are careful particularly with singletons to be sure of thread safety by using locks.  In the case of developing a bot, the best way to do this is in the bot’s constructor without any lock/monitor.   Questions or feedback?  Let us know!

Testing a RockPaperAzure Bot in a Winform

In Friday’s webcast, I showed a quick ‘n dirty utility for testing a RockPaperAzure bot outside of the game server and even the Bot Lab. When we ran some of these tournaments in person, it was very difficult to get a good feel for your bot before deploying it, and that’s why we introduced the idea of a Bot Lab. But even with the Bot Lab, if you’re working out a complex algorithm, it can be handy to have a simple test hardness. By pulling in the DLLs from the Bot Lab, it’s pretty easy to put together a little utility. To locate the DLLs, crack open the BotLabSite project and locate the ref directory, and grab the Compete.Bot, RockPaperScissorsPro, and RockPaperScissorsPro.RPA libraries: One thing to note: the RockPaperScissorsPro.RPA assembly, in the MyBot project, has an XML file that you can also include if you’d like intellisense – for example, we call out that GetRandomMove returns Rock/Paper/Scissors, not dynamite/water balloon: In our Windows Form app, we’ll create a few textboxes for the moves of each player, and the player’s log file: In our project, we’ll build a couple of bots – these can be your actual bots (because they use the same interface) or completely different – it’s up to you. MyBot will be the main bot we want to test, and Opponent will be, obviously, the opponent. In our form app, we’ll declare some of the player/game objects we need to test: 1: IRockPaperScissorsBot myBot; 2: IRockPaperScissorsBot opponentBot; 3: Player rpsPlayer1; 4: Player rpsPlayer2; 5: PlayerLog player1Log; 6: PlayerLog player2Log; 7: 8: private void Form1_Load(object sender, EventArgs e) 9: { 10: myBot = new MyBot(); 11: opponentBot = new OpponentBot(); 12: 13: rpsPlayer1 = new Player("you", myBot); 14: rpsPlayer2 = new Player("opponent", opponentBot); 15: 16: player1Log = new PlayerLog(rpsPlayer1, rpsPlayer1, rpsPlayer2); 17: player2Log = new PlayerLog(rpsPlayer2, rpsPlayer1, rpsPlayer2); 18: } When the form loads, we initialize our players. Each player has a bunch of methods and properties, but most importantly, also has the player’s bot. This can be a little confusing because bot is a property of the player. We’ll also create some player logs – normally the engine does this for us, but we’re running outside the engine so we need to do that ourselves. There are 2 ways we can have out bots move: Option 1: Simulate the game environment. This is a good option if you want to test timings against the game engine. I’m including this here really just for information sake – most people who want to test timings will be far better off testing in the bot lab. 1: int i = 0; 2: 3: private void button1_Click(object sender, EventArgs e) 4: { 5: i++; 6: 7: PlayerMove ourMove = rpsPlayer1.GetMoveToMake( 8: rpsPlayer2, GameRules.Default, player1Log); 9: 10: PlayerMove opponentMove = rpsPlayer2.GetMoveToMake( 11: rpsPlayer2, GameRules.Default, player1Log); By calling GetMoveToMake on the player, we’ll get back the Player’s move and this will be done just like it is in the real game – timeouts and all. Option 2: Take your time! This is really the best option – we’ll call into the bots MakeMove directly and this avoids threading/timeouts – the big advantage here is that it’s much easier to step through and debug. There is one tiny gotcha. The player log files are managed by the player, and in this case, we’re sidestepping that. In order to have a working log, we’ll need to inject that log via reflection. Reflection code won’t work on the real game server, but it comes in handy in our test app: 1: int i = 0; 2: 3: private void button1_Click(object sender, EventArgs e) 4: { 5: i++; 6: 7: Type t = typeof(Player); 8: FieldInfo fieldInfo = t.GetField( 9: "<Log>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance); 10: fieldInfo.SetValue(rpsPlayer1, player1Log); 11: fieldInfo.SetValue(rpsPlayer2, player2Log); 12: 13: Move ourMove = myBot.MakeMove(rpsPlayer1, rpsPlayer2, GameRules.Default); 14: Move opponentMove = opponentBot.MakeMove(rpsPlayer2, rpsPlayer1, GameRules.Default); What lines 7 – 11 do is use reflection to assign the player log. We need to use reflection because these are internal objects that we can’t typically access. Once we have the move, we call SetLastMove which gives bots the visibility into their last moves. 1: ... 2: rpsPlayer1.SetLastMove(new PlayerMove(rpsPlayer1, ourMove)); 3: rpsPlayer2.SetLastMove(new PlayerMove(rpsPlayer2, opponentMove)); 4: ... 5: 6: protected override void OnClosing(CancelEventArgs e) 7: { 8: rpsPlayer1.MatchOver(); 9: rpsPlayer2.MatchOver(); 10: 11: base.OnClosing(e); 12: } One other comment: in the form closing (or other location) you need to remember to close down the bots by calling MatchOver. This will make sure they shut down properly and the threads exit. With everything set up, we can run the app and see the output: So let’s return to the original question: Why do this? Suppose we want a simple way to track number and percentage of the moves thrown. We could keep simple counters (in fact, that would be the fastest way to do that), but consider this code block: 1: List<Move> opponentHistory = new List<Move>(); 2: 3: public Move MakeMove(IPlayer you, IPlayer opponent, GameRules rules) 4: { 5: gamenum++; 6: 7: if (gamenum == 1) { 8: you.Log.AppendLine("starting up."); 9: } else { 10: opponentHistory.Add(opponent.LastMove); 11: } 12: 13: if (opponentHistory.Count > 0) 14: { 15: var moveHistory = (from m in opponentHistory 16: group m by m.ToString() into g 17: select new { MoveName = g.Key, MoveCount = g.Count(), 18: Percentage = (Convert.ToDouble(g.Count()) / 19: Convert.ToDouble(opponentHistory.Count)*100) 20: } 21: ).ToList(); 22: } What we’re doing is keeping a log of the opponent’s moves into the opponentHistory list. We’ll then aggregate that into a moveHistory list, which is derived from the aggregated data. By looking at the opponentHistory, you can ask very specific questions of the data, such as move totals and percentages: 1: Rock - 3 - 27.27% 2: Paper - 6 - 54.55% 3: Scissors - 2 - 18.18% You could look at the past few moves, or the entire game – or adapt it to your project. I’ve uploaded the project, with a link below. You’ll need to pull the assemblies above into the project – I’ve left them out for licensing clarity. If you use or improve on this solution, let me know! It’s obviously not terribly advanced but should be enough to get you started. Download the solution

Rock, Paper, Azure Tournament Information

We had a couple of great questions on RPA tournaments over the first week – I thought I’d clarify a few things here. International Players As many of you know, the main tournament (with prizes) is limited the US residents. This is for legal reasons as I explained in this post. But, we wanted to get the framework in place to expand – and I’m thrilled to say that we’re there (how’s that for fast implementation?). Currently, when deploying bots, you’ll see other rounds that are open – for example, on the MyBot page: Currently, only US residents can enter the Tournament Round but everyone (including MSFT employees) can enter the Open Rounds. As other groups in varies locations put together tournaments, we are happy to support that effort. Resubmitting – not fair? One question received was from a player who thought he noticed several players resubmitting their bots rapidly without modification in order to force their bots to replay, and hopefully do better due to random elements they’ve built in their bot. Obviously, with random elements in your bot, you can win some games and lose others that will cause your bot to fluctuate position. To be clear, it doesn’t matter and this completely okay/fair to do. Here’s why: the games are played during the week in near real-time. On Friday at 2pm (for our main tournaments), we close submissions. At this time, we take a look at the players in the game for eligibility, and we start the final round at about 2:15pm. During this round at 2:15pm, all games are replayed – so the leaderboard before this is completely irrelevant – only the leaderboard created as a result of the final round is what matters. So why have the continuous integration during the week? Is it still important? You bet! It’s a chance to play and fine tune your strategy. To get ideas from other players and come up with your own. Your bot might play the same during the final, or it might not. Sandbagging Since the final leaderboard is generated as a result of the 2:15pm match, we’ve seen some interesting behavior – and this makes the game exciting! For example, suppose you’ve got a cool strategy – perhaps you wait to implement it because you don’t want your opponents to develop a counter play. This is all completely legit and part of the game. In some ways, it’s a double-edged sword – you need to test your ideas to see how good they are, but like in a poker game, you want to keep some cards close to your vest. One question we got was whether you could use time-based code in your bot. Absolutely! What I’d recommend, if coding specific for the Friday tournament, you do something like this: 1: if (DateTime.UtcNow > new DateTime(2011, 4, 15, 18, 0, 0)) 2: { 3: //begin super playing mode! 4: } In this case, we’re setting the bot to play differently after the 2pm close time on 4/15. Remember, all time is UTC on the game server (DateTime.UtcNow and DateTime.Now are the same in Windows Azure, but I use UTC for clarity). Because UTC is currently +4 hours from EDT, we add 4 hours to 2pm (1400 hours) so the cutoff time is 1800 hours UTC. I don’t recommend you set this to 2:15pm because the game may start slightly before 2:15pm. Additionally, I don’t recommend an end time because while the games should play at 2:15pm, it’s possible due to technical issues it might need to be delayed slightly. Ineligible Players We know some plays sneak in occasionally – past winners, employees … even we submit a test bot to demo the project or when trying to resolve an issue. We are usually pretty good at removing those bots. In the main tournament rounds, we’ll do our best to police the registrants to make sure they qualify, but we’ll apply a bit more scrutiny before the round at 2:15pm Friday (hence why we take a 15 minute break to give things a once-over).

Getting a Windows Azure account for Rock, Paper, Azure

If you’re interested in getting a Windows Azure account to play in Rock, Paper, Azure (RPA), there are a few options available to you, from least painful to most painful (in my opinion, anyway): Method 1 – Windows Azure Pass The way most people are getting an account is through the Windows Azure Pass program (using code PLAYRPA).  More details can be found on the Get Started page under step 1.    But, this certainly isn’t the only way to get an account, and – for a few of you – might not be possible.  The Azure Pass is limited to one Live ID, so if you got an account through the Azure Pass program say 6 months ago, you can’t get another one.  (I won’t say anything if you just sign up for another Live ID.) Method 2 – Windows Azure Trial Account Sign up for the Windows Azure Free Trial.   This gives you 750 hours of an extra small compute instance, and 25 hours of a small compute instance.  You do need a credit card to cover overages.  Note: the Bot Lab project by default is set up as a small compute instance.  If you go this route, I highly recommend you change the Bot Lab to be an Extra Small instance.  You can do this by double-clicking the role and changing the VM size: Method 3 – MSDN Subscriptions Have an MSDN Premium or Ultimate subscription?   You already have account hours you can use.  Log into your MSDN account for more information.   This step does require a credit card (or other billing arrangement) to handle overages, but you are not billed as long as you stay within plan.  As of the time of this writing, please note that Extra Small compute instances are beta and not included in the MSDN hours – so be sure to stick with a small instance.  As usual, we recommend taking down deployments once you’re done to avoid wasting compute time. Method 4: Pay as You Go Specials Check out the current offers.   There are few different options based on your needs (and some are available specifically for partners).  The introductory special is the best way to get started, but if you’re using Windows Azure consistently, the Windows Azure Core offers a great value.   If you’re just interested in playing the game and willing to pay or aren’t able to receive other offers for some reason, deploying the Bot Lab as an Extra Small instance costs $0.05 per hour.   If you were to play during the week, and leave the Bot Lab deployed 24 hours, you’d be looking at roughly $5.  (If you only code in the evenings for a few hours, pulling down the deployment overnight and not during use will bring that down substantially.) See you on the battlefield!

My Apps

Dark Skies Astrophotography Journal Vol 1 Explore The Moon
Mars Explorer Moons of Jupiter Messier Object Explorer
Brew Finder Earthquake Explorer Venus Explorer  

My Worldmap

Month List