Na 2004, 2006 en 2008 was het dan afgelopen weekend tijd voor de vierde editie van de biertest.
De opzet is simpel: een aantal verschillende bieren wordt blind getest op de criteria uiterlijk, smaak, geur en nasmaak, en er wordt en eindoordeel gegeven. Bovendien moeten de deelnemers raden om wel bier het gaat.
Finally, almost 6 months after last working on this, I wrote a paper summarizing my research on the game of thirties. Abstract:
Abstract
In this article, we discuss the game of 30s, a fairly simple game commonly played as a drinking game. We discuss the rules, various goals one may have in the game, and the results of a calculation of the optimal strategies to achieve these goals.
First, the rules of the game are introduced, and some strategies and goals one may have in the game are discussed. Next, a calculation for the so-called second stage of the game is executed, and an implementation for the simulator of the first stage is discussed. Next, we show how to use its output, and analyze some of its results. Finally, we claim that by some formal definition, the game can be called a ‘game of chance’.
All relevant files can be found here:
Note that the earier handout and blog posts contained a (I now think) erroneous calculation of the expected value of the second stage of the game. Happy reading!
Some three years after being spotted on German television at Rock am Ring – and of course, some months since having been on the BBC at a snooker match – , finally I was spotted again, this time on the Fabchannel recording of last years Wir Sind Helden concert in Paradiso:
After the 2004 edition and the 2006 edition, last weekend again it was time for the Great Exciting Beer Test.
Alfa, Amstel, Amstel Malt, Bavaria, Brand, Carlsberg, Chimay Trappist, Dommelsch, Duvel, Export, Grolsch, Heineken, Hertog Jan Grand Prestige, Krusovice, Mongozo, Palm, Schutters, Warsteiner
Let’s first look at the most important result: the best-graded beer. The following table summarizes this:
| Naam | PC | PPL | SD | UI | AR | SM | NS | E | |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Bavaria | 5,0 | 1,6 | 0,6 | 6,8 | 7,2 | 7,4 | 7,3 | 7,3 |
| 2 | Palm | 5,4 | 2,0 | 1,2 | 6,0 | 8,1 | 7,0 | 6,8 | 7,2 |
| 3 | Mongozo | 5,9 | 3,0 | 1,0 | 6,2 | 5,3 | 7,3 | 7,2 | 6,9 |
| 4 | Dommelsch | 5,0 | 1,5 | 0,6 | 6,1 | 6,9 | 6,6 | 6,2 | 6,7 |
| 5 | Grolsch | 5,0 | 0,0 | 0,5 | 6,0 | 6,7 | 6,4 | 6,1 | 6,6 |
| 6 | Duvel | 8,5 | 4,2 | 0,8 | 5,8 | 4,3 | 6,6 | 7,1 | 6,4 |
| 7 | HJ G Prestige | 10,0 | 3,3 | 1,6 | 6,7 | 7,5 | 6,8 | 6,8 | 6,4 |
| 8 | Chimay Trappist | 7,0 | 4,6 | 0,8 | 6,5 | 5,5 | 6,7 | 6,5 | 6,3 |
| 9 | Alfa | 5,0 | 1,3 | 1,3 | 5,7 | 6,2 | 6,1 | 6,0 | 6,3 |
| 10 | Amstel | 5,0 | 1,7 | 0,8 | 6,3 | 7,1 | 6,4 | 6,0 | 6,3 |
| 11 | Export | 5,0 | 0,8 | 1,1 | 5,8 | 6,6 | 6,1 | 6,1 | 6,1 |
| 12 | Brand | 5,0 | 1,8 | 1,4 | 5,3 | 7,4 | 5,5 | 6,0 | 5,9 |
| 13 | Carlsberg | 5,0 | 3,0 | 0,9 | 5,7 | 6,9 | 5,5 | 5,6 | 5,8 |
| 14 | Heineken | 5,0 | 1,8 | 0,5 | 5,5 | 5,2 | 6,1 | 6,0 | 5,7 |
| 15 | Schutters | 5,0 | 1,0 | 0,8 | 5,5 | 6,5 | 5,3 | 5,2 | 5,4 |
| 16 | Krusovice | 5,0 | 3,9 | 1,4 | 5,0 | 7,7 | 5,5 | 5,0 | 5,3 |
| 17 | Amstel Malt | 0,1 | 1,8 | 1,5 | 6,3 | 6,3 | 5,0 | 5,4 | 5,3 |
| 18 | Warsteiner | 4,8 | 3,0 | 0,8 | 4,8 | 4,7 | 5,8 | 5,3 | 5,2 |
More results later; for now, enjoy the raw data and this graph:

For the class in elliptic curves that I am currently following, it came in handy to have a script to find small integer solutions to equations such as Y^2=X(X+1)(X-1). For this, I wrote a small Perl script that generates code to check all small values for all variables in the equation, and then runs the code. For instance, consider
meilof@meilof-laptop:~$ perl solfinder.pl "y*y==x*(x*x+4*x-6)" (y,x)=-18,6 (y,x)=-3,-1 (y,x)=0,0 (y,x)=3,-1 (y,x)=18,6
This works for an arbitrary number of variables (as long as they are single characters), and any boolean expression in Perl syntax. It looks for solutions in which all variables have values with absolute value smaller than 50. Internally, this generates and then runs the following Perl code:
for ($y = -50; $y <= 50; $y++) {
for ($x = -50; $x <= 50; $x++) {
if($y*$y==$x*($x*$x+4*$x-6)) { print "(y,x)=$y,$x\n" }
}
}
Grab the script here.
While playing a bit of the game of 30s Tuesday, I learned that the second stage of the game is actually a bit different from what I previously described. In fact, it works as follows: say one has thrown 32. Then one starts throwing again, putting away 2s while new ones are thrown. But now, the previous score (in this case, 2*6 thrown in the second stage+2) gets doubled, and one starts throwing 3s. This can go on (doubling the score each time) until one gets at 6s; in this case, if 6*6s are thrown, one just continues throwing 6s — presumably, this is already bad enough for the opponent.
Unfortunately, this makes the calculation of the expected value for the second stage game more difficult for two reasons. First, the expected value is no longer linearly dependent on the value of the dice: the lower the score on the dice, the more impact going from one dice value to a higher one is. This is not a real problem since it only increases the number of equations by, say, 6. The real problem is the doubling, which makes the score dependent in a non-linear fashion on the score obtained earlier. I’ll spare you the analysis for now, but here’s the Maxima code I used to define P(x,n), which is the expected value when throwing xs when n points have already been scored. I do this by ignoring terms for very large n. This seems justifyable given that, letting n tend to infinity, the calculated values converge.d(x,n):=if(x=0) then 1 else if n=0 then (5/6)^x else sum((1/6)^i*(5/6)^(x-i)*binomial(x,i)*d(x-i,n-i),i,1,n); d(6,0)+d(6,1)+d(6,2)+d(6,3)+d(6,4)+d(6,5)+d(6,6); a:sum(d(6,i)*6*i,i,0,6); b:d(6,6); P6(x):=if x>10000 then 0 else x+a+b*(36+x+P6(72+2*x)); P(y,x):=if y=6 then P6(x) else x+sum(d(6,i)*y*i,i,0,6)+b*(6*y+x+P(y+1,12*y+2*x));This gives the following results:
| Start dice d | Expected value P(d,d) |
|---|---|
| 1 | 3.212283178756882 |
| 2 | 6.387677375348993 |
| 3 | 9.563071394130493 |
| 4 | 12.73845501067105 |
| 5 | 15.9132297503401 |
| 6 | 19.05236519793943 |
Small update: a reversed version of the source code is available. It now has command-line support, so that recompilation if one wants to use another strategy is no longer necessary. A Linux binary (static, gzipped) is available as well. Also, here is a slightly revised version of the paper, now with some formalization of expected values as well.
Last Thursday, I finished tidiying up the code for the strategy calculator: it can now also compare strategies, and it is pretty easy to add new ones. I will post the code in a while. Also, I started a bit on a mathematical formalization of the problem and the concepts involved. A first effort on a formalization (due to be released on Cleopatra’s “Schierkamp”), can be read here
Earlier, I described the optimal strategy in the game of 30s if one wants to maximize the number of points. I already mentioned then that there may actually be other things one wants to optimize. Also, since the optimal strategy may be a bit hard to remember, I developed a heuristic strategy.
So, I implemented some simple strategies, and calculated the optimal strategies to optimize various aspects. I calculated the following strategies: The various parameters of the different strategies are summarized in the following table:
| Strategy | Expected | Chance >30 | Expected Loss |
|---|---|---|---|
| Maximal | 30,15 | 0,62 | 1,07 |
| Maximize >30 | 29,84 | 0,67 | 1,06 |
| Minimize loss | 29,89 | 0,66 | 1,00 |
| Heuristic | 30,15 | 0,62 | 1,07 |
| Leave >5 | 29,64 | 0,54 | 1,30 |
| Leave >6 | 29,82 | 0,56 | 1,29 |
When interpreting these numbers, one has to keep in mind that the strategies only optimize for the given varible; thus for example, the “over 30s” strategy does not favor a score of 36 over a score of 31. So, if the first five stones are sixes, then the “over 30s” strategy will not discriminate between throwing the last dice or putting it aside. This somewhat troubles the results. Still, it can be noted that for any of the three parameters, there is a somewhat different strategy to reach its optimum.
Next time: a more detailed analysis of the differences between the various strategies. For now, see the source code of the analyser.