I’m a little late getting this out (pesky vacations and all) but we re-launched Rock, Paper, Azure (RPA) a few weeks back with weekly competitions! What is Rock, Paper, Azure? In short, it’s a game, primarily for developers. It’s also a fun way to learn programming, as the concept is simple however winning is not. You write code that plays a modified Rock, Paper, Scissors like game and tries to beat everyone else doing the same. The code that you download has everything ready to go, so you just need to worry about implementing some logic. No advanced degree required! We developed RPA as a teaching tool for the cloud. The RPA site and game engine all run in Windows Azure, and it’s a good example of building a scalable application: when the game engine is under demand, such as during our prize rounds, we’ve been able to scale up to keep up with the bot submissions. As a player, you’ll get to try out Windows Azure and learn a little about it along the way. You can also win some great stuff – like a Microsoft Surface, Kinect, and Best Buy gift cards! Check it out at http://www.rockpaperaure.com – have fun playing!
Week #3 of the Rock Paper Azure Challenge ended at 6pm EST on 12/9/2011. That means another five contestants just won $50 Best Buy gift cards! Congratulations to the following players for having the Top 5 bots for Week #3: AmpaT choi Protist RockMeister porterhouse Just a reminder to folks in the contest, be sure to catch Scott Guthrie, Dave Campbell, and Mark Russinovich live online next Tuesday, 12/13/2011, for the Learn Windows Azure event! Does your bot have what it takes to win? There is one more week to try and find out, now through December 16th, 2011. Visit the Rock Paper Azure Challenge site to learn more about the contest and get started. Remember, there are two ways to win: Sweepstakes To enter the sweepstakes all you have to do is enter a bot, any bot – even the pre-coded ones we provide – into the game between now and 6 p.m. ET on Dec. 16th. No ninja coding skills need – heck, you don’t even need Visual Studio or a Windows machine to participate! At 6 pm ET on Friday, December 16, 2011 the "Fall Sweepstakes" round will be closed and no new entries will be accepted. Shortly thereafter, four bots will be drawn at random for the Grand Prize (trip to Cancun, Mexico), First Prize (Acer Aspire S3 laptop), Second Prize (Windows Phone), and Third Prize (XBox w/Kinect bundle). Competition For the type-A folks, we’re keen on making this a competitive effort as well, so each week - beginning Nov. 25th and ending Dec. 16th - the top FIVE bots on the leaderboard will win a $50 Best Buy Gift card. If your bot is good enough to be in the top five on successive weeks, you’ll take home a gift card each of those weeks too. Of course, since you’ve entered a bot, you’re automatically in the sweepstakes as well! Note: As with past iterations of the challenge, even though you can iterate and upload updated bots for the competition, you will only be entered into the sweepstakes one time. You know what they say… you gotta be in it to win it! Good luck to all players in week #4!
Rock, Paper, Azure (RPA) is back! For those of you who have played before, be sure to get back in the game! If you haven’t heard of RPA, check out my past posts on the subject. In short, RPA is a game that we built in Windows Azure. You build a bot that plays a modified version of rock, paper, scissors on your behalf, and you try to outsmart the competition. Over the summer, we ran a Grand Tournament where the first place prize was $5,000! This time, we’ve decided to change things a bit and do both a competition and a sweepstakes. The game, of course, is a competition because you’re trying to win. But we heard from many who didn’t want to get in the game because the competition was a bit fierce. Competition: from Nov 25 through Dec 16, each Friday, we’ll give the top 5 bots a $50 Best Buy gift card. If you’re the top bot each Friday, you’ll get a $50 gift card each Friday. Sweepstakes: for all bots in the game on Dec 16th, we’ll run the final round and then select a winner at random to win a trip to Cancun. We’re also giving away an Acer Aspire S3 laptop, a Windows Phone, and an Xbox Kinect bundle. Perfect timing for the holidays! Check it out at http://www.rockpaperazure.com!
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!
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!
We’re back – this time with an International Grand Tournament in Rock, Paper, Azure. So what’s new? First, we heard many folks loud and clear that they weren’t happy it was U.S. residents only. So, now’s your chance – we’ve opened up the tournament to Canada, the UK, Sweden, New Zealand, Germany, China, and of course the USA. We’ve also included country flags in the leaderboard: Next, we’ve changed some of the rules. Specifically, players are now “blind” when they play in the GT. What does that mean? It means that your bot will not know the team name of the opponent. While playing, the name of the opponent is a “?” and this is also reflected in the game history and log file: Why this change? Primarily, we felt it made the game a little more interesting as it focuses on algorithms as opposed to brute force. We’ve created a GT Practice Round that is not blind, so if you wish, you can tinker in this round to get some exposure and fine tune your logic. Of course, playing in the practice round is optional. Next, players will break down into heats during the GT. After the round closes, we’ll segment players into a number of heats (as I write this, I can’t quite recall if we agreed on a random 25% in each heat, or 25 players per heat). The idea is that this creates a ladder approach to get to the top and adds a bit of excitement to see how far up the ladder your bot can go. It also scales nicer, since we’re assuming a higher involvement in the competition. Finally, we decided to give away something a little sweeter than an Xbox. This time, we’re got $5,000 riding on first place! Additionally, what we’ve decided to do is spread out the winnings a bit more so second place receives $1,000, and the next ten players (3rd-12th place) all receive $250. So, why the prize structure? Well, during an in-person event during our original 6 week competition, I heard someone remark that it would be too difficult to place in the top 3 to get a prize, much less win the Xbox. I can understand that because, indeed, some of the bots we saw were really phenomenal. What we wanted to do was make it so there were enough prizes to reward “pretty good play” for those (like myself) are interested in playing a little, but not spending a hundred hours coding a bot. With the new prize structure plus blind playing, it’s really anyone’s game with a little clever code. We hope you think so, too… and have fun playing! Questions or comments, feel free to ping us either here on my blog or through the www.rockpaperazure.com website.
You’ve heard about cloud computing and already know it’s the greatest thing since sliced bread – and maybe you’ve already attended a Microsoft Azure Boot Camp or other event introducing you to the cloud and detailing the various parts of the Windows Azure platform. Well we’ll do that too… in the first half hour! The rest of the time we’ll have a bit of fun with Azure by taking a look at some cool demos and poking under the hood. We’ll then take a look at some of the innovative uses of cloud computing that Windows Azure customers have already produced.
After lunch, we’ll introduce the genesis and creation of the Rock Paper Azure Challenge… AND run our very own Challenge on-site, exclusive to attendees only, complete with prizes like an Xbox 360/Kinect bundle, a stand-alone Kinect, and a $50 gift certificate. This is an interactive way to learn about developing and deploying to the cloud, with a little friendly competition thrown in for fun.
So bring your laptop, Windows Azure account credentials and a sense of adventure and join us for this FREE, full-day event as Peter, Jim, and I take you “to the cloud!”
· Windows Azure Account – don’t have one? We’re offering a free Windows Azure 30-day pass for all attendees. Apply for yours now as it can take 3 days to receive. Use code AZEVENT
· Laptop with Azure Tooks and SDK installed
Want a leg up on the competition? Visit the Rock Paper Azure Challenge web site and begin coding your winning bot today.
Ft. Lauderdale, FL
Due to the hands-on nature of this event seating is limited. Reserve your spot by registering today!
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))
3: DataTable table = dataset.Tables[opponent.TeamName];
5: foreach (Round round in rounds)
… 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.
3: StreamWriter writer = new StreamWriter(@"C:\RPSLog.txt", append);
7: catch (Exception)
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.
5: using (SqlCommand command = new SqlCommand("SELECT * FROM sys.Tables", connection))
7: SqlDataReader reader = command.ExecuteReader();
8: while (reader.Read())
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!
In part 1, I detailed some of the specifics in getting the Rock, Paper, Azure (RPA) up and running in Windows Azure. In this post, I’ll start detailing some of the other considerations in the project – in many ways, this was a very real migration scenario of a reasonably complex application. (This post doesn’t contain any helpful info in playing the game, but those interested in scalability or migration, read on!) The first issue we had with the application was scalability. Every time players are added to the game, the scalability requirements of course increases. The original purpose of the engine wasn’t to be some big open-ended game played on the internet; I imagine the idea was to host small (10 or less players). While the game worked fine for < 10 players, we started to hit some brick walls as we climbed to 15, and then some dead ends around 20 or so. This is not a failing of the original app design because it was doing what it was intended to do. In my past presentations on scalability and performance, the golden rule I always discuss is: you have to be able to benchmark and measure your performance. Whether it is 10 concurrent users or a million, there should always be some baseline metric for the application (requests/sec., load, etc.). In this case, we wanted to be able to quickly run (within a few minutes) a 100 player round, with capacity to handle 500 players. The problem with reaching these numbers is that as the number of players goes up, the number of games played goes up drastically (N * N-1 / 2). Even for just 50 players, the curve looks like this: Now imagine 100 or 500 players! The first step in increasing the scale was to pinpoint the two main problem areas we identified in the app. The primary was the threading model around making a move. In an even match against another player, roughly 2,000 games will be played. The original code would spin up a thread for each _move_for each game in the match. That means that for a single match, a total of 4,000 threads are created, and in a 100-player round, 4,950 matches = 19,800,000 threads! For 500 players, that number swells to 499,000,000. The advantage of the model, though, is that should a player go off into the weeds, the system can abort the thread and spin up a new thread in the next game. What we decided to do is create a single thread per player (instead of a thread per move). By implementing 2 wait handles in the class (specifically a ManualResetEvent and AutoResetEvent) we can accomplish the same thing as the previous method. (You can see this implementation in the Player.cs file in the DecisionClock class.) The obvious advantage here is that we go from 20 million threads in a 100 player match to around 9,900 – still a lot, but significantly faster. In the first tests, 5 to 10 player matches would take around 5+ minutes to complete. Factored out (we didn’t want to wait) a 100 player match would take well over a day. In this model, it’s significantly faster – a 100 player match is typically complete within a few minutes. The next issue was multithreading the game thread itself. In the original implementation, games would be played in a loop that would match all players against each other, blocking on each iteration. Our first thought was to use Parallel Extensions (of PFx) libraries built into .NET 4, and kicking off each game as a Task. This did indeed work, but the problem was that games are so CPU intensive, creating more than 1 thread per processor is a bad idea. If the system decided to context switch when it was your move, it could create a problem with the timing and we had an issue with a few timeouts from time to time. Since modifying the underlying thread pool thread count is generally a bad idea, we decided to implement a smart thread pool like the one here on The Code Project. With this, we have the ability to auto scale the threads dynamically based on a number of conditions. The final issue was memory management. This was solved by design: the issue was that original engine (and Bot Lab) don’t store any results until the round is over. This means that all the log files really start to eat up RAM…again, not a problem for 10 or 20 players – we’re talking 100-200+ players and the RAM just bogs everything down. The number of players in the Bot Lab is small enough where this wasn’t a concern, and the game server handles this by design by using SQL Azure, recording results as the games are played. Next time in the deep dive series, we’ll look at a few other segments of the game. Until next time!
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…