55#include " components/motor/MotorController.h"
66#include " components/motion/MotionController.h"
77
8+ namespace PCG {
9+ uint32_t pcg32_random_r (pcg32_random_t * rng) {
10+ uint64_t oldstate = rng->state ;
11+ // Advance internal state
12+ rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1 );
13+ // Calculate output function (XSH RR), uses old state for max ILP
14+ uint32_t xorshifted = ((oldstate >> 18u ) ^ oldstate) >> 27u ;
15+ uint32_t rot = oldstate >> 59u ;
16+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31 ));
17+ }
18+
19+ // Lemire's Method (slight rewrite) [0, range)
20+ uint32_t bounded_rand (pcg32_random_t & rng, uint32_t range) {
21+ uint64_t m;
22+ uint32_t t = (-range) % range;
23+ uint32_t l;
24+ do {
25+ uint32_t x = pcg32_random_r (&rng);
26+ m = uint64_t (x) * uint64_t (range);
27+ l = uint32_t (m);
28+ } while (l < t);
29+ return m >> 32 ;
30+ }
31+ };
32+
833using namespace Pinetime ::Applications::Screens;
934
1035namespace {
@@ -43,11 +68,12 @@ Dice::Dice(Controllers::MotionController& motionController,
4368 Controllers::MotorController& motorController,
4469 Controllers::Settings& settingsController)
4570 : motorController {motorController}, motionController {motionController}, settingsController {settingsController} {
46- std::seed_seq sseq {static_cast <uint32_t >(xTaskGetTickCount ()),
47- static_cast <uint32_t >(motionController.X ()),
48- static_cast <uint32_t >(motionController.Y ()),
49- static_cast <uint32_t >(motionController.Z ())};
50- gen.seed (sseq);
71+ rng.state = (static_cast <uint64_t >(xTaskGetTickCount ()) << 32 ) ^ (static_cast <uint64_t >(motionController.NbSteps ()) << 16 ) ^ (uint64_t ) &rng;
72+ rng.inc = (static_cast <uint64_t >(motionController.X ()) << 32 ) ^ (static_cast <uint64_t >(motionController.Y ()) << 16 ) ^
73+ static_cast <uint64_t >(motionController.Z ());
74+ rng.inc ^= (uint64_t ) PCG::pcg32_random_r (&rng);
75+ rng.inc ^= (uint64_t ) PCG::pcg32_random_r (&rng) << 32 ;
76+ rng.state = (uint64_t ) PCG::pcg32_random_r (&rng) << 32 ^ PCG::pcg32_random_r (&rng);
5177
5278 lv_obj_t * nCounterLabel = MakeLabel (&jetbrains_mono_bold_20,
5379 LV_COLOR_WHITE,
@@ -79,8 +105,7 @@ Dice::Dice(Controllers::MotionController& motionController,
79105 lv_obj_align (dCounter.GetObject (), dCounterLabel, LV_ALIGN_OUT_BOTTOM_MID, 0 , 10 );
80106 dCounter.SetValue (6 );
81107
82- std::uniform_int_distribution<> distrib (0 , resultColors.size () - 1 );
83- currentColorIndex = distrib (gen);
108+ currentColorIndex = PCG::bounded_rand (rng, resultColors.size ());
84109
85110 resultTotalLabel = MakeLabel (&jetbrains_mono_42,
86111 resultColors[currentColorIndex],
@@ -157,12 +182,10 @@ void Dice::Refresh() {
157182void Dice::Roll () {
158183 uint8_t resultIndividual;
159184 uint16_t resultTotal = 0 ;
160- std::uniform_int_distribution<> distrib (1 , dCounter.GetValue ());
161-
162185 lv_label_set_text (resultIndividualLabel, " " );
163186
164187 if (nCounter.GetValue () == 1 ) {
165- resultTotal = distrib (gen) ;
188+ resultTotal = PCG::bounded_rand (rng, dCounter. GetValue ()) + 1 ;
166189 if (dCounter.GetValue () == 2 ) {
167190 switch (resultTotal) {
168191 case 1 :
@@ -175,7 +198,7 @@ void Dice::Roll() {
175198 }
176199 } else {
177200 for (uint8_t i = 0 ; i < nCounter.GetValue (); i++) {
178- resultIndividual = distrib (gen) ;
201+ resultIndividual = PCG::bounded_rand (rng, dCounter. GetValue ()) + 1 ;
179202 resultTotal += resultIndividual;
180203 lv_label_ins_text (resultIndividualLabel, LV_LABEL_POS_LAST, std::to_string (resultIndividual).c_str ());
181204 if (i < (nCounter.GetValue () - 1 )) {
0 commit comments