Some probablities for success with OVA dice pools
Posted: Mon Oct 15, 2007 4:14 pm
I like the die rolling method for Ricochet/OVA, but I don't necessarily find it intuitive. So, to get a feel for some of the probabilities, I wrote a brute-force C program to determine them (the source code for which can be found at the bottom of this post). I had to limit the number of dice I ran it against as it was taking forever to finish (like not finishing after running all weekend on a 2.67 GHz machine with 2G of RAM). I also ran it some against the d10 version of the dice pool that had been discussed here.
The abbreviations used for the difficulties and the numbers in the form [d6]/[d10] are as follows:
The results (in terms of chance of making a test of that difficulty) for the d6 dice pool are:
Note that values of a 100% are not, actually, 100% but just very close; similarly, some of the 0% values are just too small to register with the format selected (you can tell those with a moment's thought).
The results for the d10 dice pool are:
As can be seen, the proposed difficulty numbers give probabilities fairly different than the d6 dice pool.
The program (for anyone interested):
The abbreviations used for the difficulties and the numbers in the form [d6]/[d10] are as follows:
Code: Select all
Easy EZ [ 2]/[ 4]
Moderate MO [ 4]/[ 6]
Challenging CG [ 6]/[10]
Difficult DF [ 8]/[14]
Very Difficult VD [10]/[16]
Extremely Difficult ED [12]/[20]
Nigh Impossible NI [15]/[25]
Code: Select all
#D EZ ( 2) MO ( 4) CG ( 6) DF ( 8) VD (10) ED (12) NI (15)
=========================================================================
-6 23.257% 0.391% 0.000% 0.000% 0.000% 0.000% 0.000%
-5 27.908% 0.781% 0.000% 0.000% 0.000% 0.000% 0.000%
-4 33.490% 1.563% 0.002% 0.000% 0.000% 0.000% 0.000%
-3 40.188% 3.125% 0.013% 0.000% 0.000% 0.000% 0.000%
-2 48.225% 6.250% 0.077% 0.000% 0.000% 0.000% 0.000%
-1 57.870% 12.500% 0.463% 0.000% 0.000% 0.000% 0.000%
0 69.444% 25.000% 2.778% 0.000% 0.000% 0.000% 0.000%
1 83.333% 50.000% 16.667% 0.000% 0.000% 0.000% 0.000%
2 97.222% 80.556% 38.889% 8.333% 5.556% 2.778% 0.000%
3 99.537% 93.981% 60.648% 22.685% 15.278% 8.333% 0.926%
4 99.923% 98.380% 77.855% 39.892% 27.623% 16.512% 3.318%
5 99.987% 99.601% 89.185% 56.970% 41.088% 26.800% 7.446%
6 99.998% 99.908% 95.413% 71.727% 54.345% 38.398% 13.351%
7 100.000% 99.980% 98.279% 83.031% 66.382% 50.366% 20.869%
8 100.000% 99.996% 99.416% 90.750% 76.556% 61.795% 29.663%
9 100.000% 99.999% 99.817% 95.437% 84.581% 71.959% 39.271%
10 100.000% 100.000% 99.947% 97.957% 90.480% 80.410% 49.161%
11 100.000% 100.000% 99.985% 99.162% 94.512% 86.998% 58.801%
12 100.000% 100.000% 99.996% 99.683% 97.058% 91.825% 67.726%
13 100.000% 100.000% 99.999% 99.888% 98.536% 95.148% 75.588%
14 100.000% 100.000% 100.000% 99.963% 99.323% 97.292% 82.185%
The results for the d10 dice pool are:
Code: Select all
#D EZ ( 4) MO ( 6) CG (10) DF (14) VD (16) ED (20) NI (25)
=========================================================================
-6 5.765% 0.391% 0.000% 0.000% 0.000% 0.000% 0.000%
-5 8.235% 0.781% 0.000% 0.000% 0.000% 0.000% 0.000%
-4 11.765% 1.563% 0.000% 0.000% 0.000% 0.000% 0.000%
-3 16.807% 3.125% 0.001% 0.000% 0.000% 0.000% 0.000%
-2 24.010% 6.250% 0.010% 0.000% 0.000% 0.000% 0.000%
-1 34.300% 12.500% 0.100% 0.000% 0.000% 0.000% 0.000%
0 49.000% 25.000% 1.000% 0.000% 0.000% 0.000% 0.000%
1 70.000% 50.000% 10.000% 0.000% 0.000% 0.000% 0.000%
2 93.000% 78.000% 24.000% 4.000% 3.000% 1.000% 0.000%
3 98.700% 91.500% 39.700% 11.400% 8.600% 3.100% 0.200%
4 99.790% 97.130% 54.980% 21.310% 16.270% 6.360% 0.760%
5 99.969% 99.159% 68.329% 32.703% 25.402% 10.777% 1.806%
6 99.996% 99.786% 78.986% 44.563% 35.362% 16.278% 3.433%
7 99.999% 99.952% 86.844% 56.006% 45.540% 22.719% 5.706%
8 100.000% 99.990% 92.230% 66.369% 55.401% 29.902% 8.659%
9 100.000% 99.998% 95.675% 75.239% 64.516% 37.580% 12.297%
10 100.000% 100.000% 97.736% 82.449% 72.588% 45.483% 16.593%
11 100.000% 100.000% 98.888% 88.028% 79.449% 53.341% 21.490%
The program (for anyone interested):
Code: Select all
/***********************************************************************
*
*N {ricochet.c} -- Calculate probabilities for Rocochet dice pools.
*
***********************************************************************/
#include <stdio.h>
#include <stdlib.h>
/* Types. */
typedef unsigned char RicoDie;
typedef int Bool;
typedef struct {
RicoDie *dice;
RicoDie dieSize;
int diceCount;
int actualDiceCount;
} RicoDicePool;
/* The following define is platform dependent. For instance on Windows, it
is __int64, and on some Unix platforms long int. */
#define Int64 long
/* Constants. */
#define TRUE (-1)
#define FALSE (0)
#define MAX_DIE_SIZE 256
#define DIFFICULTY_COUNT 7
#define MIN_DICE_POOL -6
#define MAX_DICE_POOL 14
/* Utility macros. */
#define ACTUAL_COUNT(count) ((count > 0) ? count : (-count + 2))
/* Fixed data. */
static const char *DifficultyLabels[] = {"Easy",
"Moderate",
"Challenging",
"Difficult",
"Very Difficult",
"Extremely Difficult",
"Nigh Impossible"};
static const char *DifficultyTags[] = {"EZ","MO","CG","DF","VD","ED","NI"};
static const int DifficultyLevels6[] = {2,4,6,8,10,12,15};
static const int DifficultyLevels10[] = {4,6,10,14,16,20,25};
/***********************************************************************
*
*N {CreatePool} -- Create a dice pool, all initialized to 1's
*
***********************************************************************/
RicoDicePool * CreatePool (RicoDie size,
int count)
{
int actualCount,d;
RicoDicePool *pool;
/* Deal with dice counts < 1. */
actualCount = ACTUAL_COUNT (count);
/* Allocate structures. */
pool = (RicoDicePool *)malloc (sizeof(RicoDicePool));
if (!pool) return NULL;
pool->dice = malloc (sizeof(RicoDie) * actualCount);
if (!pool->dice) return NULL;
/* Initialize values. */
for (d = 0;d < actualCount;d++) pool->dice[d] = 1;
pool->dieSize = size;
pool->diceCount = count;
pool->actualDiceCount = actualCount;
/* Done. */
return pool;
}
/***********************************************************************
*
*N {FreePool} -- Free a dice pool.
*
***********************************************************************/
void FreePool (RicoDicePool *pool)
{
if (!pool) return;
if (pool->dice) free (pool->dice);
free (pool);
return;
}
/***********************************************************************
*
*N {IncrementPool} -- Increment a dice pool to the next value.
*
***********************************************************************/
Bool IncrementPool (RicoDicePool *pool)
{
int d;
for (d = 0;d < pool->actualDiceCount;d++) {
if (pool->dice[d] == pool->dieSize) {
if (d == (pool->actualDiceCount - 1)) return FALSE; /* Overflow! */
pool->dice[d] = 1;
} else {
pool->dice[d]++;
break;
}
}
return TRUE;
}
/***********************************************************************
*
*N {EvaluatePool} -- Determine the value of the supplied dice pool.
*
***********************************************************************/
int EvaluatePool (const RicoDicePool *pool)
{
int d,value,rollValue;
RicoDie dieCount[MAX_DIE_SIZE];
/* If there are zero or negative dice in the pool, just look for the lowest
value. */
if (pool->diceCount < 1) {
value = pool->dieSize;
for (d = 0;d < pool->actualDiceCount;d++)
if (pool->dice[d] < value) value = pool->dice[d];
}
/* Positive dice a bit trickier, since we need to detect multiple instances
of the same roll, so we'll count those first. (Multiple 1's don't count
so we don't add them up at the end.) */
else {
for (d = 1;d <= pool->dieSize;d++) dieCount[d] = 0;
for (d = 0;d < pool->diceCount;d++) dieCount[pool->dice[d]]++;
value = 1;
for (d = 2;d <= pool->dieSize;d++) {
rollValue = dieCount[d] * d;
if (rollValue > value) value = rollValue;
}
}
return value;
}
/***********************************************************************
*
*N {PoolSuccessStats} -- Determine success percentages for a given pool size.
*
***********************************************************************/
Bool PoolSuccessStats (RicoDie size,
int count,
const int *difficulties,
double *successPercentages,
int difficultyCount)
{
RicoDicePool *pool;
int value,d;
Int64 *successes,totalTests;
/* Create the pool to test. */
pool = (RicoDicePool *) CreatePool (size,count);
if (!pool) return FALSE;
/* Initialize test values. */
successes = (Int64 *)calloc (difficultyCount,sizeof(Int64));
if (!successes) return FALSE;
totalTests = 0;
/* Loop through all possible values of the dice pool, and record which ones
succeeded. */
do {
value = EvaluatePool (pool);
for (d = 0;d < difficultyCount;d++)
if (value >= difficulties[d]) successes[d]++;
totalTests++;
} while (IncrementPool (pool));
FreePool (pool);
/* Calculate percentages. */
for (d = 0;d < difficultyCount;d++)
successPercentages[d] = (double)successes[d] / (double)totalTests * 100.0;
free (successes);
return TRUE;
}
/***********************************************************************
*
*N {Main} -- Main function
*
***********************************************************************/
int main (int argc, char *argv[])
{
int poolSize,d;
double successPercentages[DIFFICULTY_COUNT];
/* Print Header and terms. */
printf ("Calculate success chances for Ricochet Dice Pools\n");
printf ("=================================================\n");
for (d = 0;d < DIFFICULTY_COUNT;d++)
printf ("%-24s %2s [%2d]/[%2d]\n",DifficultyLabels[d],DifficultyTags[d],
DifficultyLevels6[d],DifficultyLevels10[d]);
printf ("\nCalculate D6's\n");
printf ("\n#D %2s (%2d) %2s (%2d) %2s (%2d) %2s (%2d) %2s (%2d)"
" %2s (%2d) %2s (%2d)\n",
DifficultyTags[0],DifficultyLevels6[0],
DifficultyTags[1],DifficultyLevels6[1],
DifficultyTags[2],DifficultyLevels6[2],
DifficultyTags[3],DifficultyLevels6[3],
DifficultyTags[4],DifficultyLevels6[4],
DifficultyTags[5],DifficultyLevels6[5],
DifficultyTags[6],DifficultyLevels6[6]);
printf ("=================================================================="
"=======\n");
/* Print Calculations. */
for (poolSize = MIN_DICE_POOL;poolSize <= MAX_DICE_POOL;poolSize++) {
if (PoolSuccessStats (6,poolSize,DifficultyLevels6,successPercentages,
DIFFICULTY_COUNT)) {
printf ("%2d %7.3f%% %7.3f%% %7.3f%% %7.3f%% %7.3f%% %7.3f%% "
"%7.3f%%\n",
poolSize,
successPercentages[0],
successPercentages[1],
successPercentages[2],
successPercentages[3],
successPercentages[4],
successPercentages[5],
successPercentages[6]);
fflush (stdout);
}
}
printf ("\n\nCalculate D10's\n");
printf ("\n#D %2s (%2d) %2s (%2d) %2s (%2d) %2s (%2d) %2s (%2d)"
" %2s (%2d) %2s (%2d)\n",
DifficultyTags[0],DifficultyLevels10[0],
DifficultyTags[1],DifficultyLevels10[1],
DifficultyTags[2],DifficultyLevels10[2],
DifficultyTags[3],DifficultyLevels10[3],
DifficultyTags[4],DifficultyLevels10[4],
DifficultyTags[5],DifficultyLevels10[5],
DifficultyTags[6],DifficultyLevels10[6]);
printf ("=================================================================="
"=======\n");
/* Print Calculations. */
for (poolSize = MIN_DICE_POOL;poolSize <= MAX_DICE_POOL;poolSize++) {
if (PoolSuccessStats (10,poolSize,DifficultyLevels10,successPercentages,
DIFFICULTY_COUNT)) {
printf ("%2d %7.3f%% %7.3f%% %7.3f%% %7.3f%% %7.3f%% %7.3f%% "
"%7.3f%%\n",
poolSize,
successPercentages[0],
successPercentages[1],
successPercentages[2],
successPercentages[3],
successPercentages[4],
successPercentages[5],
successPercentages[6]);
fflush (stdout);
}
}
return EXIT_SUCCESS;
}