Skip to content

dnd-character: chi-squared tests - #584

Merged
keiravillekode merged 3 commits into
exercism:mainfrom
keiravillekode:dnd-tests
Sep 15, 2026
Merged

keiravillekode merged 3 commits into
exercism:mainfrom
keiravillekode:dnd-tests

Conversation

@keiravillekode

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown
Contributor

This PR touches files which potentially affect the outcome of the tests of an exercise. This will cause all students' solutions to affected exercises to be re-tested.

If this PR does not affect the result of the test (or, for example, adds an edge case that is not worth rerunning all tests for), please add the following to the merge-commit message which will stops student's tests from re-running. Please copy-paste to avoid typos.

[no important files changed]

For more information, refer to the documentation. If you are unsure whether to add the message or not, please ping @exercism/maintainers-admin in a comment. Thank you!

@keiravillekode

Copy link
Copy Markdown
Contributor Author


A correct implementation has less than a 0.01% chance of failing each test.

Note that, according to the instructions, an ability score is _the sum of the three largest results out of four rolls of an unbiased d6 (six-sided die)_.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The instructions does not propose these restrictions.

Here is what the instruction document currently states:

You do this by rolling four 6-sided dice and recording the sum of the largest three dice.

There is no statement of requirement that it be an unbiased six sided die, and even states that it is not four rolls of a single die, but "by rolling four 6-sided dice", while the answer could be accomplished with a single d6 rolled four times, it is misquoting, misstating what is referenced.

Instead, we can avoid this (due to it may be changed at any time, without any downstream referencing of append file) by deferring to the instructions without mentioning specifics to this level of detail.

Perhaps the safest line would be:

"See the instructions for a definition of what an ability score is."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the word "above" is added to introduce "instructions" and while it can be true that it is literally "above" it is not the case for all situations (such as reviewing this append file alone). We could reference "instructions" without a geographical reference of any kind, and it would be more universally compatible with the reader's situation.

test "random ability is distributed correctly" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);
const random = prng.random();
var counts = [_]u64{0} ** 16;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var counts: [16]u64 = @splat(0);

test "each character ability is distributed correctly" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);
const random = prng.random();
var counts = [_][16]u64{[_]u64{0} ** 16} ** 6;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var counts: [6][16]u64 = @splat(@splat(0));

test "character abilities are independent" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);
const random = prng.random();
var counts = [_]u64{0} ** 64;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    var counts: [64]u64 = @splat(0);


/// The number of times each score from 3 to 18 arises among the
/// 6 * 6 * 6 * 6 = 1296 equally likely rolls of four dice.
const score_weights = [16]u64{ 1, 4, 10, 21, 38, 62, 91, 122, 148, 167, 172, 160, 131, 94, 54, 21 };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const score_weights: [16]u64 = .{ 1, 4, 10, 21, 38, 62, 91, 122, 148, 167, 172, 160, 131, 94, 54, 21 };

}

test "random ability is within range" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);

}

test "random ability is distributed correctly" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);

}

test "random character is valid" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);

}

test "each character ability is distributed correctly" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);

}

test "character abilities are independent" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);

}

test "character depends only on the random number generator" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var prng: std.Random.DefaultPrng = .init(testing.random_seed);


test "character depends only on the random number generator" {
var prng = std.Random.DefaultPrng.init(testing.random_seed);
var other_prng = std.Random.DefaultPrng.init(testing.random_seed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var other_prng: std.Random.DefaultPrng = .init(testing.random_seed);

var prng = std.Random.DefaultPrng.init(testing.random_seed);
var other_prng = std.Random.DefaultPrng.init(testing.random_seed);
for (0..20) |_| {
const character = Character.init(prng.random());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    const character: Character = .init(prng.random());

var other_prng = std.Random.DefaultPrng.init(testing.random_seed);
for (0..20) |_| {
const character = Character.init(prng.random());
const other_character = Character.init(other_prng.random());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    const other_character: Character = .init(other_prng.random());

const random = prng.random();
var counts = [_]u64{0} ** 64;
for (0..sample_size) |_| {
const character = Character.init(random);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const character: Character = .init(random);

const random = prng.random();
var counts = [_][16]u64{[_]u64{0} ** 16} ** 6;
for (0..sample_size) |_| {
const character = Character.init(random);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const character: Character = .init(random);

const random = prng.random();
for (0..20) |_| {
const character = Character.init();
const character = Character.init(random);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const character: Character = .init(random);

@keiravillekode

Copy link
Copy Markdown
Contributor Author

All of these are at maintainers' discretion.

@truly-not-taken truly-not-taken left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var x = T{} is not the preferred syntax, var x: T = .{} is.
ziglang/zig#5038

@splat() is better than **.

@truly-not-taken

Copy link
Copy Markdown

All of these are at maintainers' discretion.

Yes. I am sorry for the spam. I did not know it would work that way.

@keiravillekode
keiravillekode merged commit a360080 into exercism:main Sep 15, 2026
8 checks passed
@keiravillekode
keiravillekode deleted the dnd-tests branch September 15, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants