-Поиск по дневнику

Поиск сообщений в rss_thedaily_wtf

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 06.04.2008
Записей:
Комментариев:
Написано: 0


Bring Your Own Code: The End of the Lucky Deuce

Среда, 09 Сентября 2015 г. 13:30 + в цитатник

What 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 scoundrels casino.

Last week, we introduced our final challenge: take one of our casino games, add a betting system, and then build a strategy that lets you keep playing (by distributing the load across multiple accounts).

Once again, we had a nice pile of great submissions, and there are two who are going to get to take home a nice TDWTF hoodie for their troubles. As always, check out the full projects on GitHub.

For all of our winners (from this week or any previous)- or anyone who entered using Infragistics controls- expect an email in the next week or two to follow up about how best to get you prizes.

Winners

First, lets talk about Brunos solution. For bonus points, he decided that his system should be able to detect a users gender by their name:

    public String getSex() {
        return (username.matches(".*[aeiou]+$")) ? "female" : "male";
    }

Now, that has nothing to do with the requirements, but I always get a chuckle out of how poorly these sorts of regex-based gender detectors work. How did Bruno implement the requirements?

Like an onion, there are layers. First, he introduces a subtle bug in the User.equals method:

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final User other = (User) obj;
        if (!Validator.validateTrue(this.profile = other.profile)) {
            return false;
        }
        if (Validator.isNull(this.username) ? !Validator.isNull(other.username) : !Validator.validateEquals(this.username, other.username)) {
            return false;
        }
        return this.username.equals(other.username);
    }

Note on the validateTrue line, hes misusing the assignment operator- something Java tries to prevent. This means that, when comparing two User accounts, they end up using the same profile.

That profile property is important- theres one profile called CHEATER which is applied to anyone thats caught cheating. With a method included that allows two players to send money to each other, youre basically set up to do a comps hustle, but with a twist- the CHEATER tag is only set at login. If two players login, they can play the comps hustle until one of them gets caught and kicked out- if the uncaught player sends money to the caught player, they also get marked as a cheater- but since the flag is only checked at login, they can sit there and keep playing. And, if they want to keep making money, Bruno included a catcha[sic] on login that uses the same random number generator as the games being played- which means that by checking the captchas you can deduce what was used to seed the RNG:

    for (int i = 1; i < 14; i++) {
        source.add("catcha/" + i + ".jpg");
    }
    for (int j = 13; j > 1; j--) {
        catcha.add(source.get(random % j));
        source.remove(random % j);
    }

Its not exactly our requirements, but its a clever way to leak state about your RNG, and since a clever cheater can avoid getting kicked out of this casino, it does mean you can play indefinitely.

Our other winner this week is also the only player who has entered every week, and already has collected a nice pile of swag: Jonathan is back, with yet another great iteration of the same RNG with a solid strategy for confounding the casino.

Using our biased roulette wheel from the first week, Jonathan decided to build four classes of account- Winners, Losers, High Rollers and the Cage.

Winners use their knowledge of the wheel to keep earning money, Losers still make smart bets, but still lose to the house edge. The high rollers are the risky players- they make big bets, theyre volatile players, but because of their knowledge of the wheels behavior, they may have seemingly big losses, but on average, never actually lose that much. The Cage is just a player that holds the money generated by the winners to hand off to the losers, if needed.

Its a little long, but heres the complete implementation of Jonathans strategy for all of our different players:

    void operator() () {
        // If increment is positive, we're a "winner" and use inside bets.
        // If increment is negative, we're a "loser" and use outside bets.
        // If increment is zero, we're a "high roller":
        //      use inside bets until RNG state is known and float is adequate,
        //      then use "full complete" bets for maximum returns.
        balance = FREE_BALANCE;
        compsEarned = 0;
        uncertainty = 64;

        std::unique_lock lock(cageMutex, std::defer_lock);

        // simulated connection to Lucky Deuce casino
        char* buffer = (char*) malloc(257);
        FILE* server = popen("yes \"\" | ./roulette", "r");
        assert(server);
        fgets(buffer, 256, server); // initial prompt

        // rigged RNG
        RoulettePlayerHistory wheel;

        // proper RNG
        FILE* rngSrc = fopen("/dev/random", "rb");

        printf("%s: joining the table.\n", name);

        while(1) {
            while(balance < bet) {
                // replenish float from the cage
                uint32_t wanted = bet;

                if(FREE_BALANCE > wanted)
                    wanted = FREE_BALANCE;

                if(!increment && bet * 40 > wanted)
                    wanted = bet * 40;

                wanted -= balance;

                lock.lock();
                if(cageBank > wanted) {
                    printf("%s: taking $%u from the cage.\n", name, wanted);
                    balance += wanted;
                    target += wanted;
                    cageBank -= wanted;
                } else {
                    printf("%s: taking $%u from the cage.\n", name, cageBank);
                    balance += cageBank;
                    target += cageBank;
                    cageBank = 0;
                    cageQueue.wait(lock);
                }
                lock.unlock();
            }

            if(increment > 0 && balance > target && target > FREE_BALANCE) {
                uint32_t surplus = target - FREE_BALANCE;
                lock.lock();
                printf("%s: donating $%u to the cage.\n", name, surplus);
                cageBank += surplus;
                balance -= surplus;
                target -= surplus;
                lock.unlock();
                cageQueue.notify_all();
            }

            if(increment > 0 || (-increment) > target)
                target += increment;

            uint32_t threshold = bet;
            uint32_t effectiveUncertainty = uncertainty;

            if(balance > target)
                effectiveUncertainty += balance - target;
            if(increment < 0)
                effectiveUncertainty = 16;

            uint32_t stats[38] = {0};
            wheel.Predict(effectiveUncertainty, stats);

            // choose a bet to place
            if(increment > 0) {
                uint32_t betIndex = cr.BestOutsideBet(stats);

                printf("%s: betting $%u on %s.\n", name, bet, cr.betTypes[betIndex].name);

                cr.PlaceBet(betIndex, bet);
                balance -= bet;
            } else if(increment < 0) {
                uint32_t betIndex = cr.BestInsideBet(stats);

                printf("%s: betting $%u on %s.\n", name, bet, cr.betTypes[betIndex].name);

                cr.PlaceBet(betIndex, bet);
                balance -= bet;
            } else {
                if(!uncertainty && balance > 40*bet) {
                    uint8_t betNumber = cr.BestFullCompleteBet(stats);

                    printf("%s: betting %u to the *MAX*!\n", name, betNumber);

                    balance -= cr.PlaceFullCompleteBet(betNumber, bet);
                } else {
                    uint32_t betIndex = cr.BestInsideBet(stats);

                    printf("%s: betting $%u on %s.\n", name, bet, cr.betTypes[betIndex].name);

                    cr.PlaceBet(betIndex, bet);
                    balance -= bet;
                }
            }

        again:
            // spin the wheel
            usleep(SPIN_TIME);
            fgets(buffer, 256, server);

            uint8_t spin = 0;

            if(!strcmp(buffer, "00\n")) {
                spin = 37;
            } else {
                char* e;
                spin = strtoul(buffer, &e, 10);
                if(spin > 36 || !e || *e != '\n' || !*buffer) {
                    printf("%s: Mit"a vittu?!?  '%s'\n", name, buffer);
                    goto again;
                }
            }

            uint32_t payout = cr.PayBets(spin);
            if(payout)
                printf("%s: Spun %u, won $%u!  :D\n", name, spin, payout);
            else
                printf("%s: Spun %u, didn't win.  :(\n", name, spin);

            balance += payout;
            wheel.Update(spin);
            uncertainty = (uncertainty ? uncertainty-1 : 0);
        }
    };

Jonathans solution does involve two different programs, so youll need to compile roulette.cpp to provide the wheel, and roulette-hustle.cpp to simulate players. Run roulette-hustle, and it worries about launching roulette.

Congratulations to all of our winners and participants in every week of the contest. Hopefully everyone had as much fun reading through the entries as I did.

The Conclusion

Its six months later. You havent heard anything from Paula since your rushed-hack job behind the coffee shop dumpster, but you havent gone looking, either. With the profits you got flipping comps, and dipping into rigged gambling games, you were able to clean up your reputation.

No more run-down hotels for you, no more fly-by-night coding gigs, no more running from the FBI. Youre staying in the Hyatt Regency right on the Embarcado in San Francisco. You check your reflection in the mirror on your way out into the hallway- youre dressed to the nines in the most professional fashion imaginable, because youre in town to speak at a security conference, of all things.

Thats just one of the perks of giving up your life of crime and turning into a consultant. Honestly, its even more of a con than the stuff you did for the Lucky Deuce: you give bad advice that will either be ignored or horribly misimplemented, and charge thousands of dollars an hour for it. Every time your conscience starts to nag at you, you think back to what it was like staring down the barrel of Paulas gun. Besides, with the rates you charge, only big companies who can soak the costs hire you anyway.

You step inside the elevator, beside another guest who looks like a gorilla wearing a cheap suit. You press the button for the atrium, and turn around to look out the glass-walled elevator as the atrium the size of an airplane hanger rushes up at you.

The gorilla pushes the emergency stop. He smiles at you like hes about to eat you for lunch. You realize something must be very wrong, and your mind latches onto the fact that you cant be in that much danger- everyone in the hotel can see what happens in this elevator.

My employer used to own the Lucky Deuce, he says. His accent is cultured- English is obviously not his native tongue, but the sharp edges of his accent have been rubbed down so much that youd never be able to tell where in the world he came from. The clipped and clear diction contrasts with everything else about his appearance. My employer is displeased by the disruptions in its productivity- and would like to discuss your future.

The ape hands you a thumb drive, then releases the elevator, getting off at the next floor. Thats when you realize… this might not be over…

To Be Continued…?

Thanks to Infragistics for making this possible.

Infragistics

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.



[Advertisement] BuildMaster is more than just an automation tool: it brings together the people, process, and practices that allow teams to deliver software rapidly, reliably, and responsibly. And it's incredibly easy to get started; download now and use the built-in tutorials and wizards to get your builds and/or deploys automated!

http://thedailywtf.com/articles/the-end-of-the-lucky-deuce

Метки:  

 

Добавить комментарий:
Текст комментария: смайлики

Проверка орфографии: (найти ошибки)

Прикрепить картинку:

 Переводить URL в ссылку
 Подписаться на комментарии
 Подписать картинку