• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Herringway / unexpected / #5

02 Aug 2024 11:28PM UTC coverage: 80.601% (+0.7%) from 79.935%
#5

push

coveralls-ruby

Herringway
add influencedUniform

18 of 18 new or added lines in 1 file covered. (100.0%)

9 existing lines in 1 file now uncovered.

295 of 366 relevant lines covered (80.6%)

290077.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.75
/source/unexpected/influence.d
1
/// Functions for "luck", or influenced results
2
module unexpected.influence;
3

4
import std.range : ElementType;
5

6
enum hasMinMax(T) = is(typeof(T.min) == typeof(T.max)) && is(typeof(T.min) == T);
7

8
auto influencedChoice(Range, Rand, Element = ElementType!Range)(double luck, ref Rand rng, Range range) if (hasMinMax!(ElementType!Range)) {
UNCOV
9
        return influencedChoice(luck, rng, range, ElementType!Range.min, ElementType!Range.max);
×
10
}
11
auto influencedChoice(Range, Rand, Element = ElementType!Range)(double luck, ref Rand rng, Range range, Element worst, Element best)
12
        in(!range.empty, "Nothing to choose")
2,600✔
13
        in(best >= worst, "Worst value must be less than best")
2,600✔
14
        out(result; result >= worst, "Result is less than worst value")
5,200✔
15
        out(result; result <= best, "Result is greater than best value")
5,200✔
16
{
17
        import std.algorithm.comparison : min;
18
        import std.math : isInfinity;
19
        import std.random : uniform01;
20
        if (luck.isInfinity) {
2,600✔
21
                if (luck > 0) {
800✔
22
                        return best;
800✔
23
                } else {
24
                        return worst;
800✔
25
                }
26
        }
27
        auto chosen = range.front;
1,800✔
28
        range.popFront();
1,800✔
29
        bool negative = luck < 0.0;
1,800✔
30
        if (luck < 0.0) {
1,800✔
31
                luck = -luck;
600✔
32
        }
33
        while ((luck > 0.0) && !range.empty) {
2,700✔
34
                if (chosen > best) {
900✔
UNCOV
35
                        return best;
×
36
                } else if (chosen < worst) {
900✔
UNCOV
37
                        return worst;
×
38
                }
39
                const remaining = min(luck, 1.0);
900✔
40
                luck -= remaining;
900✔
41
                if (remaining >= uniform01(rng)) {
900✔
42
                        auto next = range.front;
900✔
43
                        range.popFront();
900✔
44
                        if (negative ^ (next > chosen)) {
900✔
45
                                chosen = next;
462✔
46
                        }
47
                }
48
        }
49
        return chosen;
3,600✔
50
}
51

52
@safe pure unittest {
53
        import std.random : Random, uniform;
54
        import std.range : generate;
55
        static struct Result {
56
                enum min = Result(0);
57
                enum max = Result(100);
58
                int x;
59
                int opCmp(Result b) const pure @safe {
UNCOV
60
                        return x - b.x;
×
61
                }
62
        }
63
        Random rand;
1✔
64
        enum iterations = 100;
65
        double test(double luck) {
UNCOV
66
                long total;
×
UNCOV
67
                foreach (i; 0 .. iterations) {
×
UNCOV
68
                        total += influencedChoice(luck, rand, generate!(() => Result(uniform(0, 100, rand)))).x;
×
69
                }
UNCOV
70
                return total / double(iterations);
×
71
        }
72
        double test2(double luck, int min = int.min, int max = int.max) {
73
                long total;
10✔
74
                foreach (i; 0 .. iterations) {
3,030✔
75
                        const value = influencedChoice(luck, rand, generate!(() => uniform(0, 100, rand)), min, max);
2,900✔
76
                        assert(value >= min);
1,000✔
77
                        assert(value <= max);
1,000✔
78
                        total += value;
1,000✔
79
                }
80
                return total / double(iterations);
10✔
81
        }
82
        assert(test2(0.0) < test2(1.0));
1✔
83
        assert(test2(0.0) > test2(-1.0));
1✔
84
        assert(test2(double.infinity) == int.max);
1✔
85
        assert(test2(-double.infinity) == int.min);
1✔
86
        assert(test2(double.infinity, 0, 100) == 100);
1✔
87
        assert(test2(-double.infinity, 0, 100) == 0);
1✔
88
        assert(test2(0.0, 0, 100) > test2(-1.0, 0, 100));
1✔
89
}
90

91
auto influencedWeightedChoice(Range, Weights, Rand, Element = ElementType!Range)(double luck, ref Rand rng, Range range, Weights weights) if (hasMinMax!(ElementType!Range)) {
92
        return influencedWeightedChoice(luck, rng, range, weights, Element.min, Element.max);
93
}
94
auto influencedWeightedChoice(Range, Weights, Rand, Element = ElementType!Range)(double luck, ref Rand rng, Range range, Weights weights, Element worst, Element best) {
95
        import std.random : dice;
96
        import std.range : drop, front, generate;
97
        return influencedChoice(luck, rng, generate!({ return range.drop(dice(rng, weights)).front; }), worst, best);
2,500✔
98
}
99

100
@safe pure unittest {
101
        import std.random : Random;
102
        import std.range : iota;
103
        static struct Result {
104
                enum min = Result(0);
105
                enum max = Result(100);
106
                int x;
107
                int opCmp(Result b) const pure @safe {
UNCOV
108
                        return x - b.x;
×
109
                }
110
        }
111
        Random rand;
1✔
112
        enum iterations = 100;
113
        enum vals = [100, 50, 33, 0, 25];
114
        double test2(double luck, int min, int max) {
115
                long total;
8✔
116
                foreach (i; 0 .. iterations) {
2,424✔
117
                        const value = influencedWeightedChoice(luck, rand, vals, iota(5), min, max);
800✔
118
                        assert(value >= min);
800✔
119
                        assert(value <= max);
800✔
120
                        total += value;
800✔
121
                }
122
                return total / double(iterations);
8✔
123
        }
124
        assert(test2(0.0, 0, 100) < test2(1.0, 0, 100));
1✔
125
        assert(test2(0.0, 0, 100) > test2(-1.0, 0, 100));
1✔
126
        assert(test2(double.infinity, 0, 100) == 100);
1✔
127
        assert(test2(-double.infinity, 0, 100) == 0);
1✔
128
        assert(test2(0.0, 0, 100) > test2(-1.0, 0, 100));
1✔
129
}
130

131
auto influencedUniform(Rand, T)(double luck, ref Rand rng, T worst, T best) {
132
        import std.random : uniform;
133
        static auto uniformRange(Rand rng, T worst, T best) {
134
                struct Result {
135
                        T front;
136
                        enum bool empty = false;
137
                        void popFront() {
138
                                front = uniform(worst, best, rng);
1,700✔
139
                        }
140
                }
141
                Result result;
800✔
142
                result.popFront();
800✔
143
                return result;
800✔
144
        }
145
        return influencedChoice(luck, rng, uniformRange(rng, worst, best), worst, best);
800✔
146
}
147

148
@safe pure unittest {
149
        import std.random : Random;
150
        Random rand;
1✔
151
        enum iterations = 100;
152
        double test(double luck, int min, int max) {
153
                long total;
8✔
154
                foreach (i; 0 .. iterations) {
2,424✔
155
                        const value = influencedUniform(luck, rand, min, max);
800✔
156
                        assert(value >= min);
800✔
157
                        assert(value <= max);
800✔
158
                        total += value;
800✔
159
                }
160
                return total / double(iterations);
8✔
161
        }
162
        assert(test(0.0, 0, 100) < test(1.0, 0, 100));
1✔
163
        assert(test(0.0, 0, 100) > test(-1.0, 0, 100));
1✔
164
        assert(test(double.infinity, 0, 100) == 100);
1✔
165
        assert(test(-double.infinity, 0, 100) == 0);
1✔
166
        assert(test(0.0, 0, 100) > test(-1.0, 0, 100));
1✔
167
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc