Version: 5.3

Vegas Blues

Danny Yoo <dyoo@hashcollision.org>

Whenever I come to Las Vegas, I squint through the cigarette smoke at the gambling machines and frown. Dad is always puzzled by my morose behavior.

“What’s wrong?” he asks. I pause and collect my thoughts.

Why does it bother me to be here, in Vegas, watching people play these games of chance, especially when the odds are rolled by a computer program?

Here, let’s look at a simple dice-rolling program.

; generate a random dice roll between 1 and 6
> (define (dice-roll)
    (add1 (random 6)))

This is a simple program that uses the built-in random function to simulate the dice roll.

We can run it a few times:
> (dice-roll)

5

> (dice-roll)

1

> (dice-roll)

4

Doesn’t that look random to you too?

If that doesn’t convince you, let’s roll it thousands of times. We’ll look at the frequency of the results, and see that all the outcomes come out fairly even.
; count-frequencies: -> void
; Roll the roller a bunch of times, and tally up how the dice rolls.
> (define (count-frequencies)
    ; Let's keep a tally to count the dice rolls:
    (define tally (make-hash))
  
    ; We will roll the dice a bunch, and add the results to our tally:
    (for ([trial-number (in-range 10000)])
      (define this-roll (dice-roll))
      (hash-set! tally this-roll (add1 (hash-ref tally this-roll 0))))
  
    ; Finally, let's print the results:
    (for ([i (in-range 6)])
      (printf "~a: ~a\n" (add1 i) (hash-ref tally (add1 i)))))

Let’s try it out.
> (count-frequencies)

1: 1627

2: 1619

3: 1702

4: 1701

5: 1679

6: 1672

> (count-frequencies)

1: 1703

2: 1688

3: 1665

4: 1616

5: 1668

6: 1660

The result of count-frequencies on our dice-roll look reasonably even. So what’s the big problem?

Experienced programmers know that there is no true randomness here. Rather, the rolls we are getting are pseudorandom. The computer dutifully performs a series of steps on a piece of information—a seedthat it keeps secret. The result of that computation looks like it comes out of pure chance, but that’s as much an illusion as the volcanoes, pyramids, and castles in a Nevada desert.

In fact, if we can control the seed, we can control the dice rolls.
; Let us control the seed value:
> (random-seed 31337)
; Roll the dice a few times...
> (for/list ([trial (in-range 10)]) (dice-roll))

'(4 3 2 2 4 5 6 3 6 5)

; If we re-seed, we'll see the exact same rolls!
> (random-seed 31337)
> (for/list ([trial (in-range 10)]) (dice-roll))

'(4 3 2 2 4 5 6 3 6 5)

I think that most non-programmers have a mental model that a dice roll in a machine is a true, non-biased one. But programmers know better. It’s just as easy to write a program that cheats as it is to write a fair one:
(define (dice-roll)
  (cond
    [(high-stakes-bet?)
     (roll-loaded-dice)]
    [else
     (roll-normal-dice)]))

And how can one tell, without having access to the program’s source code, as well as the literacy to read it?

So part of my discomfort is being a member of a tribe that has a secret: programs only do what we tell them to. These programs can be perfectly impartial or partial, and it depends on whose hand guided their creation. Though they may be housed in boxes of solid steel, their integrity is ultimately based on whether or not their programmer has integrity too.

But how can I say this all to Dad as he waits there, expectantly?

“Oh, nothing,” I reply.

He nods and pulls the one-armed bandit.