Dice game probabilities: Difference between revisions

Add C# implementation
(→‎{{header|J}}: formatting)
(Add C# implementation)
 
(88 intermediate revisions by 35 users not shown)
Line 1:
{{draft task}}
Two players have a set of dice each. The first player has nine dice with four faces each, with numbers one to four. The second player has six normal dice with six faces each, each face has the usual numbers from one to six.
 
Line 8:
This task was adapted from the Project Euler Problem n.205:
https://projecteuler.net/problem=205
 
=={{header|11l}}==
{{trans|C}}
<syntaxhighlight lang="11l">F throw_die(n_sides, n_dice, s, [Int] &counts)
I n_dice == 0
counts[s]++
R
L(i) 1..n_sides
throw_die(n_sides, n_dice - 1, s + i, counts)
 
F beating_probability(n_sides1, n_dice1,
n_sides2, n_dice2)
V len1 = (n_sides1 + 1) * n_dice1
V C1 = [0] * len1
throw_die(n_sides1, n_dice1, 0, &C1)
 
V len2 = (n_sides2 + 1) * n_dice2
V C2 = [0] * len2
throw_die(n_sides2, n_dice2, 0, &C2)
 
Float p12 = (n_sides1 ^ n_dice1) * (n_sides2 ^ n_dice2)
 
V tot = 0.0
L(i) 0 .< len1
L(j) 0 .< min(i, len2)
tot += Float(C1[i]) * C2[j] / p12
R tot
 
print(‘#.16’.format(beating_probability(4, 9, 6, 6)))
print(‘#.16’.format(beating_probability(10, 5, 7, 6)))</syntaxhighlight>
 
{{out}}
<pre>
0.5731440767829814
0.6427886287176272
</pre>
 
 
=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang="action!">INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit
 
BYTE FUNC Roll(BYTE sides,dices)
BYTE i,sum
 
sum=0
FOR i=1 TO dices
DO
sum==+Rand(sides)+1
OD
RETURN (sum)
 
PROC Test(BYTE sides1,dices1,sides2,dices2)
INT i,count=[10000],sum1,sum2,wins1,wins2,draws
REAL r1,r2,p
 
wins1=0 wins2=0 draws=0
FOR i=1 TO count
DO
sum1=Roll(sides1,dices1)
sum2=Roll(sides2,dices2)
IF sum1>sum2 THEN
wins1==+1
ELSEIF sum1<sum2 THEN
wins2==+1
ELSE
draws==+1
FI
OD
 
IntToReal(wins1,r1)
IntToReal(wins2,r2)
RealDiv(r2,r1,p)
 
PrintF("Tested %I times%E",count)
PrintF("Player 1 with %B dice of %B sides%E",dices1,sides1)
PrintF("Player 2 with %B dice of %B sides%E",dices2,sides2)
PrintF("Player 1 wins %I times%E",wins1)
PrintF("Player 2 wins %I times%E",wins2)
PrintF("Draw %I times%E",draws)
Print("Player 1 beating Player 2 probability:")
PrintRE(p)
PutE()
RETURN
 
PROC Main()
Put(125) PutE() ;clear the screen
 
Test(4,9,6,6)
Test(10,5,7,6)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Dice_game_probabilities.png Screenshot from Atari 8-bit computer]
<pre>
Tested 10000 times
Player 1 with 9 dice of 4 sides
Player 2 with 6 dice of 6 sides
Player 1 wins 5770 times
Player 2 wins 3493 times
Draw 737 times
Player 1 beating Player 2 probability:
.6053726169
 
Tested 10000 times
Player 1 with 5 dice of 10 sides
Player 2 with 6 dice of 7 sides
Player 1 wins 6417 times
Player 2 wins 3140 times
Draw 443 times
Player 1 beating Player 2 probability:
.4893252298
</pre>
 
=={{header|Ada}}==
<syntaxhighlight lang="ada">with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;
 
procedure Main is
package real_io is new Float_IO (Long_Float);
use real_io;
 
type Dice is record
Faces : Positive;
Num_Dice : Positive;
end record;
 
procedure Roll_Dice (The_Dice : in Dice; Count : out Natural) is
subtype Faces is Integer range 1 .. The_Dice.Faces;
package Die_Random is new Ada.Numerics.Discrete_Random (Faces);
use Die_Random;
Seed : Generator;
begin
Reset (Seed);
Count := 0;
for I in 1 .. The_Dice.Num_Dice loop
Count := Count + Random (Seed);
end loop;
end Roll_Dice;
 
function Win_Prob
(Dice_1 : Dice; Dice_2 : Dice; Tries : Positive) return Long_Float
is
Count_1 : Natural := 0;
Count_2 : Natural := 0;
Count_1_Wins : Natural := 0;
begin
for I in 1 .. Tries loop
Roll_Dice (Dice_1, Count_1);
Roll_Dice (Dice_2, Count_2);
if Count_1 > Count_2 then
Count_1_Wins := Count_1_Wins + 1;
end if;
end loop;
return Long_Float (Count_1_Wins) / Long_Float (Tries);
end Win_Prob;
 
D1 : Dice := (Faces => 4, Num_Dice => 9);
D2 : Dice := (Faces => 6, Num_Dice => 6);
D3 : Dice := (Faces => 10, Num_Dice => 5);
D4 : Dice := (Faces => 7, Num_Dice => 6);
 
P1 : Long_Float := Win_Prob (D1, D2, 1_000_000);
P2 : Long_Float := Win_Prob (D3, D4, 1_000_000);
begin
Put ("Dice D1 wins = ");
Put (Item => P1, Fore => 1, Aft => 7, Exp => 0);
New_Line;
Put ("Dice D2 wins = ");
Put (Item => P2, Fore => 1, Aft => 7, Exp => 0);
New_Line;
end Main;
</syntaxhighlight>
{{output}}
<pre>
Dice D1 wins = 0.5727800
Dice D2 wins = 0.6427660
</pre>
 
=={{header|BASIC}}==
==={{header|BASIC256}}===
{{trans|Yabasic}}
<syntaxhighlight lang="basic256">dado1 = 9: lado1 = 4
dado2 = 6: lado2 = 6
total1 = 0: total2 = 0
 
for i = 0 to 1
for cont = 1 to 100000
jugador1 = lanzamiento(dado1, lado1)
jugador2 = lanzamiento(dado2, lado2)
if jugador1 > jugador2 then
total1 = total1 + 1
else
if jugador1 <> jugador2 then total2 = total2 + 1
endif
next cont
 
print "Lanzado el dado "; (cont - 1); " veces"
print "jugador1 con "; dado1; " dados de "; lado1; " lados"
print "jugador2 con "; dado2; " dados de "; lado2; " lados"
print "Total victorias jugador1 = "; total1; " => "; left(string(total2 / total1), 9)
print "Total victorias jugador2 = "; total2
print (cont - 1) - (total1 + total2); " empates" + chr(10)
 
dado1 = 5: lado1 = 10
dado2 = 6: lado2 = 7
total1 = 0: total2 = 0
next i
end
 
function lanzamiento(dado, lado)
total = 0
 
for lanza = 1 to dado
total = total + int(rand * lado) + 1
next lanza
return total
end function</syntaxhighlight>
{{out}}
<pre>
Igual que la entrada de Yabasic.
</pre>
 
==={{header|FreeBASIC}}===
{{trans|Gambas}}
<syntaxhighlight lang="freebasic">Dim As Integer lado, jugador1, jugador2, total1, total2, cont, i
Dim As Integer dado1 = 9, lado1 = 4
Dim As Integer dado2 = 6, lado2 = 6
 
Randomize Timer
 
Function Lanzamiento(dado As Integer, lado As Integer) As Integer
Dim As Short lanza, total
For lanza = 1 To dado
total += Int(Rnd * lado) + 1
Next lanza
Return total
End Function
 
For i = 0 To 1
For cont = 1 To 100000
jugador1 = Lanzamiento(dado1, lado1)
jugador2 = Lanzamiento(dado2, lado2)
If jugador1 > jugador2 Then
total1 += 1
Elseif jugador1 <> jugador2 Then
total2 += 1
End If
Next cont
Print Using "Lanzado el dado & veces"; (cont - 1)
Print "jugador1 con"; dado1; " dados de"; lado1; " lados"
Print "jugador2 con"; dado2; " dados de"; lado2; " lados"
Print Using "Total victorias jugador1 = & => #.#######"; total1; (total2 / total1)
Print "Total victorias jugador2 ="; total2
Print (cont - 1) - (total1 + total2); !" empates\n"
dado1 = 5: lado1 = 10
dado2 = 6: lado2 = 7
total1 = 0: total2 = 0
Next i
 
Sleep</syntaxhighlight>
{{out}}
<pre>
Lanzado el dado 100000 veces
jugador1 con 9 dados de 4 lados
jugador2 con 6 dados de 6 lados
Total victorias jugador1 = 57274 => 0.6237211
Total victorias jugador2 = 35723
7003 empates
 
Lanzado el dado 100000 veces
jugador1 con 5 dados de 10 lados
jugador2 con 6 dados de 7 lados
Total victorias jugador1 = 64093 => 0.4893826
Total victorias jugador2 = 31366
4541 empates
</pre>
 
==={{header|Yabasic}}===
{{trans|FreeBASIC}}
<syntaxhighlight lang="yabasic">dado1 = 9: lado1 = 4
dado2 = 6: lado2 = 6
total1 = 0: total2 = 0
 
for i = 0 to 1
for cont = 1 to 100000
jugador1 = lanzamiento(dado1, lado1)
jugador2 = lanzamiento(dado2, lado2)
if jugador1 > jugador2 then
total1 = total1 + 1
elseif jugador1 <> jugador2 then
total2 = total2 + 1
endif
next cont
print "Lanzado el dado ", (cont - 1), " veces"
print "jugador1 con ", dado1, " dados de ", lado1, " lados"
print "jugador2 con ", dado2, " dados de ", lado2, " lados"
print "Total victorias jugador1 = ", total1, " => ", (total2 / total1)
print "Total victorias jugador2 = ", total2
print (cont - 1) - (total1 + total2), " empates\n"
dado1 = 5: lado1 = 10
dado2 = 6: lado2 = 7
total1 = 0: total2 = 0
next i
 
sub lanzamiento(dado, lado)
local lanza, total
for lanza = 1 to dado
total = total + int(ran(lado)) + 1
next lanza
return total
end sub</syntaxhighlight>
{{out}}
<pre>
Igual que la entrada de FreeBASIC.
</pre>
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdint.h>
 
Line 64 ⟶ 385:
printf("%1.16f\n", beating_probability(10, 5, 7, 6));
return 0;
}</langsyntaxhighlight>
{{out}}
<pre>0.5731440767829801
0.6427886287176260</pre>
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
 
class Program
{
static uint MinOf(uint x, uint y)
{
return x < y ? x : y;
}
 
static void ThrowDie(uint nSides, uint nDice, uint s, uint[] counts)
{
if (nDice == 0)
{
counts[s]++;
return;
}
for (uint i = 1; i <= nSides; i++)
{
ThrowDie(nSides, nDice - 1, s + i, counts);
}
}
 
static double BeatingProbability(uint nSides1, uint nDice1, uint nSides2, uint nDice2)
{
uint len1 = (nSides1 + 1) * nDice1;
uint[] c1 = new uint[len1]; // initialized to zero by default
ThrowDie(nSides1, nDice1, 0, c1);
 
uint len2 = (nSides2 + 1) * nDice2;
uint[] c2 = new uint[len2];
ThrowDie(nSides2, nDice2, 0, c2);
double p12 = Math.Pow(nSides1, nDice1) * Math.Pow(nSides2, nDice2);
 
double tot = 0.0;
for (uint i = 0; i < len1; i++)
{
for (uint j = 0; j < MinOf(i, len2); j++)
{
tot += (double)(c1[i] * c2[j]) / p12;
}
}
return tot;
}
 
static void Main(string[] args)
{
Console.WriteLine(BeatingProbability(4, 9, 6, 6));
Console.WriteLine(BeatingProbability(10, 5, 7, 6));
}
}
</syntaxhighlight>
{{out}}
<pre>
0.573144076782982
0.642788628717627
 
</pre>
 
=={{header|C++}}==
<syntaxhighlight lang="cpp">#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <map>
 
// Returns map from sum of faces to number of ways it can happen
std::map<uint32_t, uint32_t> get_totals(uint32_t dice, uint32_t faces) {
std::map<uint32_t, uint32_t> result;
for (uint32_t i = 1; i <= faces; ++i)
result.emplace(i, 1);
for (uint32_t d = 2; d <= dice; ++d) {
std::map<uint32_t, uint32_t> tmp;
for (const auto& p : result) {
for (uint32_t i = 1; i <= faces; ++i)
tmp[p.first + i] += p.second;
}
tmp.swap(result);
}
return result;
}
 
double probability(uint32_t dice1, uint32_t faces1, uint32_t dice2, uint32_t faces2) {
auto totals1 = get_totals(dice1, faces1);
auto totals2 = get_totals(dice2, faces2);
double wins = 0;
for (const auto& p1 : totals1) {
for (const auto& p2 : totals2) {
if (p2.first >= p1.first)
break;
wins += p1.second * p2.second;
}
}
double total = std::pow(faces1, dice1) * std::pow(faces2, dice2);
return wins/total;
}
 
int main() {
std::cout << std::setprecision(10);
std::cout << probability(9, 4, 6, 6) << '\n';
std::cout << probability(5, 10, 6, 7) << '\n';
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
0.5731440768
0.6427886287
</pre>
 
=={{header|Common Lisp}}==
''DRAFT''
 
====1. Note====
 
We use total probability rule.
 
====2. Program====
 
Player i gets s<sub>i</sub> points as the sum of rolling n<sub>i</sub> dices, each with f<sub>i</sub> faces.
 
<syntaxhighlight lang=lisp>(defun n-ways (n f s &optional (mem (make-array '(999 99) :initial-element -1)))
(cond ((and (= n 0) (= s 0)) 1)
((or (= n 0) (<= s 0)) 0)
((>= (aref mem s n) 0) (aref mem s n))
(t (loop for i from 1 to f
sum (n-ways (1- n) f (- s i) mem) into total
finally (return (setf (aref mem s n) total))))))
 
(defun winning-probability (n1 f1 n2 f2 &aux (w 0))
(loop for i from n1 to (* n1 f1)
do (loop for j from n2 to (* n2 f2)
do (if (> i j)
(setf w (+ w (* (n-ways n1 f1 i) (n-ways n2 f2 j))))))
finally (return (/ w (* (expt f1 n1) (expt f2 n2))))))</syntaxhighlight>
 
==== 3. Execution ====
 
<pre>(winning-probability 9 4 6 6)
(winning-probability 5 10 6 7)</pre>
 
{{out}}
<pre>48679795/84934656 ; ≈ 0.573
3781171969/5882450000 ; ≈ 0.643</pre>
 
That's all Folks !
 
''cyril nocton (cyril.nocton@gmail.com) w/ google translate''
 
=={{header|D}}==
===version 1===
<langsyntaxhighlight lang="d">import std.stdio, std.range, std.algorithm;
 
void throwDie(in uint nSides, in uint nDice, in uint s, uint[] counts)
Line 105 ⟶ 577:
writefln("%1.16f", beatingProbability!(4, 9, 6, 6));
writefln("%1.16f", beatingProbability!(10, 5, 7, 6));
}</langsyntaxhighlight>
{{out}}
<pre>0.5731440767829801
Line 112 ⟶ 584:
===version 2 (Faster Alternative Version)===
{{trans|Python}}
<langsyntaxhighlight lang="d">import std.stdio, std.range, std.algorithm;
 
ulong[] combos(R)(R sides, in uint n) pure nothrow @safe
Line 150 ⟶ 622:
writefln("%1.16f", winning(iota(1u, 5u), 9, iota(1u, 7u), 6));
writefln("%1.16f", winning(iota(1u, 11u), 5, iota(1u, 8u), 6));
}</langsyntaxhighlight>
{{out}}
<pre>0.5731440767829801
0.6427886287176262</pre>
 
=={{header|EasyLang}}==
{{trans|Phix}}
<syntaxhighlight>
proc throw_die n_sides n_dice s . counts[] .
if n_dice = 0
counts[s] += 1
return
.
for i = 1 to n_sides
throw_die n_sides (n_dice - 1) (s + i) counts[]
.
.
func proba n_sides1 n_dice1 n_sides2 n_dice2 .
len c1[] (n_sides1 + 1) * n_dice1
len c2[] (n_sides2 + 1) * n_dice2
throw_die n_sides1 n_dice1 0 c1[]
throw_die n_sides2 n_dice2 0 c2[]
p12 = pow n_sides1 n_dice1 * pow n_sides2 n_dice2
for i = 1 to len c1[]
for j = 1 to lower (i - 1) len c2[]
tot += c1[i] * c2[j] / p12
.
.
return tot
.
numfmt 5 0
print proba 4 9 6 6
print proba 10 5 7 6
</syntaxhighlight>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: dice generalizations kernel math prettyprint sequences ;
IN: rosetta-code.dice-probabilities
 
: winning-prob ( a b c d -- p )
[ [ random-roll ] 2bi@ > ] 4 ncurry [ 100000 ] dip replicate
[ [ t = ] count ] [ length ] bi /f ;
 
9 4 6 6 winning-prob
5 10 6 7 winning-prob [ . ] bi@</syntaxhighlight>
{{out}}
<pre>
0.57199
0.64174
</pre>
 
=={{header|Forth}}==
{{works with|gforth|0.7.3}}
<br>
<syntaxhighlight lang="forth">#! /usr/bin/gforth
 
\ Dice game probabilities
 
: min? ( addr -- min )
@
;
 
: max? ( addr -- max )
cell + @
;
 
: max+1-min? ( addr -- max+1 min )
dup max? 1+ swap min?
;
 
: addr? ( addr x -- addr' )
over min? - 2 + cells +
;
 
: weight? ( addr x -- w )
2dup swap min? < IF
2drop 0
ELSE
2dup swap max? > IF
2drop 0
ELSE
addr? @
THEN
THEN
;
 
: total-weight? ( addr -- w )
dup max? 1+ ( addr max+1 )
over min? ( addr max+1 min )
0 -rot ?DO ( adrr 0 max+1 min )
over i weight? +
LOOP
nip
;
 
: uniform-aux ( min max x -- addr )
>r 2dup
2dup swap - 3 + cells allocate throw ( min max min max addr )
tuck cell + ! ( min max min addr )
tuck ! ( min max addr )
-rot swap ( addr max min )
r> -rot ( addr x max min )
- 3 + 2 ?DO ( addr x )
2dup swap i cells + !
LOOP
drop
;
 
: convolve { addr1 addr2 -- addr }
addr1 min? addr2 min? +
addr1 max? addr2 max? +
0 uniform-aux { addr }
addr1 max+1-min? ?DO
addr2 max+1-min? ?DO
addr1 j weight?
addr2 i weight? *
addr i j + addr? +!
LOOP
LOOP
addr
;
 
: even? ( n -- f )
2 mod 0=
;
 
: power ( addr exp -- addr' )
dup 1 = IF
drop
ELSE
dup even? IF
2/ recurse dup convolve
ELSE
over swap 2/ recurse dup convolve convolve
THEN
THEN
;
 
: .dist { addr -- }
addr total-weight? { tw }
addr max+1-min? ?DO
i 10 .r
addr i weight? dup 20 .r
0 d>f tw 0 d>f f/ ." " f. cr
LOOP
;
 
: dist-cmp { addr1 addr2 xt -- p }
0
addr1 max+1-min? ?DO
addr2 max+1-min? ?DO
j i xt execute IF
addr1 j weight?
addr2 i weight?
* +
THEN
LOOP
LOOP
0 d>f
addr1 total-weight? addr2 total-weight? um* d>f
f/
;
 
: dist> ( addr1 addr2 -- p )
['] > dist-cmp
;
 
\ creates the uniform distribution with outcomes from min to max
: uniform ( min max -- addr )
1 uniform-aux
;
 
\ example
 
1 4 uniform 9 power
1 6 uniform 6 power
dist> f. cr
 
1 10 uniform 5 power
1 7 uniform 6 power
dist> f. cr
 
bye
</syntaxhighlight>
 
{{out}}
<pre>
time ./dice-game-probabilities.fs
0.57314407678298
0.642788628717626
 
real 0m0,008s
user 0m0,005s
sys 0m0,003s
</pre>
 
 
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
local fn RollTheDice( dice as long, sides as long ) as long
long i, total = 0
for i = 1 to dice
total += rnd(sides)
next
end fn = total
 
 
void local fn CaclulateProbabilities( dice1 as long, sides1 as long, dice2 as long, sides2 as long )
long i, player1, player2
float total1 = 0, total2 = 0, total3 = 0
for i = 1 to 100000
player1 = fn RollTheDice( dice1, sides1 )
player2 = fn RollTheDice( dice2, sides2 )
if ( player1 > player2 ) then total1++ : continue
if ( player1 < player2 ) then total2++ : continue
if ( player1 == player2 ) then total3++ : continue
next
printf @"Dice cast %ld times.", i - 1
printf @"Player 1 with %ld dice of %ld sides.", dice1, sides1
printf @"Player 2 with %ld dice of %ld sides.", dice2, sides2
printf @"Total wins Player 1 = %.f. Probability of winning: %0.4f%%.", total1, (total1 / i ) * 100
printf @"Total wins Player 2 = %.f", total2
printf @"Number of ties: %.f.", total3
end fn
 
randomize
print
fn CaclulateProbabilities( 9, 4, 6, 6 )
print
fn CaclulateProbabilities( 5, 10, 6, 7 )
print
 
HandleEvents
</syntaxhighlight>
{{output}}
<pre>
Dice cast 100000 times.
Player 1 with 9 dice of 4 sides.
Player 2 with 6 dice of 6 sides.
Total wins Player 1 = 57301. Probability of winning: 57.3004%.
Total wins Player 2 = 35733
Number of ties: 6966.
 
Dice cast 100000 times.
Player 1 with 5 dice of 10 sides.
Player 2 with 6 dice of 7 sides.
Total wins Player 1 = 64289. Probability of winning: 64.2884%.
Total wins Player 2 = 31296
Number of ties: 4415.
</pre>
 
 
 
=={{header|Gambas}}==
'''[https://gambas-playground.proko.eu/?gist=ef255e4239a713aba35598a4617af3c9 Click this link to run this code]'''
<syntaxhighlight lang="gambas">' Gambas module file
 
Public Sub Main()
Dim iSides, iPlayer1, iPlayer2, iTotal1, iTotal2, iCount, iCount0 As Integer
Dim iDice1 As Integer = 9
Dim iDice2 As Integer = 6
Dim iSides1 As Integer = 4
Dim iSides2 As Integer = 6
 
Randomize
 
For iCount0 = 0 To 1
For iCount = 1 To 100000
iPlayer1 = Roll(iDice1, iSides1)
iPlayer2 = Roll(iDice2, iSides2)
If iPlayer1 > iPlayer2 Then
iTotal1 += 1
Else If iPlayer1 <> iPlayer2 Then
iTotal2 += 1
Endif
Next
 
Print "Tested " & Str(iCount - 1) & " times"
Print "Player1 with " & Str(iDice1) & " dice of " & Str(iSides1) & " sides"
Print "Player2 with " & Str(iDice2) & " dice of " & Str(iSides2) & " sides"
Print "Total wins Player1 = " & Str(iTotal1) & " - " & Str(iTotal2 / iTotal1)
Print "Total wins Player2 = " & Str(iTotal2)
Print Str((iCount - 1) - (iTotal1 + iTotal2)) & " draws" & gb.NewLine
 
iDice1 = 5
iDice2 = 6
iSides1 = 10
iSides2 = 7
iTotal1 = 0
iTotal2 = 0
Next
 
End
 
Public Sub Roll(iDice As Integer, iSides As Integer) As Integer
Dim iCount, iTotal As Short
 
For iCount = 1 To iDice
iTotal += Rand(1, iSides)
Next
 
Return iTotal
 
End</syntaxhighlight>
Output:
<pre>
Tested 100000 times
Player1 with 9 dice of 4 sides
Player2 with 6 dice of 6 sides
Total wins Player1 = 56980 - 0.62823797823798
Total wins Player2 = 35797
7223 draws
 
Tested 100000 times
Player1 with 5 dice of 10 sides
Player2 with 6 dice of 7 sides
Total wins Player1 = 64276 - 0.48548447320928
Total wins Player2 = 31205
4519 draws
</pre>
 
=={{header|Go}}==
{{trans|C}}
<syntaxhighlight lang="go">package main
 
import(
"math"
"fmt"
)
 
func minOf(x, y uint) uint {
if x < y {
return x
}
return y
}
 
func throwDie(nSides, nDice, s uint, counts []uint) {
if nDice == 0 {
counts[s]++
return
}
for i := uint(1); i <= nSides; i++ {
throwDie(nSides, nDice - 1, s + i, counts)
}
}
 
func beatingProbability(nSides1, nDice1, nSides2, nDice2 uint) float64 {
len1 := (nSides1 + 1) * nDice1
c1 := make([]uint, len1) // all elements zero by default
throwDie(nSides1, nDice1, 0, c1)
 
len2 := (nSides2 + 1) * nDice2
c2 := make([]uint, len2)
throwDie(nSides2, nDice2, 0, c2)
p12 := math.Pow(float64(nSides1), float64(nDice1)) *
math.Pow(float64(nSides2), float64(nDice2))
 
tot := 0.0
for i := uint(0); i < len1; i++ {
for j := uint(0); j < minOf(i, len2); j++ {
tot += float64(c1[i] * c2[j]) / p12
}
}
return tot
}
 
func main() {
fmt.Println(beatingProbability(4, 9, 6, 6))
fmt.Println(beatingProbability(10, 5, 7, 6))
}</syntaxhighlight>
 
{{out}}
<pre>
0.5731440767829815
0.6427886287176273
</pre>
 
More idiomatic go:
 
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"math/rand"
)
 
type set struct {
n, s int
}
 
func (s set) roll() (sum int) {
for i := 0; i < s.n; i++ {
sum += rand.Intn(s.s) + 1
}
return
}
 
func (s set) beats(o set, n int) (p float64) {
for i := 0; i < n; i++ {
if s.roll() > o.roll() {
p = p + 1.0
}
}
p = p / float64(n)
return
}
 
func main() {
fmt.Println(set{9, 4}.beats(set{6, 6}, 1000))
fmt.Println(set{5, 10}.beats(set{6, 7}, 1000))
}</syntaxhighlight>
 
{{out}}
<pre>
0.576
0.639
</pre>
=={{header|Haskell}}==
{{trans|Python}}
<syntaxhighlight lang="haskell">import Control.Monad (replicateM)
import Data.List (group, sort)
 
succeeds :: (Int, Int) -> (Int, Int) -> Double
succeeds p1 p2 =
sum
[ realToFrac (c1 * c2) / totalOutcomes
| (s1, c1) <- countSums p1
, (s2, c2) <- countSums p2
, s1 > s2 ]
where
totalOutcomes = realToFrac $ uncurry (^) p1 * uncurry (^) p2
countSums (nFaces, nDice) = f [1 .. nFaces]
where
f =
fmap (((,) . head) <*> (pred . length)) .
group . sort . fmap sum . replicateM nDice
 
main :: IO ()
main = do
print $ (4, 9) `succeeds` (6, 6)
print $ (10, 5) `succeeds` (7, 6)</syntaxhighlight>
{{out}}
<pre>0.5731440767829815
0.6427886287176273</pre>
 
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight Jlang="j">gen_dict =: (({. , #)/.~@:,@:(+/&>)@:{@:(# <@:>:@:i.)~ ; ^)&x:
 
beating_probability =: dyad define
Line 163 ⟶ 1,080:
'C1 P1' =. gen_dict/ y
(C0 +/@:,@:(>/&:({."1) * */&:({:"1)) C1) % (P0 * P1)
)</langsyntaxhighlight>
'''Example Usage:'''
<langsyntaxhighlight Jlang="j"> 10 5 (;x:inv)@:beating_probability 7 6
┌─────────────────────┬────────┐
│3781171969r5882450000│0.642789│
Line 172 ⟶ 1,089:
┌─────────────────┬────────┐
│48679795r84934656│0.573144│
└─────────────────┴────────┘</langsyntaxhighlight>
gen_dict explanation:<br>
<code>gen_dict</code> is akin to <code>gen_dict</code> in the python solution and
Line 196 ⟶ 1,113:
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.util.Random;
 
public class Dice{
Line 253 ⟶ 1,170:
System.out.println("p1 wins " + (100.0 * p1Wins / rolls) + "% of the time");
}
}</langsyntaxhighlight>
{{out}}
<pre>10000 rolls, p1 = 9d4, p2 = 6d6
Line 266 ⟶ 1,183:
1000000 rolls, p1 = 5d10, p2 = 6d7
p1 wins 64.279% of the time</pre>
 
=={{header|JavaScript}}==
===simulating===
<syntaxhighlight lang="javascript">
let Player = function(dice, faces) {
this.dice = dice;
this.faces = faces;
this.roll = function() {
let results = [];
for (let x = 0; x < dice; x++)
results.push(Math.floor(Math.random() * faces +1));
return eval(results.join('+'));
}
}
 
function contest(player1, player2, rounds) {
let res = [0, 0, 0];
for (let x = 1; x <= rounds; x++) {
let a = player1.roll(),
b = player2.roll();
switch (true) {
case (a > b): res[0]++; break;
case (a < b): res[1]++; break;
case (a == b): res[2]++; break;
}
}
document.write(`
<p>
<b>Player 1</b> (${player1.dice} × d${player1.faces}): ${res[0]} wins<br>
<b>Player 2</b> (${player2.dice} × d${player2.faces}): ${res[1]} wins<br>
<b>Draws:</b> ${res[2]}<br>
Chances for Player 1 to win:
~${Math.round(res[0] / eval(res.join('+')) * 100)} %
</p>
`);
}
 
let p1, p2;
 
p1 = new Player(9, 4),
p2 = new Player(6, 6);
contest(p1, p2, 1e6);
 
p1 = new Player(5, 10);
p2 = new Player(6, 7);
contest(p1, p2, 1e6);
</syntaxhighlight>
{{out}}
<pre>
Player 1 (9 × d4): 572753 wins
Player 2 (6 × d6): 356478 wins
Draws: 70769
Chances for Player 1 to win: ~57 %
 
Player 1 (5 × d10): 643127 wins
Player 2 (6 × d7): 312151 wins
Draws: 44722
Chances for Player 1 to win: ~64 %
</pre>
 
=={{header|jq}}==
{{trans|Wren}}
{{works with|jq}}
'''Works with gojq, the Go implementation of jq'''
<syntaxhighlight lang="jq"># To take advantage of gojq's arbitrary-precision integer arithmetic:
def power($b): . as $in | reduce range(0;$b) as $i (1; . * $in);
 
# Input: an array (aka: counts)
def throwDie($nSides; $nDice; $s):
if $nDice == 0
then .[$s] += 1
else reduce range(1; $nSides + 1) as $i (.;
throwDie($nSides; $nDice-1; $s + $i) )
end ;
 
def beatingProbability(nSides1; nDice1; nSides2; nDice2):
def a: [range(0; .) | 0];
 
((nSides1 + 1) * nDice1) as $len1
| ($len1 | a | throwDie(nSides1; nDice1; 0)) as $c1
 
| ((nSides2 + 1) * nDice2) as $len2
| ($len2 | a | throwDie(nSides2; nDice2; 0)) as $c2
 
|((nSides1|power(nDice1)) * (nSides2|power(nDice2))) as $p12
 
| reduce range(0; $len1) as $i (0;
reduce range(0; [$i, $len2] | min) as $j (.;
. + ($c1[$i] * $c2[$j] / $p12) ) ) ;
 
beatingProbability(4; 9; 6; 6),
beatingProbability(10; 5; 7; 6)</syntaxhighlight>
{{out}}
<pre>
0.5731440767829815
0.6427886287176273
</pre>
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<syntaxhighlight lang="julia">play(ndices::Integer, nfaces::Integer) = (nfaces, ndices) ∋ 0 ? 0 : sum(rand(1:nfaces) for i in 1:ndices)
 
simulate(d1::Integer, f1::Integer, d2::Integer, f2::Integer; nrep::Integer=1_000_000) =
mean(play(d1, f1) > play(d2, f2) for _ in 1:nrep)
 
println("\nPlayer 1: 9 dices, 4 faces\nPlayer 2: 6 dices, 6 faces\nP(Player1 wins) = ", simulate(9, 4, 6, 6))
println("\nPlayer 1: 5 dices, 10 faces\nPlayer 2: 6 dices, 7 faces\nP(Player1 wins) = ", simulate(5, 10, 6, 7))</syntaxhighlight>
 
{{out}}
<pre>Player 1: 9 dices, 4 faces
Player 2: 6 dices, 6 faces
P(Player1 wins) = 0.572805
 
Player 1: 5 dices, 10 faces
Player 2: 6 dices, 7 faces
P(Player1 wins) = 0.642727</pre>
 
=={{header|Kotlin}}==
{{trans|C}}
<langsyntaxhighlight lang="scala">// version 1.1.2
 
fun throwDie(nSides: Int, nDice: Int, s: Int, counts: IntArray) {
Line 292 ⟶ 1,326:
 
var tot = 0.0
for (i in 0 until len1) {
for (j in 0 until minOf(i, len2)) {
tot += c1[i] * c2[j] / p12
}
}
return tot
}
Line 301 ⟶ 1,337:
println(beatingProbability(4, 9, 6, 6))
println(beatingProbability(10, 5, 7, 6))
}</langsyntaxhighlight>
 
{{out}}
Line 308 ⟶ 1,344:
0.6427886287176273
</pre>
 
=={{header|Lua}}==
===Simulated===
<syntaxhighlight lang="lua">
local function simu(ndice1, nsides1, ndice2, nsides2)
local function roll(ndice, nsides)
local result = 0;
for i = 1, ndice do
result = result + math.random(nsides)
end
return result
end
local wins, coms = 0, 1000000
for i = 1, coms do
local roll1 = roll(ndice1, nsides1)
local roll2 = roll(ndice2, nsides2)
if (roll1 > roll2) then
wins = wins + 1
end
end
print("simulated: p1 = "..ndice1.."d"..nsides1..", p2 = "..ndice2.."d"..nsides2..", prob = "..wins.." / "..coms.." = "..(wins/coms))
end
 
simu(9, 4, 6, 6)
simu(5, 10, 6, 7)
</syntaxhighlight>
{{out}}
<pre>
simulated: p1 = 9d4, p2 = 6d6, prob = 573372 / 1000000 = 0.573372
simulated: p1 = 5d10, p2 = 6d7, prob = 642339 / 1000000 = 0.642339
</pre>
 
===Computed===
<syntaxhighlight lang="lua">
local function comp(ndice1, nsides1, ndice2, nsides2)
local function throws(ndice, nsides)
local sums = {}
for i = 1, ndice*nsides do
sums[i] = 0
end
local function throw(ndice, nsides, s)
if (ndice==0) then
sums[s] = sums[s] + 1
else
for i = 1, nsides do
throw(ndice-1, nsides, s+i)
end
end
return sums
end
return throw(ndice, nsides, 0)
end
local p1 = throws(ndice1, nsides1)
local p2 = throws(ndice2, nsides2)
local wins, coms = 0, nsides1^ndice1 * nsides2^ndice2
for k1,v1 in pairs(p1) do
for k2,v2 in pairs(p2) do
if (k1 > k2) then
wins = wins + v1 * v2
end
end
end
print("computed: p1 = "..ndice1.."d"..nsides1..", p2 = "..ndice2.."d"..nsides2..", prob = "..wins.." / "..coms.." = "..(wins/coms))
end
 
comp(9, 4, 6, 6)
comp(5, 10, 6, 7)
</syntaxhighlight>
{{out}}
<pre>
computed: p1 = 9d4, p2 = 6d6, prob = 7009890480 / 12230590464 = 0.57314407678298
computed: p1 = 5d10, p2 = 6d7, prob = 7562343938 / 11764900000 = 0.64278862871763
</pre>
 
=={{header|M2000 Interpreter}}==
Using a buffer of random numbers for all games.
 
 
<syntaxhighlight lang="m2000 interpreter">
Declare random1 lib "advapi32.SystemFunction036" {long lpbuffer, long length}
Flush
Prob(4, 9, 6, 6, 55555)
Prob(10, 5, 7, 6, 55555)
Sub Prob(face1 as long=4 ,dice1=9, face2 as long=6,dice2=6, games=1000)
if face1<1 or face1>256 or face2<1 or face2>256 then Error "Faces out of limits"
profiler
local m=@PlayAll(dice1,dice2, games), tt=timecount
print "Time to fill the buffer with random bytes ";str$(tt, "#0.00 ms")
local s1=dice1-1, s2=dice2-1, k, l, f1=face1/256, f2=face2/256, i, n1=0&, n2=0&
print "Buffer size ";str$(len(m)/1024,"#0.#");" Kbyte": Refresh
profiler
for i=0 to games-1
long n1=dice1:for j=0to s1{n1+=eval(m, i!n1!j)*f1}
long n2=dice2:for j=0to s2{n2+=eval(m, i!n2!j)*f2}
if n1>n2 then k++ else if n1<n2 then l++
next
print "Games Total "; games
print "Player 1 wins ";k; " probability of winning:" ;str$(k/games, "#0.00 %")
print "Player 2 wins ";l; " probability of winning:" ;str$(l/games, "#0.00 %")
print "Number of ties ";games-k-l
print "Execution time ";str$(timecount/1000, "#0.0 s")
End Sub
Function PlayAll(dice1, dice2, games as long)
if games<1 then error "games<1"
local onegame
structure onegame {
n1 as byte * dice1
n2 as byte * dice2
}
buffer Alfa as onegame*games
call void random1(alfa(0), len(alfa))
= Alfa
End Function
</syntaxhighlight>
{{out}}
<pre>
Time to fill the buffer with random bytes 2.00 ms
Buffer size 813.8 Kbyte
Games Total 55555
Player 1 wins 31870 probability of winning:57.37 %
Player 2 wins 19729 probability of winning:35.51 %
Number of ties 3956
Execution time 179.9 s
 
Time to fill the buffer with random bytes 1.65 ms
Buffer size 596.8 Kbyte
Games Total 55555
Player 1 wins 35441 probability of winning:63.79 %
Player 2 wins 17605 probability of winning:31.69
Number of ties 2509
Execution time 138.7 s
</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">ClearAll[GetProbability]
GetProbability[{dice1_List, n_Integer}, {dice2_List, m_Integer}] :=
Module[{a, b, lena, lenb},
a = Tuples[dice1, n];
a = Plus @@@ a;
lena = a // Length;
a = Tally[a];
a[[All, 2]] /= lena;
b = Tuples[dice2, m];
b = Plus @@@ b;
lenb = b // Length;
b = Tally[b];
b[[All, 2]] /= lenb;
Total[If[#[[1, 1]] > #[[2, 1]], #[[1, 2]] #[[2, 2]], 0] & /@
Tuples[{a, b}]]
]
GetProbability[{Range[4], 9}, {Range[6], 6}]
GetProbability[{Range[10], 5}, {Range[7], 6}]</syntaxhighlight>
{{out}}
<pre>48679795/84934656
3781171969/5882450000</pre>
 
=={{header|Nim}}==
{{libheader|bignum}}
<syntaxhighlight lang="nim">import bignum
from math import sum
 
proc counts(ndices, nsides: int): seq[int] =
result.setlen(ndices * nsides + 1)
for i in 1..nsides:
result[i] = 1
for i in 1..<ndices:
var c = newSeq[int](result.len)
for sum in i..(i * nsides):
for val in 1..nsides:
inc c[sum + val], result[sum]
result = move(c)
 
proc probabilities(counts: seq[int]): seq[Rat] =
result.setLen(counts.len)
let total = sum(counts)
for i, n in counts:
result[i] = newRat(n, total)
 
proc beatingProbability(ndices1, nsides1, ndices2, nsides2: int): Rat =
let counts1 = counts(ndices1, nsides1)
let counts2 = counts(ndices2, nsides2)
var p1 = counts1.probabilities()
var p2 = counts2.probabilities()
 
result = newRat(0)
for sum1 in ndices1..p1.high:
var p = newRat(0)
for sum2 in ndices2..min(sum1 - 1, p2.high):
p += p2[sum2]
result += p1[sum1] * p
 
echo beatingProbability(9, 4, 6, 6).toFloat
echo beatingProbability(5, 10, 6, 7).toFloat</syntaxhighlight>
 
{{out}}
<pre>0.5731440767829801
0.6427886287176261</pre>
 
=={{header|ooRexx}}==
===Algorithm===
<langsyntaxhighlight lang="oorexx">Numeric Digits 30
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 367 ⟶ 1,602:
psum+=p1.x
End
Return</langsyntaxhighlight>
{{out}}
<pre>Player 1 has 9 dice with 4 sides each
Line 378 ⟶ 1,613:
 
===Algorithm using rational arithmetic===
<langsyntaxhighlight lang="oorexx">Numeric Digits 30
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 480 ⟶ 1,715:
Parse Arg a,b
if b = 0 then return abs(a)
return ggt(b,a//b)</langsyntaxhighlight>
{{out}}
<pre>Player 1 has 9 dice with 4 sides each
Line 494 ⟶ 1,729:
===Algorithm using class fraction===
Class definition adapted from Arithmetic/Raional.
<langsyntaxhighlight lang="oorexx">Numeric Digits 50
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 652 ⟶ 1,887:
::attribute denominator GET
 
::requires rxmath library</langsyntaxhighlight>
{{out}}
<pre>Player 1 has 9 dice with 4 sides each
Line 666 ⟶ 1,901:
===Test===
Result from 10 million tries.
<langsyntaxhighlight lang="oorexx">oid='diet.xxx'; Call sysFileDelete oid
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 711 ⟶ 1,946:
o:
Say arg(1)
Return lineout(oid,arg(1))</langsyntaxhighlight>
 
{{out}}
Line 729 ⟶ 1,964:
=={{header|Perl}}==
{{trans|Python}}
<langsyntaxhighlight lang="perl">use List::Util qw(sum0 max);
 
sub comb {
Line 763 ⟶ 1,998:
 
print '(', join(', ', winning([1 .. 4], 9, [1 .. 6], 6)), ")\n";
print '(', join(', ', winning([1 .. 10], 5, [1 .. 7], 6)), ")\n";</langsyntaxhighlight>
{{out}}
<pre>
Line 770 ⟶ 2,005:
</pre>
 
=={{header|Perl 6Phix}}==
{{trans|Go}}
<lang perl6>sub likelihoods ($roll) {
<!--<syntaxhighlight lang="phix">(phixonline)-->
my ($dice, $faces) = $roll.comb(/\d+/);
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
my @counts;
<span style="color: #008080;">function</span> <span style="color: #000000;">throwDie</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">nSides</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">counts</span><span style="color: #0000FF;">)</span>
@counts[$_]++ for [X+] |((1..$faces,) xx $dice);
<span style="color: #008080;">if</span> <span style="color: #000000;">nDice</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
return [@counts[]:p], $faces ** $dice;
<span style="color: #000000;">counts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">s</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
}
<span style="color: #008080;">else</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">nSides</span> <span style="color: #008080;">do</span>
sub beating-probability ([$roll1, $roll2]) {
<span style="color: #000000;">counts</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">throwDie</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nSides</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">counts</span><span style="color: #0000FF;">)</span>
my (@c1, $p1) := likelihoods $roll1;
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
my (@c2, $p2) := likelihoods $roll2;
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
my $p12 = $p1 * $p2;
<span style="color: #008080;">return</span> <span style="color: #000000;">counts</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
[+] gather for @c1 X @c2 -> $p, $q {
take $p.value * $q.value / $p12 if $p.key > $q.key;
<span style="color: #008080;">function</span> <span style="color: #000000;">beatingProbability</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">nSides1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nSides2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice2</span><span style="color: #0000FF;">)</span>
}
<span style="color: #004080;">integer</span> <span style="color: #000000;">len1</span> <span style="color: #0000FF;">:=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">nSides1</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">nDice1</span><span style="color: #0000FF;">,</span>
}
<span style="color: #000000;">len2</span> <span style="color: #0000FF;">:=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">nSides2</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">nDice2</span>
 
<span style="color: #004080;">sequence</span> <span style="color: #000000;">c1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">throwDie</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nSides1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len1</span><span style="color: #0000FF;">)),</span>
# We're using standard DnD notation for dice rolls here.
<span style="color: #000000;">c2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">throwDie</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nSides2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len2</span><span style="color: #0000FF;">))</span>
say .gist, "\t", .perl given beating-probability < 9d4 6d6 >;
<span style="color: #004080;">atom</span> <span style="color: #000000;">p12</span> <span style="color: #0000FF;">:=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nSides1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice1</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nSides2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nDice2</span><span style="color: #0000FF;">),</span>
say .gist, "\t", .perl given beating-probability < 5d10 6d7 >;</lang>
<span style="color: #000000;">tot</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">len1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">min</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">len2</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">tot</span> <span style="color: #0000FF;">+=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">c1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">c2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">p12</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">tot</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%0.16f\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">beatingProbability</span><span style="color: #0000FF;">(</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%0.16f\n"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">beatingProbability</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">))</span>
<!--</syntaxhighlight>-->
{{out}}
<small>
<pre>0.573144077 <48679795/84934656>
(aside: the following tiny discrepancies are to be expected when using IEEE-754 64/80-bit floats; if you want to read anything into them, it should just be that we are all using the same hardware, and probably showing a couple too many digits of (in)accuracy on 32-bit.)
0.64278862872 <3781171969/5882450000></pre>
</small><br>
Note that all calculations are in integer and rational arithmetic, so the results in fractional notation are exact.
32 bit, same as Go, Kotlin
<pre>
0.5731440767829815
0.6427886287176273
</pre>
64 bit, same as D, Python[last], Ruby, Tcl
<pre>
0.5731440767829801
0.6427886287176262
</pre>
 
=={{header|PL/I}}==
===version 1===
<langsyntaxhighlight lang="pli">*process source attributes xref;
dicegame: Proc Options(main);
Call test(9, 4,6,6);
Line 872 ⟶ 2,129:
End;
End;
End;</langsyntaxhighlight>
{{out}}
<pre>Player 1 has 9 dice with 4 sides each
Line 882 ⟶ 2,139:
Probability for player 1 to win: 0.642703175544738770</pre>
===version 2 using rational arithmetic===
<langsyntaxhighlight lang="pli">*process source attributes xref;
dgf: Proc Options(main);
Call test(9, 4,6,6);
Line 1,026 ⟶ 2,283:
End;
 
End;</langsyntaxhighlight>
{{out}}
<pre>Player 1 has 9 dice with 4 sides each
Line 1,039 ⟶ 2,296:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from itertools import product
 
def gen_dict(n_faces, n_dice):
Line 1,057 ⟶ 2,314:
 
print beating_probability(4, 9, 6, 6)
print beating_probability(10, 5, 7, 6)</langsyntaxhighlight>
{{out}}
<pre>0.573144076783
Line 1,063 ⟶ 2,320:
 
To handle larger number of dice (and faster in general):
<langsyntaxhighlight lang="python">from __future__ import print_function, division
 
def combos(sides, n):
Line 1,088 ⟶ 2,345:
 
# mountains of dice test case
# print(winning((1, 2, 3, 5, 9), 700, (1, 2, 3, 4, 5, 6), 800))</langsyntaxhighlight>
{{out}}
<pre>
Line 1,096 ⟶ 2,353:
 
If we further restrict die faces to be 1 to n instead of arbitrary values, the combo generation can be made much faster:
<langsyntaxhighlight lang="python">from __future__ import division, print_function
from itertools import accumulate # Python3 only
 
Line 1,119 ⟶ 2,376:
print(winning(5, 10, 6, 7))
 
#print(winning(6, 700, 8, 540))</langsyntaxhighlight>
{{out}}
<pre>
Line 1,125 ⟶ 2,382:
0.6427886287176262
</pre>
 
=={{header|R}}==
Solving these sorts of problems by simulation is trivial in R.
<syntaxhighlight lang="rsplus">probability <- function(facesCount1, diceCount1, facesCount2, diceCount2)
{
mean(replicate(10^6, sum(sample(facesCount1, diceCount1, replace = TRUE)) > sum(sample(facesCount2, diceCount2, replace = TRUE))))
}
cat("Player 1's probability of victory is", probability(4, 9, 6, 6),
"in the first game and", probability(10, 5, 7, 6), "in the second.")</syntaxhighlight>
{{out}}
<pre>Player 1's probability of victory is 0.572652 in the first game and 0.642817 in the second.</pre>
 
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
 
(define probs# (make-hash))
Line 1,164 ⟶ 2,432:
 
(printf "GAME 2 (5D10 vs 6D7) [what is a D7?]~%")
(game-probs 5 10 6 7)</langsyntaxhighlight>
 
{{out}}
Line 1,178 ⟶ 2,446:
P(P2 win): 0.312715
(3781171969/5882450000 523491347/11764900000 735812943/2352980000)</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2020.08.1}}
<syntaxhighlight lang="raku" line>sub likelihoods ($roll) {
my ($dice, $faces) = $roll.comb(/\d+/);
my @counts;
@counts[$_]++ for [X+] |(1..$faces,) xx $dice;
return [@counts[]:p], $faces ** $dice;
}
sub beating-probability ([$roll1, $roll2]) {
my (@c1, $p1) := likelihoods $roll1;
my (@c2, $p2) := likelihoods $roll2;
my $p12 = $p1 * $p2;
[+] gather for flat @c1 X @c2 -> $p, $q {
take $p.value * $q.value / $p12 if $p.key > $q.key;
}
}
 
# We're using standard DnD notation for dice rolls here.
say .gist, "\t", .raku given beating-probability < 9d4 6d6 >;
say .gist, "\t", .raku given beating-probability < 5d10 6d7 >;</syntaxhighlight>
{{out}}
<pre>0.573144077 <48679795/84934656>
0.64278862872 <3781171969/5882450000></pre>
Note that all calculations are in integer and rational arithmetic, so the results in fractional notation are exact.
 
=={{header|REXX}}==
===Algorithmversion 1===
{{trans|ooRexx}}
(adapted for Classic Rexx)
<syntaxhighlight lang="rexx">/* REXX */
<lang rexx>Numeric Digits 30
Numeric Digits 30
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 1,245 ⟶ 2,542:
res=res p.x
End
Return res</langsyntaxhighlight>
{{out}}
<pre>
Player 1 has 9 dice with 4 sides each
Result from 100.000 tries.
Player 2 has 6 dice with 6 sides each
tbd</pre>
Probability for player 1 to win: 0.573144076782980082947530864198
===tbd===
 
<lang rexx>oid='diet.xxx'; 'erase' oid
Player 1 has 5 dice with 10 sides each
Player 2 has 6 dice with 7 sides each
Probability for player 1 to win: 0.642788628717626159168373721835
</pre>
 
===version 2===
<syntaxhighlight lang="rexx">/* REXX */
oid='diet.xxx'; 'erase' oid
Call test '9 4 6 6'
Call test '5 10 6 7'
Line 1,296 ⟶ 2,601:
o:
Say arg(1)
Return lineout(oid,arg(1))</langsyntaxhighlight>
{{out}}
<pre>Player 1 has: 9 dice with 4 sides each
Player 2 has: 6 dice with 6 sides each
0.574 player 1 wins
Probability for player 1 to win: 0.573144076782980082947530864198
0.3506 player 2 wins
 
0.0754 draws
Player 1 has 5 dice with 10 sides each
0.109000 seconds elapsed
Player 2 has 6 dice with 7 sides each
Player 1: 5 dice with 10 sides each
Probability for player 1 to win: 0.642788628717626159168373721835</pre>
Player 2: 6 dice with 7 sides each
0.6411 player 1 wins
0.3115 player 2 wins
0.0474 draws
0.078000 seconds elapsed</pre>
 
===optimized===
This REXX version is an optimized and reduced version of the first part of the first1<sup>st</sup> REXX example.
<langsyntaxhighlight lang="rexx">/*REXX pgm computes and displays the probabilities of a two─player S─sided, N─dice game.*/
numeric digits 100 /*increase│decreaseincrease/decrease forto heart's desire. */
call game 9 4, 6 6 /*1st player: 9 dice, 4 sides; 2nd player: 6 dice, 6 sides*/
call game 5 10, 6 7 /* " " 5 " 10 " " " 6 " 7 " */
Line 1,315 ⟶ 2,625:
/*──────────────────────────────────────────────────────────────────────────────────────*/
game: parse arg w.1 s.1, w.2 s.2 /*1st player(dice sides), 2nd player···*/
p.= 0
do j=1 for 2; @@.j= prob(w.j, s.j)
do k=w.j to w.j*s.j; parse var @@.j p.j.k @@.j; end /*k*/
end /*j*/
low.= 0
do j=w.1 to w.1*s.1
do k=0 for j; low.j= low.j + p.2.k; end /*k*/
end /*j*/
say ' Player 1 has ' w.1 " dice with " s.1 ' sides each.'
say ' Player 2 has ' w.2 " dice with " s.2 ' sides each.'
winP= 0
do j=w.1 to w.1*s.1; winP= winP + p.1.j * low.j
end /*j*/
say 'The % probability for first player to win is ' format(winP*100, , 30digits()%2) "%."
say /* */
return /*displayshow 301/2 decimalof digits────┘100 dec. digits────┘ */
/*──────────────────────────────────────────────────────────────────────────────────────*/
prob: procedure; parse arg n,s,,@ $; #.= 0; pow= s**n
do j=1 for n; @= @'DO _'j"=1 forFOR" s';'; end /*j*/
@= @'_='; do k=1 for n-1; @= @"_"k'+' ; end /*k*/
interpret @'_'n"; #."_'=#.'_"+1" copies(';END', k)
ns= n*s; do j=0 to ns; p.j= #.j / pow; end /*j*/
do k=n to ns; $= $ p.k; end /*k*/
return $ /* ◄──────────────── probability of 1st player to win, S─sided, N dice.*/</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
'''output'''
<pre>
Player 1 has 9 dice with 4 sides each.
Player 2 has 6 dice with 6 sides each.
The % probability for first player to win is 57.31440767829800829475308641975331440767829800829475308641975308641975308641975309 %.
 
Player 1 has 5 dice with 10 sides each.
Player 2 has 6 dice with 7 sides each.
The % probability for first player to win is 64.27886287176261591683737218335927886287176261591683737218335897457691948082856633 %.
</pre>
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">def roll_dice(n_dice, n_faces)
return [[0,1]] if n_dice.zero?
one = [1] * n_faces
Line 1,375 ⟶ 2,685:
puts "Probability for player 1 to win: #{win[1]} / #{sum}",
" -> #{win[1].fdiv(sum)}", ""
end</langsyntaxhighlight>
 
{{out}}
Line 1,388 ⟶ 2,698:
Probability for player 1 to win: 7562343938 / 11764900000
-> 0.6427886287176262
</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">// Returns a vector containing the number of ways each possible sum of face
// values can occur.
fn get_totals(dice: usize, faces: usize) -> Vec<f64> {
let mut result = vec![1.0; faces + 1];
for d in 2..=dice {
let mut tmp = vec![0.0; d * faces + 1];
for i in d - 1..result.len() {
for j in 1..=faces {
tmp[i + j] += result[i];
}
}
result = tmp;
}
result
}
 
fn probability(dice1: usize, faces1: usize, dice2: usize, faces2: usize) -> f64 {
let totals1 = get_totals(dice1, faces1);
let totals2 = get_totals(dice2, faces2);
let mut wins = 0.0;
let mut total = 0.0;
for i in dice1..totals1.len() {
for j in dice2..totals2.len() {
let n = totals1[i] * totals2[j];
total += n;
if j < i {
wins += n;
}
}
}
wins / total
}
 
fn main() {
println!("{}", probability(9, 4, 6, 6));
println!("{}", probability(5, 10, 6, 7));
}</syntaxhighlight>
 
{{out}}
<pre>
0.5731440767829801
0.6427886287176262
</pre>
 
=={{header|Sidef}}==
{{trans|Python}}
<langsyntaxhighlight lang="ruby">func combos(sides, n) {
n || return [1]
var ret = ([0] * (n*sides.max + 1))
Line 1,405 ⟶ 2,760:
var (win,loss,tie) = (0,0,0)
p1.each_kv { |i, x|
win += x*p2.ftfirst(0,i-1).sum(0)
tie += x*p2.ftslice(i, i).sumfirst(01).sum
loss += x*p2.ftslice(i+1).sum(0)
}
[win, tie, loss]  »/» p1.sum*p2.sum
}
 
Line 1,415 ⟶ 2,770:
say "=> #{title}"
for name, prob in (%w(p₁\ win tie p₂\ win) ~Z res) {
say "P(#{'%6s'  % name}) =~ #{prob.round(-11)} (#{prob.as_frac})"
}
print "\n"
Line 1,421 ⟶ 2,776:
 
display_results('9D4 vs 6D6', winning(range(1, 4), 9, range(1,6), 6))
display_results('5D10 vs 6D7', winning(range(1,10), 5, range(1,7), 6))</langsyntaxhighlight>
{{out}}
<pre>
Line 1,438 ⟶ 2,793:
 
To handle the nested loop in <tt>NdK</tt>, [[Tcl]]'s metaprogramming abilities are exercised. The goal is to produce a script that looks like:
<langsyntaxhighlight Tcllang="tcl">foreach d0 {1 2 3 4 5 6} {
foreach d1 {1 2 3 4 5 6} {
...
Line 1,446 ⟶ 2,801:
...
}
}</langsyntaxhighlight>
 
See the comments attached to that procedure for a more thorough understanding of how that is achieved (with the caveat that <tt>$d0..$dN</tt> are reversed).
Line 1,452 ⟶ 2,807:
Such metaprogramming is a very powerful technique in Tcl for building scripts where other approaches (in this case, recursion) might not be appealing, and should be in every programmer's toolbox!
 
<langsyntaxhighlight Tcllang="tcl">proc range {b} { ;# a common standard proc: [range 5] -> {0 1 2 3 4}
set a 0
set res {}
Line 1,509 ⟶ 2,864:
puts [format "p1 has %dd%d; p2 has %dd%d" {*}$p1 {*}$p2]
puts [format " p1 wins with Pr(%s)" [win_pr [NdK {*}$p1] [NdK {*}$p2]]]
}</langsyntaxhighlight>
 
{{Out}}
Line 1,523 ⟶ 2,878:
I include this to <em>emphasise</em> the importance and power of metaprogramming in a Tcler's toolbox, as well as sharing a useful proc.
 
<langsyntaxhighlight Tcllang="tcl">package require Tcl 8.6 ;# for [tailcall] - otherwise use [uplevel 1 $script]
# This proc builds up a nested foreach call, then evaluates it.
#
Line 1,566 ⟶ 2,921:
foreach* {*}$args $script
return $sum
}</langsyntaxhighlight>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">import math
 
fn min_of(x int, y int) int {
if x < y {
return x
}
return y
}
fn throw_die(n_sides int, n_dice int, s int, mut counts []int) {
if n_dice == 0 {
counts[s]++
return
}
for i := int(1); i <= n_sides; i++ {
throw_die(n_sides, n_dice - 1, s + i, mut counts)
}
}
fn beating_probability(n_sides1 int, n_dice1 int, n_sides2 int, n_dice2 int) f64 {
len1 := (n_sides1 + 1) * n_dice1
mut c1 := []int{len: len1} // all elements zero by default
throw_die(n_sides1, n_dice1, 0, mut c1)
len2 := (n_sides2 + 1) * n_dice2
mut c2 := []int{len: len2}
throw_die(n_sides2, n_dice2, 0, mut c2)
p12 := math.pow(f64(n_sides1), f64(n_dice1)) *
math.pow(f64(n_sides2), f64(n_dice2))
mut tot := 0.0
for i := int(0); i < len1; i++ {
for j := int(0); j < min_of(i, len2); j++ {
tot += f64(c1[i] * c2[j]) / p12
}
}
return tot
}
fn main() {
println(beating_probability(4, 9, 6, 6))
println(beating_probability(10, 5, 7, 6))
}</syntaxhighlight>
 
{{out}}
<pre>
0.57314407678298
0.64278862871763
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
<syntaxhighlight lang="wren">var throwDie // recursive
throwDie = Fn.new { |nSides, nDice, s, counts|
if (nDice == 0) {
counts[s] = counts[s] + 1
return
}
for (i in 1..nSides) throwDie.call(nSides, nDice-1, s + i, counts)
}
 
var beatingProbability = Fn.new { |nSides1, nDice1, nSides2, nDice2|
var len1 = (nSides1 + 1) * nDice1
var c1 = List.filled(len1, 0)
throwDie.call(nSides1, nDice1, 0, c1)
 
var len2 = (nSides2 + 1) * nDice2
var c2 = List.filled(len2, 0)
throwDie.call(nSides2, nDice2, 0, c2)
 
var p12 = nSides1.pow(nDice1) * nSides2.pow(nDice2)
var tot = 0
for (i in 0...len1) {
for (j in 0...i.min(len2)) {
tot = tot + c1[i] * c2[j] / p12
}
}
return tot
}
 
System.print(beatingProbability.call(4, 9, 6, 6))
System.print(beatingProbability.call(10, 5, 7, 6))</syntaxhighlight>
 
{{out}}
<pre>
0.57314407678298
0.64278862871763
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<langsyntaxhighlight lang="zkl">fcn combos(sides, n){
if(not n) return(T(1));
ret:=((0).max(sides)*n + 1).pump(List(),0);
Line 1,591 ⟶ 3,037:
s := p1.sum(0)*p2.sum(0);
return(win.toFloat()/s, tie.toFloat()/s, loss.toFloat()/s);
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">println(winning([1..4].walk(), 9, [1..6].walk(),6));
println(winning([1..10].walk(),5, [1..7].walk(),6)); # this seem hardly fair</langsyntaxhighlight>
{{out}}
<pre>
338

edits