What you need to do is have your conditional inside a function with a number parameter. Then when you pass it a die, anydice will roll the die at that time and use the result in the function.
function: X:n conditional {
if X = 1 {execute arbitrary code here}
if X = 2 {execute arbitrary code here}
if X = 3 {execute arbitrary code here}
if X = 4 {execute arbitrary code here}
if X = 5 {execute arbitrary code here}
if X = 6 {execute arbitrary code here}
}
output [d6 conditional]
There are some slightly more practical examples of this technique in my answer here.
Overall this seems to benefit the first player, but it depends how you measure it.
I thought I would model this programatically as it will be a bit more flexible than using AnyDice. I've written a script which carries out the process a large number of times and averages the values for each player.
The main difficulty here is how you actually interpret the data: what makes one array of ability scores better than another one? There are multiple ways to judge this. I'll include some values for different methods.
Total of all ability scores
Player 1 has mean ability score value 72.95522.
Player 2 has mean ability score value 73.43975.
Player 3 has mean ability score value 73.64131.
Player 4 has mean ability score value 73.72761.
Verdict: Being later in the order is better
Total of all ability scores except the lowest one
Player 1 has mean ability score value 66.49585.
Player 2 has mean ability score value 65.71347.
Player 3 has mean ability score value 65.10333.
Player 4 has mean ability score value 64.57315.
Verdict: Being earlier in the order is better
Total points buy cost of all ability scores
(I've used invented points buy scores for numbers outside the normal allowed range: 18 = 19, 17 = 15, 16 = 12, 6-7 = -1, 4-5 = -2, 3 = -1)
Player 1 has mean ability score value 33.43838.
Player 2 has mean ability score value 31.80692.
Player 3 has mean ability score value 31.00389.
Player 4 has mean ability score value 30.64647.
Verdict: Being earlier in the order is better
Total points buy cost of all ability scores except the lowest one
Player 1 has mean ability score value 34.33727.
Player 2 has mean ability score value 31.88918.
Player 3 has mean ability score value 30.39722.
Player 4 has mean ability score value 29.45149.
Verdict: Being earlier in the order is much better
I've included my horrible amateur code here so you can try it out.
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw(sum);
use Data::Dumper;
use POSIX;
use 5.010;
my $die_size = 6;
my $number_of_dice = 4;
my $number_of_players = 4;
my $number_of_runs = 10000;
sub get_single_ability_score {
my @rolls;
for (1..$number_of_dice) {
my $roll = 1 + int rand($die_size);
push @rolls, $roll;
}
@rolls = sort {$a <=> $b} @rolls;
for (1..$number_of_dice - 3) {
shift @rolls;
}
my $ability_score = sum(@rolls);
return $ability_score;
}
sub get_total_values {
my @group_ability_scores;
for (1..$number_of_players * 6) {
push @group_ability_scores, get_single_ability_score();
}
@group_ability_scores = sort { $b <=> $a } @group_ability_scores;
my @player_order = (1..$number_of_players);
my @reverse_player_order = sort { $b <=> $a } @player_order;
@player_order = (@player_order, @reverse_player_order, @player_order, @reverse_player_order, @player_order, @reverse_player_order);
my @player_ability_scores;
foreach my $player (@player_order) {
my @ability_scores;
my $chosen_ability_score = shift @group_ability_scores;
push @ability_scores, $chosen_ability_score;
push @{ $player_ability_scores[$player-1] }, @ability_scores;
}
my @total_values;
foreach my $player (1..$number_of_players) {
my @ability_scores = sort { $a <=> $b } @{ $player_ability_scores[$player-1] };
my $total_value = 0;
shift @ability_scores; # One dump stat is fine so discard the lowest ability score
foreach my $ability_score (@ability_scores) {
#$total_value += $ability_score; # Uses the score as the value
#$total_value += floor(($ability_score - 10) / 2); # Uses the modifier as the value
given ($ability_score) {
when ($_ == 18) {$total_value += 19}
when ($_ == 17) {$total_value += 15}
when ($_ == 16) {$total_value += 12}
when ($_ == 15) {$total_value += 9}
when ($_ == 14) {$total_value += 7}
when ($_ == 13) {$total_value += 5}
when ($_ == 12) {$total_value += 4}
when ($_ == 11) {$total_value += 3}
when ($_ == 10) {$total_value += 2}
when ($_ == 9) {$total_value += 1}
when ($_ == 8) {$total_value += 0}
when ($_ == 7) {$total_value += -1}
when ($_ == 6) {$total_value += -2}
when ($_ == 5) {$total_value += -3}
when ($_ == 4) {$total_value += -4}
when ($_ == 3) {$total_value += -5}
}
}
push @total_values, $total_value;
}
return @total_values;
}
my @all_values;
for (1..$number_of_runs) {
my @total_values = get_total_values();
foreach my $player (1..$number_of_players) {
push @{ $all_values[$player-1] }, $total_values[$player-1];
}
}
for my $player (1..$number_of_players) {
my $total_value;
foreach my $value (@{ $all_values[$player-1] }) {
$total_value += $value;
}
my $mean_value = $total_value / $number_of_runs;
print "Player $player has mean ability score value $mean_value.\n";
}
Try it online!
Best Answer
Yes, this can be done. The Anydice documentation details how we can describe arbitrary dice. Functionally with percentages like that, the dice is equivalent to:
... So we'll define exactly that die in this Anydice program:
The syntax used there is sequences, and we're using it so we don't have to write out
{1, 1, 1, 1, 1, 1, 1, 1...
and so on eighteen times, and then the same for the five other faces. That's too prone to error and difficult to read. A more normal usage of sequences is writing1..3:2
, which is a sequence from 1 to 3 repeated twice, which is to say it represents1, 2, 3, 1, 2, 3
. We're generating a sequence that contains 1 repeated 18 times. The same goes for the other values.W is a variable (covered in The Basics in the documentation). Variables must be uppercase, but you can name it whatever you want, including
WEIGHTED_DIE
if you'd prefer.