Ability score statistics: point buy vs. rolling

Asmor said:
A bunch of people, myself included, tackled this a long time ago.

http://www.enworld.org/showthread.php?t=128481

Short, possibly biased, answer: The average rolled character is just under 30.5 points. This is assuming that a 7 is -1, a 6 -2, etc.

There was a bit of variation, but after checking both an "exact" method and the "monte carlo" method of rolling up a million characters and averaging them, both answers came out close enough that I'm pretty confident in the 30.5.
Since there was a decent amount of consensus on that number, I went through and reviewed my code again -- found one more issue. I was only allowing a reroll if the max score was <= 13 and the sum of modifiers was <= 0, instead of if either one is true. After fixing that, I get a number consistent with the others in that thread -- 30.4769. Note that this is an analytical/deterministic result, not stochastic.

With that final correction, here's a review of the average point buy costs for various dice rolling methods:

Average Characters (3d6, reroll if max < 12 or modifiers < -2): 19.5109 (26.3% chance of reroll)
Standard rolling (4d6, drop lowest, reroll if max < 14 or modifiers < +1): 30.4769 (12.9% chance of reroll)
Standard + reroll ones (4d6, drop lowest, reroll 1s, reroll if max < 14 or modifiers < +1): 37.7441 (2.4% chance of reroll)
High-Powered Characters (5d6, drop lowest 2, reroll if max < 15 or modifiers < +2): 39.1323 (6.6% chance of reroll)

Also, I cleaned up and consolidated the code, and I added comments. So it's available for double-checking, or if anyone wants to use it as a basis for other calculations. The program is in C++, and it runs in about 1.3 seconds on a 2GHz machine whe compiled using gcc -O2. There's not much code involved, but it's bulked up to about double its raw size due to comments.

This is for the straight 4d6-drop-lowest version, but it's easy to change with the #defines at the top (rerolling 1s is done by using 5-sided dice with a die bonus of 1):

Code:
#include <math.h>
#include <memory.h>
#include <stdio.h>
#include <algorithm>

#define NUM_DICE 4
#define NUM_SIDES 6
#define DIE_BONUS 0
#define REROLL_MAX_SCORE_THRESHOLD 14
#define REROLL_MODIFIER_SUM_THRESHOLD 1

// calculate the probability of each score and fill it into _score_prob
void calculate_score_probs(double* _score_prob)
{
	memset(_score_prob, 0, sizeof(double)*19);

	// iterate through all possible sets of dice rolls
	int num_possibilities = (int)pow(NUM_SIDES, NUM_DICE);
	for(int i=1; i<num_possibilities; i++) {
		int die[NUM_DICE];
		memset(die, 0, sizeof(int)*NUM_DICE);

		// turn this index into individual die roll numbers
		int i2 = i;
		for(int j=0; j<NUM_DICE; j++) {
			die[j] = i2 % NUM_SIDES + 1 + DIE_BONUS;
			i2 /= NUM_SIDES;
		}

		// sort the dice so that the highest rolls are first in the array
		std::sort(die, die+NUM_DICE);
		std::reverse(die, die+NUM_DICE);
		// increment the probability for the score that's the sum of the highest 3 dice
		_score_prob[die[0]+die[1]+die[2]] += 1.0/num_possibilities;
	}
}

int main()
{
	// score_prob is the probability of rolling each score. The score is the index into
	// the array, so the first 3 entries will be empty.
	double score_prob[19];
	calculate_score_probs(score_prob);
	// score_cost is an array of the point costs for each score, indexed the same way
	int score_cost[19] = {0, 0, 0, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16};

	// prob_of_cost is the probability of a set of scores having a specific total point
	// cost (ignoring score sets that can be rerolled).  The point cost + 24 is the index
	// into the array (total possible range of -24 to 96).
	double prob_of_cost[121];
	memset(prob_of_cost, 0, sizeof(double)*121);
	// total prob is the probability of rolling a set of scores that can't be rerolled.
	double total_prob = 0;

	// iterate through all possible sets of scores.  There are 16 possible scores (3-18),
	// so the total number of sets of scores is 16^6 = 16777216.
	for(int i=0; i<16777216; i++)
	{
		bool max_score_over_threshold = false;
		int modifier_sum = 0;
		double prob = 1;
		int cost = 0;

		// turn the index into a set of individual scores
		int i2 = i;
		for(int j=0; j < 6; j++) {
			int score = i2 % 16 + 3;
			i2 /= 16;

			// for each score, record if it's over 13 or and its effect on the sum of
			// the modifiers, so we can decide if this score set can be rerolled.
			if(score >= REROLL_MAX_SCORE_THRESHOLD)
				max_score_over_threshold = true;
			modifier_sum += score/2 - 5;

			// after each roll, multiply the probability of this score set by the
			// probability of rolling the most recent score.  By the end of the set,
			// we'll have the overall probability of the entire score set.
			prob *= score_prob[score];
			// likewise, add the point cost of the current score into the total for
			// this set.
			cost += score_cost[score];
		}

		// only count this score set if it can't be rerolled
		if(max_score_over_threshold && modifier_sum >= REROLL_MODIFIER_SUM_THRESHOLD) {
			prob_of_cost[cost+24] += prob;
			total_prob += prob;
		}
	}

	// add up the cost of each score set, weighted by the probability of that score
	// set occurring.
	double total_cost = 0;
	for(int i=0; i<=121; i++)
		total_cost += (i-24) * prob_of_cost[i];

	printf("score sets that can be rerolled:  %.4f%\n", (1 - total_prob)*100);
	// the overall EV is the (weighted) average cost of non-rerollable score sets
	// divided by the chance of rolling a non-rerollable score set in the first place.
	printf("average point cost after rerolls:  %.4f\n", total_cost/total_prob);

	return 0;
}
 

log in or register to remove this ad

We've used a more liberal variation of 4d6, and I'm curious as to how it would come out in this analysis. You start out rolling 3d6 for your first score. If you wish, you may roll a fourth die and drop the lowest, or you may take the 3d6 result and "bank" the fourth die for a later roll. For each subsequent roll, you can take the 3d6 and bank the fourth, you can roll a fourth die, or you can roll one or more dice from your bank (in addition to the standard fourth die) and take the best three. Obviously, for your last roll, you roll 4d6 plus any remaining dice in the bank, and take the highest three.

--Axe
 

Pickaxe said:
We've used a more liberal variation of 4d6, and I'm curious as to how it would come out in this analysis. You start out rolling 3d6 for your first score. If you wish, you may roll a fourth die and drop the lowest, or you may take the 3d6 result and "bank" the fourth die for a later roll. For each subsequent roll, you can take the 3d6 and bank the fourth, you can roll a fourth die, or you can roll one or more dice from your bank (in addition to the standard fourth die) and take the best three. Obviously, for your last roll, you roll 4d6 plus any remaining dice in the bank, and take the highest three.

--Axe

I think that would be extremely complicated to figure out statistically, especially since there's an element of choice involved there. If it were done at all, I think you'd be best off doing it by randomly generating the characters, and even then you'd still have to figure out how and when to use the extra rolls.
 

kerbarian said:
A number of people have mentioned the house rule of rerolling ones. I decided to see how much of a difference it makes, and it's pretty huge.

Rolling 4d6 and dropping the lowest gives you an average point buy cost of 28.5 (29.2 with rerolls). If you reroll ones, the average point buy cost jumps all the way to 37.4 (37.5 with rerolls). That's about as good as 5d6, drop the lowest 2.

I think the reason we started using that rule was b/c we really were rolling quite bad ... and it was 1e ... where a 14 in a score usually meant nada.
 

Asmor said:
I think that would be extremely complicated to figure out statistically, especially since there's an element of choice involved there. If it were done at all, I think you'd be best off doing it by randomly generating the characters, and even then you'd still have to figure out how and when to use the extra rolls.
I think I've actually figured out a way to work through the results analytically in a reasonable amount of time, but as you say, it does involve an element of choice. So one of the inputs to the model would have to be a set of rules for deciding when to use the dice rolls.
 

Wolf72 said:
I think the reason we started using that rule was b/c we really were rolling quite bad ... and it was 1e ... where a 14 in a score usually meant nada.

Point buy is the only way to be fair, it makes sure all characters have the same advantage from the start, and places them in the ability range the DM desires. Just as you wouldn't give one character max starting funds, and another 30% of max starting funds, that's the reason to use point buy.

<ducks>
 

Remove ads

Top