
Show HN: A Set of Dice That Follows the Gambler's Fallacy - xori
https://github.com/xori/gamblers-dice
======
andy_wrote
There's a probability model called the Pólya urn where you imagine an urns
containing numbered balls (colored balls in a typical example, but to draw the
comparison with dice we can say they're numbered 1-6), and every time you draw
a ball of a certain color, you put back more balls according to some rule. A
few probability distributions can be expressed in terms of a Pólya urn, see
[https://en.wikipedia.org/wiki/P%C3%B3lya_urn_model](https://en.wikipedia.org/wiki/P%C3%B3lya_urn_model).

A fair 6-sided die would be an equal number of balls numbered 1-6 and a rule
that you simply return the ball you drew. You can get a gambler's fallacy
distribution by, say, adding one of every ball that you didn't draw. I read
the code as a Pólya urn starting with 1 ball 1-N and doing that on each draw
plus reducing the number of balls of the drawn number to 1.

Also related, in 2d space, is the idea of randomly covering the plane in
points but getting a spread-out distribution, since uniformity will result in
clusters. (If you're moving a small window in any direction and you haven't
seen a point in a while, you're "due" to see another one, and vice versa if
you just saw a point.) Mike Bostock did a very nice visualization of that
here:
[https://bost.ocks.org/mike/algorithms/](https://bost.ocks.org/mike/algorithms/)

~~~
xori
Thank you! Sometimes the hardest thing is knowing what to google!

~~~
duxup
I do a lot of furious googling thinking: "Oh man this has to be a thing but
what could it be and how would someone describe it?... awe forget it."

Then months later by accident while looking at a completely different topic:
"OMG there it is, the thing!"

~~~
CPLX
Indeed. This happened to me the other day trying to find the name for a domino
joiner while googling for biscuit joiners.

------
ideonexus
A great application for this is in randomizing playlists. My friends, who are
also CS grads and should know better, have often complained that their MP3
players, CD carousels, etc play the same music too often claiming that the
random is broken, when a song repeating in a short period of time or other
songs never playing is what you would expect from a truly random selection.
Using this algorithm, you'd be sure to hear all of your songs. I'm guessing
most music services already do something like this.

~~~
drewrv
This is also an example of users saying they want one thing (randomness) when
really they want something else (variety).

~~~
nkrisc
Great example of finding what users really want as opposed to what they say
they want.

~~~
Tarq0n
This sounds like a giant strawman to me. Where do programmers get the idea
that a mode called 'shuffle' would call for sampling with replacement? The
obvious software analogy to shuffling would be re-ordering a list randomly,
not randomly drawing from a list.

I think this whole shuffling meme started with Spotify's engineers
misunderstanding what they were asked to do, then claiming their customers
don't know what they want when they obviously delivered the wrong feature.

------
Pfhreak
Interesting, and at first I was excited about the possibilities in something
like D&D, where a series of bad rolls can have you feeling down. "I'm due for
a critical hit any swing now..."

Players would love that! Make my hero feel more heroic! The inevitable
comeback!

But then I thought about the inverse case -- you are doing really well, and
now you are due for a failure. Or series of failures. That would feel awful.

We have a lot of emotions around dice rolling. I wonder if players really want
from their dice. Would players prefer dice that are secretly unevenly weighted
towards good rolls? Would they still want those dice if they knew they were
weighted?

~~~
talyian
In some competitive games like Dota and LoL, the random distribution for
critical hits is weighted so that it ramps up over time, resetting after a
successful crit.
([http://dota2.gamepedia.com/Random_distribution](http://dota2.gamepedia.com/Random_distribution))
This both reduces the chance of two high rolls coming up twice in a row as
well as long periods of low rolls.

It doesn't have the "you are doing really well, and now you are due for a
failure" since "not a critical" isn't really that negative of an outcome.

For something like D&D, the same kind of "better-than-random" distribution
just comes from adding dice. 4d6 is much more consistent than 1d21+3.

~~~
gozur88
Dota was my first thought when I read the article. Good Dota players pay
attention to their crits, and if they haven't had one in a few hits they
adjust strategy with the expectation of higher damage, something you would
never do if it was truly random.

~~~
joefkelley
Yeah I've definitely seen Arteezy on PA hit neutrals until he gets a few non-
crits in a row, then go gank.

------
doodpants
> I made a chatbot that rolled dice, and it was constantly criticized for
> being "broken" because four 3's would come up in a row.

> These accusations would come up even though they (all being computer science
> majors) know it's possible (although unlikely) for these events to happen.
> They just don't trust the black box.

I am reminded of the approach that GamesByEmail.com used to address this
criticism:
[http://www.gamesbyemail.com/News/DiceOMatic](http://www.gamesbyemail.com/News/DiceOMatic)

~~~
nfriedly
> _As I promised earlier, if you donate to the site and are unhappy about the
> rolls, let me know and I will pull a die out of the machine, melt it flat
> and mail it to you, as an object lesson to the other dice. Tangible
> revenge._

Hah! That might be the best donation "gift" I've ever heard of!

------
nickm12
I had the privilege of studying probability from G-C. Rota. One of my favorite
quotes from him was "Randomness is not what we expect", which he used to
describe the phenomenon of people disbelieving that random data was actually
random. Another great was "This will become intuitive to you, once you adjust
your intuition to the facts."

~~~
DINKDINK
A good way to show how the "Randomness is not what we expect" phenomenon
manifests is the following.

Given a fair coin that outputs Heads (H) or Tails (T), which of the following
sequences is more or less probable

HHTHTT or HHHHHH

Answer: Both are equally probable strings to be generated by the fair coin and
each should occur once in every 64 sequences (~1.56%)

~~~
andy_boot
True But I would like to show you an interesting counterexample which requires
changing the rules slightly. If we toss a coin _and keep tossing until one of
the below sequences turn up_ then which sequence is more likely?

HHHHHH THHHHH

Answer: THHHHH. Only 1/(2^6) of the time it will be HHHHHH. The only way to
get HHHHHH will be if the first 6 flips are heads. If you don't flip a head
you must have got a tail which means THHHHH will always appear before HHHHHH.

~~~
ianamartin
I think the real issue that most people have understanding this stuff is that
they don't have a clear grasp of dependent vs independent events.

We tend to use the fair coin or the fair die as a common way of talking about
things, but I've found that this is problematic for a lot of people.

First off is the use of the word fair. People not from a background in
statistics don't think of that word the way we do. They think of it as an
attribute of the object itself. The the coin or die is 'fair' in the ethical
sense of the word.

Second is the experiential understanding: 'This coin is fair and therefore
should flip heads and tails with equal frequency. It's the same damn coin, and
I flipped it a thousand times! Why are these crazy stats people telling me it
comes up heads and tail equally often? It doesn't, dammit!'

What I've had some success with helping people understand independent trials
is to get them to envision flipping 6 different coins at the same time. Then
you can sort of walk them back into understanding that flipping 6 different
coins once is no different from flipping the same one 6 times. The events are
totally unrelated, and a past event is not a predictor of the future.

Plus, you can actually map out the math for them on the spot. .5 * .5 * .5,
etc.

That's just my experience trying to explain things though. Would love some
criticisms if there are better ways to go about this.

------
cableshaft
There was an old flash video game I worked on a long time ago where I did
exactly this. I had a boss with two main attacks, and I didn't want it to be
super predictable A/B/A/B, so I had it pick between A and B randomly, then
reweight the probabilities, so if it picked A, instead of 50% A, 50% B it'd
now be 25% A, 75% B. If it picked A again it'd be down to like 12.5% A, 87.5%
B. If B then got chosen, it'd flip flop to 75% A, 25% B, etc. The result was
it mostly went back and forth between the two, but would do some attacks 2 or
3 times in a row before switching back to the other.

You can actually play it right here and go direct to the Boss Fight if you
wanted to: [http://briancable.com/clock-legends/](http://briancable.com/clock-
legends/)

~~~
hn_throwaway_99
Hmm, but by the algorithm you describe you are MORE likely to get a "super
predictable" a/b/a/b than you would with just an independently random coin
flip each time. That is, strings of multiple As or Bs in a row is less likely
with your algorithm, but you make it sound like that's what you wanted.

~~~
cableshaft
No, you misunderstand. I didn't want it to be always A,B,A,B, but I also
didn't want it to be an even coin flip and risk an A,A,A,A,A,A,A or whatever
(like in the play _Rosencrantz and Guildenstern are Dead_ ).

With my method, it was possible for the same move to be picked 2 or 3 times in
a row, but it mostly went back and forth, so the player was definitely going
to encounter both moves, but they couldn't know for absolute certain which
move the next one would be (and they both needed you to kind of quickly get
into different positions before getting hit).

The type of pattern you'd usually get with mine was more like
A,B,B,A,A,B,A,B,A,A,A,B,B,A.

------
vanderZwan
A similar, simpler idea is sometimes used in games: you put all choices in a
"bag", then draw from the bag until it's empty, then put everything back.

Tetris is the go-to example. Tetris has seven tetronimos, and in most modern
implementations you're guaranteed to see them in sets of seven in random
order.

[http://tetris.wikia.com/wiki/Random_Generator](http://tetris.wikia.com/wiki/Random_Generator)

This is pretty essential to make competitive play err on the side of skill
rather than randomness: pro-players can anticipate and plan for this. For fun,
here's a recent Tetris head-to-head speed-run from Awesome Games Done Quick,
with pretty good narration about the tactics involved:

[https://www.youtube.com/watch?v=PeNB4w99FiY&t=1h21m15s](https://www.youtube.com/watch?v=PeNB4w99FiY&t=1h21m15s)

------
bigato
Now I really want physical loaded dice which follow the gambler's fallacy! Is
it too crazy of an idea?

~~~
Pxtl
You could just use a deck of cards with numbers on them. That's the simplest
way to do "Gambler's Fallacy Dice" IRL. For example, there's a popular Catan
expansion pack that replaces the dice with a deck of cards with numbers on
them for just this reason, because in Catan each roll of 2D6 represents
different regions of the map paying out so if a number never comes up it
_never_ pays out.

~~~
acomjean
The thing about rolling 2D6, is the distribution isn't even.

I'm not sure that factors into the game (have played but its been a while).
Cards seem like a more controlled way to distribute the results with some
randomness.

only one way to get a 12 (6+6) but 7 much more likely.. (6+1, 5+2, 4+3, 3+4,
2+5, 1+6)

as someone who played a bit of online backgammon back in the day, We always
suspected the random dice rolls behaved differently in the game than playing
in real life...

~~~
speeder
Catan cards take that in account.

They basically made one card for each possiblity of pair of dices, so there is
a 7 card for 6+1, another for 5+2, and so on...

Playing with it is MUCH better than with dice... when I played with the dice
that came with my copy with catan, the dice were clearly defective (rolls
weren't just random-looking, they were WILDLY wrong, it rolled 10s 2 times the
amount of 7s...), and the game was super boring, it would end with everyone
having the same materials and not having others, so not even trade would fix
the game, we had stuff like 10 turns in a row where noone had one particular
item while the 'bank' ran out of the other items because everyone had lots of
them.

~~~
pbhjpbhj
In Catan can't you trade any 4 identical resources for any one other resource?
It slows down resource acquisition but should eliminate the situation you
describe!?

~~~
speeder
You can, but if I remember the resource noone had was bricks, that is very
important...

So the game pace slowed to a crawl... Also, the funky dice never rolling
bricks meant people would quickly rack up random resources, sometimes like 3
of each, so they ended with 9 cards, and would then lose to robber rolls (7).

Then of course in one game where this happened there was an asshole cousin
that thought it would be hilarious to hog resources and make the game worse,
he would spend his whole turn making 'negotiations' with everyone, and them
cancelling them, wasting like 5 minutes every time it was his turn, and
sometimes if 7 was taking long enough have 20 cards on his hand...

We don't play with that cousin anymore either.

But yeah, not having a way to build roads make the game suuuuuper slow.

------
hesdeadjim
This reminds me of Sid Meier's talk at GDC about having to game the random
number system because of player's expectations:

[http://www.gdcvault.com/play/1012186/The-Psychology-of-
Game-...](http://www.gdcvault.com/play/1012186/The-Psychology-of-Game-Design)

More often than not, true RNG in game design takes a back seat to fun.

~~~
eterm
Playerunknown's battlegrounds currently suffers from item spawns being "too
random". You can go houses without finding a rifle then suddenly find 2-3
practically on top of each other.

They could do with learning a little from other games and making it a little
less random.

Ultimately you can see it as a bug in human reasoning but we're the ones
playing the game.

~~~
fenwick67
TBH I like the current uniformity of the item spawns. It varies the gameplay
and forces you to adapt.

If every house had one pistol and one rifle it would get pretty dull. Raiding
3 houses and only getting a crossbow, bandages, and SMG magazines is
frustrating but it's exciting. Just last night I got to #3 or #4 with a
crossbow and a pistol.

------
Thespian2
For board games, like "Settlers of Catan" where resources are generated based
on rolls of 2d6, one could use an analog version of this with a cup containing
36 chits, of the numbers 2-12 according to the normal distribution, _without_
replacement. You would still get the randomness of ordering, but over 36
draws/turns would get a complete "average" distribution.

If that is a bug or a feature is left as an exercise for the reader.

~~~
cletusw
[https://boardgamegeek.com/boardgame/20038/catan-event-
cards](https://boardgamegeek.com/boardgame/20038/catan-event-cards)

------
kator
I often use google "flip a coin"[1] for stupid things and the other day I was
wondering why almost every single time it came up heads. I started to wonder
if there was a browser rng problem or the code was crazy etc.

[1]
[https://www.google.com/search?q=google+flip+a+coin](https://www.google.com/search?q=google+flip+a+coin)

~~~
yathern
Just tried it, and my first four flips were heads - you may be on to
something... I'll keep flipping and come back with my results.

Update: Heads stayed ahead by a few for quite a while, until they tied at 45
each. It's a race to 50, my money is on tails - it's due for a comeback!

Update: Tails takes the lead, 46-47!

Update: 47-49 Tails is in position to strike!

Update: Tails wins! 48-50! (two more clicks to make a sum of 100 results in a
perfect 50/50 split)

It's surprisingly fun to anthropomorphize heads vs tails, and commentating on
their battle

~~~
wpietri
Obligatory relevant XKCD: [https://xkcd.com/904/](https://xkcd.com/904/)

~~~
wpietri
And for those who are really in to this topic, Taleb's "Fooled by Randomness"
is great. There's a section on how financial traders often end up ranked like
this. Somebody makes an effectively random bet, but it pays off big so they're
treated as a genius. It made me see all sorts of organizations differently.

~~~
ianamartin
Taleb is the Deepak Chopra of Economics and Probability. What he says sounds
really important, but is mostly a bunch of horseshit.

~~~
wpietri
The guy spent years as a trader. I spent a few years working for traders. I
think his analysis of the sociology and psychology of trading was spot on.
That's the main content of this book, so I'm still comfortable recommending it
even if he doesn't meet your standards elsewhere.

~~~
ianamartin
I think he's pretty much the definition of survivorship bias. And that he
deeply misunderstands statistics in the same way that Malcolm Gladwell does.

------
closed
At first I was confused, because statistical models that aren't temporally
independent are very common.

But it's very clear from the comments that having dice that aren't independent
between rolls is incredibly in demand :o, and having the right words to google
can be tricky.

(I feel like there's an important lesson there)

~~~
xori
This is what I found my University degree was best for. Teaching me what the
name is, of the thing to Google in the future.

------
onetwotree
Video games, especially competitive ones, do this to limit the effect of
randomness on the outcome of the game, while still keeping the sequence of
random events unpredictable enough to "feel" random and preventing simple
exploits.

DoTA2 uses a simple distribution based on the number of "rolls" since the last
successful one - P(N) = P0 * N, where P0 is the base probability and N is the
number of rolls since the last successful one[1].

It keeps both "hot" and "cold" streaks from being too much of an issue,
although that doesn't stop players from cursing the RNG gods when they lose.

[1]
[http://dota2.gamepedia.com/Random_distribution](http://dota2.gamepedia.com/Random_distribution)

------
eriknstr
> I made a chatbot that rolled dice, and it was constantly criticized for
> being "broken" because four 3's would come up in a row.

> These accusations would come up even though they (all being computer science
> majors) know it's possible (although unlikely) for these events to happen.
> They just don't trust the black box.

This reminds me of a talk [1] given at Game Developer's Conference (GDC) about
the game Civilization, in which the Sid Meyer -- creator of said game -- spent
a bit of the time talking about the difference between fairness and perceived
fairness. The talk is only an hour long and worth watching.

[1]: [https://www.youtube.com/watch?v=AJ-
auWfJTts](https://www.youtube.com/watch?v=AJ-auWfJTts)

~~~
vacri
When your battleship is destroyed by a peasant with a pitchfork, there's not a
lot of perceived fairness...

------
root_axis
This reminds me of an article discussing the perceived outcome of RNG
decisions in video games. In many types of games, the system will display a
percentage chance of success for a given action which allows the player to
make risk assessments regarding possible choices. Unfortunately, the
unmodified RNG behavior creates an unpleasant experience for the user because
the unweighted random outcomes feel "unfair" when failure streaks pop-up,
thus, game designers almost always introduce some type of magic cushioning to
the RNG so that the user never faces too many repeated failures.

~~~
NelsonMinar
Folks who play Blizzard games call this the "Pity Timer". World of Warcraft,
Hearthstone, and Overwatch all have some mechanic where your odds of getting a
desireable thing go up if you've had more recent disappointments.

RNJesus is merciful.

~~~
heartles
It's also known as a mercy pull in kingdom hearts Union X, where after a few
failed attempts of trying to get a high level medal they will guarantee you
one on the next pull.

------
_Marak_
I'm probably very wrong, but I still feel there is some undiscovered science
when it comes to RNG and the fallacy of the maturity of chances ( Gambler's
Fallacy ).

Einstein believed the universe was deterministic. Just because it appears to
us that there is no correlation between independent events ( the roll of a
dice ), does not mean that there isn't some underlaying variable that we are
unable to measure or perceive which is affecting the outcome of the roles.

~~~
abritinthebay
There almost certainly is but you can’t collect the data. At some point
quantum effects will come into play too.

Theoretically all physical processes are predictable, but in practice there is
a limit.

~~~
robotresearcher
> Theoretically all physical processes are predictable

If you count a radioactive decay event as a physical process, then this is not
so.

~~~
abritinthebay
I don’t. Radioactive decay is practically the very definition of the quantum
effects I mentioned.

~~~
CryptoFascist
Not counting radioactive decay as a physical process because you've chosen to
define physical processes as deterministic is some intriguing mental
gymnastics.

~~~
abritinthebay
_for the purposes described in the comment_ \- I was quite clear that a
certain level you get down to quantum effects.

But for the context of the physical processes the OP was talking about those
effects are not significant and so I excluded them.

~~~
robotresearcher
How about we replace the dice with Schrödinger's cat?

~~~
abritinthebay
Then we’re dealing with a very different thing and the conversation is
therefore different?

~~~
robotresearcher
> Theoretically all physical processes are predictable, but in practice there
> is a limit.

So you defined away quantum effects as 'not physical', which most people would
not agree with. How do feel about the _theoretical_ limits on measurement
accuracy that also negate your claim?

------
YCode
I wonder if this could be / has been applied to loot tables in video games in
order to keep the player interested in playing.

I've designed a few loot tables and the Gambler's Fallacy is a criticism I
often have to deal with when people don't understand why a given item hasn't
dropped despite them having killed a mob enough times to statistically warrant
it.

~~~
woodrowbarlow
on the other side of the coin, monster hunter players claim that the game
actively avoids giving them items that they want in order to increase the
(eventual) satisfaction. they call it the "desire sensor".

[http://monsterhunter.wikia.com/wiki/Monster_Hunter_Wiki:Mons...](http://monsterhunter.wikia.com/wiki/Monster_Hunter_Wiki:Monster_Hunter_Vocabulary#Desire_Sensor)

the studio has denied the existence of any such mechanism.

------
rivo
The quote at the end is meant as a joke but it's interesting how often this is
true. A lot of magic tricks rely on being prepared for different outcomes,
while often trying for the least likely one first. This unlikely outcome
happens surprisingly often and therefore makes the effect even more
unbelievably amazing.

I had a friend think of a playing card and any number (1-52). She picked the 6
of spades and the number 15 which is exactly the position where the card was
located. It was only the third time I had done this trick with anybody.

Obviously, card and number picking is not uniformly random, especially when
you influence their choice (e.g. "pick a large number"). But the odds of
someone guessing the exact combination should still be extremely low.

A lot of what you see from David Blaine on TV is exactly this. He always has a
backup plan but more often than not he doesn't need it.

------
erikb
And then there's also the gamblers wisdom: If the dice was facing a 6 for too
many times in a row, look for another game.

------
methodin
It's always nagged me that statistical problems are scoped so small. Surely in
saying there's 6 outcomes on a dice you'd obfuscated the billions of
interactions between atoms and input possibilities in doing so. Thrower A and
thrower B will undoubtedly throw slightly different which might actually
constraint the outcomes and skew the 1 in 6 percentages?

It's similar to me to condensing 30 characters to 5 via an algorithm. You can
go one direction but not the other and if your model was centered around the
resulting 5 it doesn't really reflect what's actually happening which may skew
the probabilities quite a bit. e.g. if the algorithm was "if first letter is
not q, then first letter in output is q". If you were saying each has an equal
percentage of occurring it'd be flat out wrong.

* I am not a statistician and have no idea what I'm talking about

~~~
ianamartin
For these kinds of exercises about fair dice and fair coins, it's a lot like
the kind of jiggery-pokery that happens in Physics classes and stuff. "Under
ideal circumstances . . .", "In a perfect vacuum . . .", etc.

Outside of games, for which this was explicitly created, these kinds of things
are learning tools to understand distributions and dependent vs. independent
events, and it also makes a separate point about assumptions.

In reality, if we were wanting to predict the outcome from a real dice-
throwing event, we would either sample the results from actual people throwing
dice, or we would simulate the results based on parameter inputs for exactly
the types of things you are talking about.

Of course, no one really cares that much about dice, other than people who
play board games with dice. :) So substitute any other stochastic method for
generating an outcome that does matter, and the statistical approach will
generally be the same: either sample or simulate.

Obviously there are exceptions, but that's really the basic idea.

------
jonjonjonjon22
I'm not a programmer but I've thought about this a lot. It'd be interesting to
know if my simple solution here has something wrong with it.

My idea is based on time - if we assign each song to a 1/1000th of a second,
we play the song that matches the 1000th of a second when the next song is
called.

In this case, I'm referring to the 1/1000th of a second of current time of
day. Depending on the song´s position in the second that I change tracks, is
what song gets played.

A bit more randomness (if this is needed) could come if we use Pi - for
example, we can run through a series in Pi which adds to the ID of the song.
Differing track lengths then do the job of ensuring that we always wind up on
a different song in the loop.

The above seems to my layman's eye to be a simpler solution, at least.

------
smallnamespace
This shows up a lot (predictably) in actual games, e.g. Hearthstone sells you
digital cards, and the randomization specifically guarantees that the time
between rare cards is capped [1].

Having unusually bad luck (e.g. opening 100 packs and not getting a single
legendary card, when the average would be every ~20 packs) feels bad and
probably loses Blizzard a customer, so the solution is to cut off the downside
tail of the distribution.

[1]
[https://www.reddit.com/r/hearthstone/comments/3z7jyh/pity_ti...](https://www.reddit.com/r/hearthstone/comments/3z7jyh/pity_timer_on_packs_opening_and_the_best_strategy/)

------
colanderman
A simpler (albeit quite deterministic) way of accomplishing this is to use an
LFSR [1] or the CRC [2] of an incrementing counter. Such a sequence of values
"looks random" under many measures but also has the probability that you
_will_ eventually get an even distribution of values (after the period of the
counter).

[1] [https://en.wikipedia.org/wiki/Linear-
feedback_shift_register](https://en.wikipedia.org/wiki/Linear-
feedback_shift_register)

[2]
[https://en.wikipedia.org/wiki/Cyclic_redundancy_check](https://en.wikipedia.org/wiki/Cyclic_redundancy_check)

------
18nleung
How exactly does the roll() method work? Can't seem to parse the meaning of
`runningSum` and `mark`.

    
    
      roll() {
        const sum = this.state.reduce((p, c) => p + c, 0)
        const r = Math.random() * sum
        let runningSum = 0
        let result = -1
        for (let i = 0; i < this.state.length; i++) {
          const mark = this.state[i]
          runningSum += mark
          if(r < runningSum && result === -1) {
            result = i
            this.state[i] = 1
          } else {
            this.state[i]++
          }
        }
        // Add 1, so the die roll is between 1 -> size of die
        return (result + 1)
      }

~~~
18nleung
Ok — I think I've figured it out, but let me know if I've gotten anything
wrong:

At the outset, `this.state` is initialized as an array of `1`s — [1, 1, 1, ...
, 1] — the number of `1`s is based on the `size` parameter passed to the `Die`
constructor. So for a 4-sided die, `this.state` would initially be `[1, 1, 1,
1]`.

`sum` is the accumulated sum of `this.state`, but it helped me to think of the
`sum` variable as a number line. Continuing with the 4-sided die case, we'd
have a number line of length 4 at initialization (sum of `[1, 1, 1, 1]`).

In the context of a number line, though, `this.state` can be thought of as
giving the geometric positions of each possible result. `this.state[i]` simply
gives the length of the valid region for a certain result. At initialization,
each result of `1` to `4` of our four-sided die would have a length of 1 on
the number line (again, `[1, 1, 1, 1]`).

In concrete terms, the region [0, 1) on the number line would yield a roll of
`1`, the region [1, 2) would yield a roll of `2`, ... , the region [3, 4)
would yield a roll of `4`.

With that in mind, we can think of `r` as choosing a random point on the
number line between 0 and the end of the number line. At initialization, it
simply chooses a point on [0, 4), since 4 is the length of our number line.

`runningSum` is our location on the number line. The code chooses a result
here using the boolean expression `(r < runningSum)`, but it helped me to
think of it in flipped terms: checking if `runningSum` is greater than or
equal to `r`.

In essence, we're traversing the number line starting from 0.

Back to our four-sided die example: let's say `r`, the random point on the
number line we got, was 2.5. At initialization we'd start by checking the
region of the number line where `1` would be our result. Since `this.state[0]`
(the length of the valid region for the result `1`) is 1, we can say that if
we choose a point randomly on the number line [0, 4) and it is on the interval
[0, 1), our roll is a 1.

However, 2.5 is not on [0, 1), so we add the length of the region where `1` is
valid to `runningSum` (our location on the number line) so we can move on to
the next region - the interval where `2` is our result. The length of this
interval is stored in `this.state[1]`, and is also equal to 1 (`this.state` =
`[1, 1, 1, 1]`). In terms of our number line, the valid interval is thus [1,
2). At this point, our location of the number line, `runningSum`, is 2: still
less than 2.5.

Next, we'd get to the region for the result `3`, `this.state[2]`, and we'd be
at [2, 3) on our number line. At this point, our `runningSum` (location on the
number line) is 3, which is greater than `r` (the randomly chosen point on the
number line), 2.5, and we have our result. (sidenote: the variable `result`
being equal to `-1` is a sentinel value and prevents `4` also being considered
a valid roll by virtue of it being greater than 2.5 as well. After this
iteration, `result` is set to `2` - changed to `3` in the return statement).

The "magic" of the die comes in when traversing the number line over the non-
valid regions, however. While we're traversing the number line, we're also
resizing the valid regions for each result and extending the line for the next
roll. If we go back to the example in the previous paragraphs with the 4-sided
die, we saw that since `r` (our randomly chosen point on the number line),
2.5, was not on [0, 1), the result of our roll was not `1`. To increase the
likelihood of `1` in the next roll, we increase the length of the number line
and the region where `1` is our roll: `this.state` becomes `[2, 1, 1, 1]`, the
valid region for a roll of `1` becomes [0, 2), and the size of the number line
grows to 5 (however, this expansion of the number line does not apply to the
current roll).

At the culmination of our first example above, `this.state` would be `[2, 2,
1, 2]` — we'd increase the size of the valid region for each result except for
`3`, our result from the previous roll. For the next roll, we'd choose a
random point on the number line between 0 and (2 + 2 + 2 + 1 = 7). In terms of
probabilities, another `3` would be half as likely as a `1`, `2`, or `4`,
independently.

------
vacri
On a related note, a colleague once worked at a place where they did this for
on-call: Everyone has an on-call score. Every week, the person on-call had
their score set to zero, and everyone else incremented by one. You could plan
out the next couple of months this way, and it provided an elegant way for new
hires to take their place - they start at zero, and were generally familiar
enough by the time their number came around.

There were some housekeeping rules to work around the organicness of human
life - if someone went on holiday they kept their score, for example - but
overall it seemed to work.

------
biafra
How do I run this code? I thikn I succesfully installed the package with npm.
There were some warnings but no error. But how do I run:

> const RiggedDie = require('gamblers-dice')

> const die = new RiggedDie(20) // for a d20

> console.log(die.roll()) // 1 -> 20

> console.log(die.roll()) // keep using the same instance

Do I put it in a file? Do I copy paste it into a REPL? If so what provides
that REPL?

I am always surprised when sample code providers assume I know their languages
ecosystem.

UPDATE: Apparently I can use "node" as a REPL for this.

------
nerdponx
This "unfair RNG" issue was big in Dota 2 (a popular video game) for a while.
They ultimately implemented something similar and AFAIK now all "random"
effects use it.

~~~
fiatjaf
I googled "RNG" because I wanted to know what it meant, but was presented with
an interactive widget that generated numbers.

~~~
sloppycee
RNG stands for Random Number Generator. It is used colloquially, in gaming, to
refer to the probability of certain random events or the underlying
implementation of them.

~~~
avisser
In its most personified form, the RNG transforms into RN Jesus to whom you
pray for good video game luck.

------
careersuicide
Just wanna say: I _love_ this.

------
Tade0
Kudos for the "I don't get it" section.

------
biesnecker
In 2010 I asked a similar question on StackOverflow for choosing the option
that would have the correct answer in multiple choice tests:
[https://stackoverflow.com/questions/3099153/better-random-
fe...](https://stackoverflow.com/questions/3099153/better-random-feeling-
integer-generator-for-short-sequences)

------
dmartinez
I like to think of this as "human random". It's easier to get along with
people using this type of algorithm.

------
mysterydip
This will be great for game developers as many a player has complained that
the RNG wasn't "fair" because they got so many fails in a row or never saw a
critical hit or whatever, even though it was mathematically correctly random.
Thanks, looking forward to using it!

------
dllthomas
Sure, the Gambler's Fallacy has worked out poorly in the past... but doesn't
that mean it's due?

------
dcookie
This reminds me of the first scene in Rosencrantz & Guildenstern Are Dead.
[https://www.youtube.com/watch?v=RjOqaD5tWB0](https://www.youtube.com/watch?v=RjOqaD5tWB0)

------
gpawl
The NBA Draft Lottery is similar in spirit:

[https://en.wikipedia.org/wiki/NBA_draft_lottery](https://en.wikipedia.org/wiki/NBA_draft_lottery)

------
IncRnd
Bingo cards (the real ones, not the theoretical ones) often have human
interaction as one of the steps in their creation. This is so they appear
random, distinct, without patterns, etc.

------
exabrial
A good application for this would be prevent "Starvation" when doing random
rewards in a video game. For instance, if a special item is to be dropped
after defeating a boss...

------
zem
reminds me of a very interesting demonstration from martin gardner. draw a 6x6
grid, and write a random digit in each cell, proceeding row by row. now count
the number of pairs of consecutive (x, x) going horizontally versus
vertically; you will almost always get doubled numbers in the columns because
that's how random numbers work, but almost never in the rows, because when
people are trying to generate "random" numbers by hand they avoid runs or
other patterns.

------
snake_plissken
Random question I've always had issues resolving: if the Gambler's Fallacy is
real, how can you detect loaded dice?

------
emodendroket
This actually seems like it would be pretty good for applications like games
or playing random songs.

------
ProgrammerMatt
Can someone explain to me why there is such a large discrepancy for the
different sides for math.random()? seems fairly large

~~~
xori
It's actually not that bad. The graph just emphasises the subtle differences.
The worst one (a 10) was rolled 696 times extra over the expected number of
100,000 rolls. That's like 0.3% deviation.

------
sebnap
I think they didn't trust your programming skills as much as the possibility
of absurd sequences :D

~~~
xori
Unfortunately I think you're right.

------
overcast
"A terrible idea is born." :D I can only imagine what will be made on top of
this.

------
mwexler
Finally, Spotify's shuffle algorithm can be fixed! Thank goodness you created
this.

------
andrepd
Eh, I thought this was something more mathematical, like non-transitive dice
([https://en.wikipedia.org/wiki/Nontransitive_dice](https://en.wikipedia.org/wiki/Nontransitive_dice)).
Apparently it's... a weighted random number generator? in node.js?

~~~
xori
Yep it's nothing fancy. But I've yet to have seen it done before.

------
mighty_bander
Pshaw. Make real dice that do that and I'll get excited.

------
Sawamara
This is actually useful for many rpg games.

