• The VOIDRUNNER'S CODEX is coming! Explore new worlds, fight oppressive empires, fend off fearsome aliens, and wield deadly psionics with this comprehensive boxed set expansion for 5E and A5E!

D&D 5E Randomly generating point-buy arrays

m00

Villager
Hi guys,

Here's a simple method for randomly generating ability score arrays of a fixed point-buy value. It's simple enough to use at the table: all it requires is a bunch of 6-sided dice! (I'm sure you can find enough.) It can be adjusted for different point-buy values and for different ability score cost tables, but what I'm presenting is assuming the default point buy described in the PHB.

I'm not advocating for or against point buy vs. rolled stats; mostly this is just an interesting statistical exercise!

The Algorithm

Step 0: Decide the value (call it n) of the array and grab that many 6-sided dice and put them in a dice pool.

Step 1: Roll all n dice in the pool. Count how many are equal to 1. Find the largest cost on the "Ability Score Point Cost" table in the PHB that is equal to or less than this value (call this value x). Assign the corresponding score for value x to the first place in the ability score array. Remove x dice from the dice pool.

For example, say there are 2 dice that show a 1, so x=2. The score corresponding to x=2 is 10, so the first score in the array is 10. Then, remove x=2 dice from the dice pool. Alternatively, imagine there are 6 dice that show a 1; in this case, x=5, since 5 is the largest cost that is less than or equal to 6 (the next highest cost is 7, which is larger than 6). In this case, the first score is set to 13 and 5 dice are removed from the pool.

Step 2: As step 1, but count how many dice are less than or equal to 2. (Remember to keep removing dice from the pool from here on!)

Step 3: As step 1, but count how many dice are less than or equal to 3.

Step 4: As step 1, but count how many dice are less than or equal to 4.

Step 5: As step 1, but count how many dice are less than or equal to 5.

Step 6: As step 1, but count how many dice are less than or equal to 6. Obviously, this step is not really random, so you can just assign the remaining points to the last slot in the array.

Step 7: Done!

Steps 1-6 will guarantee that the point-buy value of the generated array is exactly equal to 27 (or whatever n you used). The distribution for each spot in the array is different, so if you also want to randomize which scores are assigned to each stat, you should shuffle them up first. I assume that the players assign the scores as they wish, so for the below summary and examples I assume the array has been sorted from high-to-low.

Some Statistical Properties

Here is a summary of (sorted) outcomes from this distribution (I don't know of an analytical solution for this distribution, so these are all computed from a 1 million simulations):

ScoreMean95% quantile
highest14.7214-15
213.9013-15
312.9912-14
411.8910-13
510.289-12
lowest8.488-10

The overall mean ability score is 12.04. 72% of arrays have at least one score of 15; 59% have at least one score of 8; 93% have at least one 8 or 9.

Here are what 20 outcomes look like. Feel free to confirm that their values are all 27!

15,14,13,12,10,8
14,14,14,11,10,9
15,13,13,12,11,9
15,14,13,12,10,8
15,13,13,12,12,8
15,14,13,11,11,8
15,13,13,12,12,8
15,13,13,12,11,9
14,14,13,12,12,8
15,14,13,12,10,8
15,13,13,12,12,8
15,13,13,12,11,9
15,14,12,12,11,8
15,13,13,12,12,8
14,13,13,12,12,10
15,14,13,11,11,8
14,14,13,12,10,10
15,15,12,11,10,8
14,14,13,13,11,8

Some Code

Here is some R code for simulating this process:

Code:
############################
# randomly sampling arrays #
############################

ability_scores = 8:15

score_cost = c(
  "8"   = 0,
  "9"   = 1,
  "10" = 2,
  "11" = 3,
  "12" = 4,
  "13" = 5,
  "14" = 7,
  "15" = 9
)

sampleArray = function(ability_scores, score_cost, num_scores, points) {

  current_points = points
  scores = numeric(num_scores)
  for(i in 1:num_scores) {

    # 'roll' #points dice
    rolls = sample.int(num_scores, current_points, replace=TRUE)

    # keep any that are <= i
    num_this_stat = sum(rolls <= i)

    # find the score that has at most this many points
    this_score = ability_scores[max(which(score_cost <= num_this_stat))]

    # assign the score to the current array slot
    scores[i] = this_score

    # decrement the number of dice in the pool
    current_points = current_points - as.numeric(score_cost[as.character(this_score)])

  }

  return(sort(scores, decreasing=TRUE))

}


sampleArray(ability_scores, score_cost, 6, 27)
 

log in or register to remove this ad


Remove ads

Top