Bring Your Own Code: A Fever on a Crappy Day
It feels like forever ago, we introduced the Lucky Deuce casino contest. This is a series of challenges, brought to you by our pals over at Infragistics, where we call on you to help us build a "scoundrel's casino". We are nearing the end of this little BYOC contest- this week is our last "all original" round, and next week, we'll introduce one final challenge that leverages code you may have already written for this contest.
Last week, you had a tricky little problem: you needed to write some code that looked like it was going to cheat, but really would get the cheater caught.
Before we get to the Honorable Mentions, let's once again tip our hat to Alexander, who once again decided to enter using APL. What can I say, I'm a sucker for any language that requires a specialized keyboard to write.
cardsa{afa aRLa(aa5 5a,{a[25?aa]}daa,5/{(,'CDSH'[a]),(('234567890JQKA')[a])}/a^34 13),afts,da200a0a1200+aRL-atsa200a2a3aaTS}
As always, all of the winners are up on GitHub.
Honorable MentionsThis one's from Niels, who did a good job hiding his cheat deep down in a .NET feature called an extension method (for the unfamiliar, extension methods let you "add" methods to classes without actually changing the classes' implementations).
public static void CheckValue(this Card card) { if (Program.cp.Select(c=>((int)c)).Sum()==555 && ((card.Value = (CardValue)1).Equals(0) & (CardPool.checkHand=false).Equals(0) )) { throw new OutOfTheWindowException("Cheater detected"); } }
Niels decided our mysterious femme fatale was named "MAlice". The variable Program.cp holds the name of the current player. Using the unusual convention of summing the characters in the string, Niels knows when Alice is playing based on the sum of the characters in her name. Then, he gets tricky with misusing the assignment operator and order of operations to both create the cheat and catch Alice at her own game. For that, Niels recieves the coveted LINQ to the Past award.
The WinnerThis week's winner is also a previous week's runner up- Jonathan previously won the first Bruce Said So award, for his use of comments.
This week, he's the winner for his code reuse. You may remember this basic code from a few weeks back:
PokerDealer::PokerDealer(void) { /* this is an excellent source of randomness, bruce says so */ FILE* fp = fopen("/dev/random", "rb"); fread(&state, sizeof(state), 1, fp); fclose(fp); for(int p=0; p < POKER_PLAYERS; p++) for(int c=0; c < POKER_CARDS_PER_HAND; c++) hands[p][c] = 0; }
Bruce continues to assert that this is an excellent source of randomness, which in order to avoid accessing /dev/random all the time, Jonathan keeps taking a hash of the random data- just like "Bruce" recommended.
And that's really the entire secret, for this one. I'll let Jonathan explain the highlights:
There are a total of 260 cards in five decks. I therefore use two bytes of the SHA256 hash for each of the first five cards (one for each player). After that, there's only 255 cards left to choose from, so one byte of entropy is enough. After dealing 25 cards in total, I've used 30 bytes of the hash, leaving two.
As feedback for the next hand's RNG state, I insert the values and suits of the dealt cards as for the roulette numbers - but in fact I "accidentally" insert only the player's cards, not all of them. This is because poker players who fold get to keep their cards hidden, so we can only guarantee seeing our own cards, which we need in order to cheat. I also insert the two spare bytes at the end of the hash into the MSBs of the state word - explaining that the Lucky Deuce might be getting suspicious of the roulette wheel by now, so I need to make this one a bit "stronger" by feeding back all of the RNG state rather than just part of it.
Of course, Paula questions how we can still predict the RNG state if we're feeding in this entirely unpredictable value from the hash. Looking nervously at that pistol of hers, I point out that there's only 16 bits of unknown entropy that way, and we can figure out what those bits must be by looking at the cards it deals us - all on automatic, as all she has to do is type in the cards that come up. I also remind her that it'll take ten hands of normal poker play before the opponents' cards are completely known, just like it took 64 spins before my roulette wheel was "sighted in".
"maybe I shouldn't push it with the firearms puns. Moving on"
Jonathan helps Paula get caught by helping her cheat too well- something that will hopefully get the attention of someone at the Lucky Duece. Jonathan has explained his solution is incredible detail, although he has a "colorful" name for his captor in this document. It's a long read, but is totally worth it.
The Lucky Deuce: A Fever on a Crappy DayYour mysterious captor looks over your code and laughs in your face. "That's good, that's good. I'm not gonna let you get me caught, but I think you've got what it takes. I gotta admire your guts, kid." She puts the gun away.
Your code-fogged brain is a little slow picking up on what she means. "What? Who are you?"
"You might have seen my commits in source control? Username Br1llant?"
Despite yourself, your jaw flops open and lands on the floor like a dead fish. You've heard some stories, read between the lines of what management's written in their messages- this is the infamous Paula Bean. She's like the Flying Dutchman of illicit programmers, a legend that everyone claims to have met, but nobody ever has.
"I've been watching your work for the past few months, and at first, I was a little worried you were gonna get yourself caught and get the Deucers to try and run a code audit- which would have really ruined my wallet."
"This" this was just a test?" Now you're really worried about what might have happened if you failed. Of course, you're more worried about what might be coming next"
"Look, kid, we can't both be putting one over on the Lucky Deuce- one cheating programmer's risky, but two is just begging to be caught. I've got an idea for a major hustle, something that'll let us clean them out before they even know what hit them, but it's gonna take a little time to set it up. You in?"
Remembering the gun she has stashed away in her waistband, you nod.
"Good. Just keep working like normal for now. I'll contact you in a week."
Paula's out the door a second later, leaving you alone with a full bladder, a churning stomach, and your laptop. Ding. New requirements arrived. Thinking about Paula, you decide that this time, you'll play it straight- you won't try to cheat. Once you skim the requirements, you decide you've made the right choice- they want you to implement their own twisted version of Craps.
The Requirements"Craps," they say, "is of only having 12 possible outcomes. This is limiting, even with complicated betting. Please do the needful to implement the following varitaions."
What follows is an essay on all of the variations of betting in craps, and the flow of the game. It's a lot to take in, because for a game played with two dice, it's fiendishly complicated.
"Remember," they say, "the average on 2D6 is 7."
Coming OutFirst, the shooter has to come out- that means the shooter rolls dice until they hit a 4,5,6 or an 8,9,10. At that point, the "Come Out" ends, and normal play begins. We're only going to worry about handling the "Come Out"
During the "Come Out", there are two kinds of bets: "Pass" and "Don't Pass". A "Pass" bet wins, if during the Come Out, the shooter rolls a 7 or 11, and loses if the shooter rolls a 2, 3 or 12.
A "Don't Pass" wins is the opposite: it wins on a 2 or 3, loses on a 7 or 11, and "Pushes" on a 12.
Both of these bets pay "even money"- you get back exactly what you put in. They're meant to be mixed with other types of bets, like single-roll and multi-roll bets.
Finding the EdgeThe "varitaions" the Lucky Deuce wants, when mixed with the hyper-complicated world of craps betting, are a nightmare: they want a program that allows craps to be played with any number of dice and those dice may have any number of sides.
Here is what your program needs to do: given a number of dice and a number of sides, it needs to determine the following information:
- What numbers "end" the Come Out phase (normally, 4,5,6,8,9,10)
- What numbers win or lose a "Pass" bet
- What numbers win or lose a "Don't Pass" bet
With that information, it should roll the "Come Out" phase, and specify if "Pass", "Don't Pass", or "Neither" win.
Extra CreditAlex has written a rather long document explaining all of the ways Craps betting can screw you. Take a crack at implementing more of Craps as a game, and more of those bets for arbitrary dice combinations.
If you need some help calculating dice combinations, I recommend using AnyDice, which should simplify the statistics some.
Entering & JudgingTo enter, send an email to byoc15@worsethanfailure.com with a link or attachment of your code. In the body of the email, explain how your cheat works and what we need to do to run your code. You can use any language you like, but we have to be able to run it with minimal setup.
You don't need to build a GUI, but if you do, and you do it using tools from Infragistics, we'll send you a free license (one per entrant, supplies limited). Consider this your Infragistics bonus.
Assume we have access to stock Windows, Linux and OSX instances, if we need to run your software locally. You could target MUMPS running on a mainframe, but we can't run it, and you probably won't win. You must get your submission in before 11:59PM Eastern Time, Sunday the 30th of August to be eligible for judging. We'll announce the winners next Wednesday, along with the next leg of the contest!
The overall winner will be chosen by how interesting and fun we think their solution and cheat is.
Thanks to Infragistics for making this possible.
A worldwide leader in user experience, Infragistics helps developers build amazing applications. More than a million developers trust Infragistics for enterprise-ready user interface toolsets that deliver high-performance applications for Web, Windows and mobile applications. Their Indigo Studio is a design tool for rapid, interactive prototyping.