Bring Your Own Code: The Lucky Deuce: Getting in the Slot |
Last week, 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 scoundrels casino.
Last weeks challenge was to build a broken roulette wheel, that instead of being truly random, avoids recently spun numbers to feel more random. Ive rehosted all of the winners code here.
Many of you noticed that, with our rather silly requirements, you didnt need to do anything to make a cheating wheel. By simply betting on the least recently used numbers, your odds were enough to beat the house. This was true, but thats not a terribly fun approach. Still, Ryan gets credit for taking that reality and putting a thumb on the wheel, so to speak. His solution was to be a little sloppy in how he weighted the probabilities, taking a heavy hand:
def random(self):
r = random.randrange(0, sum(self.weights))
for i, x in enumerate(self.weights):
r -= x
if r < 0:
result = i
break
# adjust weights
for i, x in enumerate(self.weights):
if x < SLOTS - 1:
self.weights[i] += 1
self.weights[result] -= SLOTS/2
if result == SLOTS - 1:
return '00'
return str(result)
With this approach, recently spun numbers become really unlikely, which makes a smart betting strategy even more profitable. Congrats Ryan, you get the Just Doin My Job award. His solution also comes with a profile.py
script, which handily runs a bunch of trials to let you try out his random solution.
Edgar did add a custom cheat, after a fashion. In his solution, instead of checking if a number appears twice in a row, Edgar avoids it if its appeared twice. But thats not what makes his solution entertaining. No, his Python solution, slavishly obeys the PEP8 reccomendations for formatting Python code, to the point of complete unreadability:
while True:
# store occurrence of value
frequency_of_each_roulette_element__list_int[random_position_in_array__int] += __ONE_CONST__INT__
if frequency_of_each_roulette_element__list_int[random_position_in_array__int] >= __TWO_CONST__INT__:
# AVOID RUNS, acc. Req #3
frequency_of_each_roulette_element__list_int[random_position_in_array__int] = __ZERO_CONST__INT__
random_position_in_array__int =\
(random_position_in_array__int + __ONE_CONST__INT__) % __size_of_american_roulette_int__
For his work, Edgar gets to take home the Best Use of Variable Names prize.
Another common exploit was to exploit the lack of randomness in pseudo-random number generation. Jonathan took an approach that fed /dev/random
through SHA256 to generate his pseudo-random numbers. With that information, he can start making predictions after 64 spins. The real clever part isnt the code itself, but the comments:
/* this is an excellent source of randomness, bruce says so */
FILE* fp = fopen("/dev/random", "rb");
…
…
/* that /dev/random is too slow to use every spin */
/* cryptographic hash is effectively a random number, bruce says so */
sha256.add(&state, sizeof(state));
sha256.getHash(hash);
Edgar gets some stickers as part of the prestigious Bruce Says So award.
We had a lot of great submissions- and a lot of them. There were a lot of clever approaches, a lot of Konami codes, and a few that did some sleight of hand with unit tests to cover up their cheats. For sheer energy and thoroughness, I have to give Ben, who sent us a submission that isnt just clever code, but an extremely thorough write-up in a README file. In that write up, he first explains all the work he did to make sure his RNG was secure- and then pulls the rug out to explain exactly why it isnt. Seriously, his README is more of a work of art than any of his code.
That isnt to say that his code doesnt have a fun twist to it. With a perfect combination of extremely thorough comments and a clever use of bitwise operations, Ben hides his sleight of hand right in the open:
/* Make sure the fourth-least significant bit
* is different from the last result. All other bits are random,
* but we know it'll definitely not be identical *again*.
* Why the fourth? I expect "professional" roulette players to
* closely observe some properties, including even/odd (lsb),
* and let's assume they even observe "value mod 4" (second-lsb)
* and "value mod 8" (third-lsb). */
const uint mask = 1 << 3; /* Fourth bit, so shift '1' by three. */
const uint a = avoided & ~mask; /* Take the opposite bit. */
const uint b = generated & mask; /* Take from randomness. */
generated = a | b; /* Merge. */
Read through his code, and try and figure out his trick before reading his README.
You had a close call in Bartsow last week. The FBI tried to catch you coming out of a truck stop diner along Route 66, and its only because Gilda, the waitress, tipped you off that you were able to slip out the back. Thats what you get for leaving behind good tips, but youve padded your bankroll nicely with the proceeds of the Roulette job. You had padded it, anyway- apparently while Gilda was showing you out the back door with one hand, she stole your wallet and got a really big tip with the other.
Out of cash, youve been hitchhiking along back roads. Last night, you got picked up by a bunch of hippies on their way back from San Francisco, and they were good enough to drop you off in a little dirt patch called Dogtown. Its then that your cellphone dings- youve got a new set of requirements.
GRT JOB, the message starts, you did good work. We want you to work on our slots machine project now, it is the same more work that you already did.
Slot machine? Great, they want you to generate some more broken numbers? Or is there something else? As you read the requirements, you see some key points. First off, yes- they do want you to generate some random numbers- three of them to be exact. Theyre less concerned with imitating wheels with all of the complexity that entails, and instead, just want a function or program that can output three random numbers- but with constraints.
Firstly, we want suspense. After each number is output, there must be a pause or a wait before the next number is coming. This adds tension and makes our customers more excited. Secondly, the probabailities[sic] that the first and second numbers are the same must be very high! But the probability that all three numbers match must be very low.
You scratch your chin while thinking about the requirements. Thats all pretty easy, but it gets you thinking. With all those pauses in there, theres gotta be some way you can sneak a cheat in between them. You're going to figure out a way to rip off this slot machine, and rebuild your bankroll.
To 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 dont 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 16th 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.
http://thedailywtf.com/articles/the-lucky-deuce-getting-in-the-slot
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |