InfiniTime/src/displayapp/screens/Dice.h
Yusuf Ebrahim a40168a9d7
New dice-rolling app: InfiniDice! (#1326)
Add new App `Dice.h` to randomly roll the dice(s).
The number of dice can range from 1-9 (default 1), and the sides can
range from d2-d99 (default d2).

To have a haptic feedback we make Dice vibrate on roll.

Regarding the use of C++ `<random>` library:
There are known problems with `rand()` and `srand()` (see https://en.cppreference.com/w/cpp/numeric/random/rand)
and the `<random>` library is preferred for this reason. The function used from
`<random>` also avoids a very rare bias that would occur using `rand()` and modulo,
when `RAND_MAX` is not a multiple of `d` and the initially generated number falls in
the last "short" segment. This commit also updates the seed to derive entropy
(via `seed_seq`) from a mix of the system tick count and the x,y,z components of the
PineTime motion controller -- taking inspiration from and with credit to @w4tsn
(https://github.com/InfiniTimeOrg/InfiniTime/pull/1199)

Thanks for suggestions:
* in Dice, when rolling 1d2, also show "HEADS" or "TAILS" -- suggestion by @medeyko
* ui adjustments and result realignment -- suggestion by @Boteium

---------

Co-authored-by: NeroBurner <pyro4hell@gmail.com>
Co-authored-by: Riku Isokoski <riksu9000@gmail.com>
Co-authored-by: Paul Weiß <45500341+Poohl@users.noreply.github.com>
Co-authored-by: FintasticMan <finlay.neon.kid@gmail.com>
2024-01-23 09:45:52 +01:00

62 lines
1.8 KiB
C++

#pragma once
#include "displayapp/apps/Apps.h"
#include "displayapp/screens/Screen.h"
#include "displayapp/widgets/Counter.h"
#include "displayapp/Controllers.h"
#include "Symbols.h"
#include <array>
#include <random>
namespace Pinetime {
namespace Applications {
namespace Screens {
class Dice : public Screen {
public:
Dice(Controllers::MotionController& motionController,
Controllers::MotorController& motorController,
Controllers::Settings& settingsController);
~Dice() override;
void Roll();
void Refresh() override;
private:
lv_obj_t* btnRoll;
lv_obj_t* btnRollLabel;
lv_obj_t* resultTotalLabel;
lv_obj_t* resultIndividualLabel;
lv_task_t* refreshTask;
bool enableShakeForDice = false;
std::mt19937 gen;
std::array<lv_color_t, 3> resultColors = {LV_COLOR_YELLOW, LV_COLOR_MAGENTA, LV_COLOR_AQUA};
uint8_t currentColorIndex;
void NextColor();
Widgets::Counter nCounter = Widgets::Counter(1, 9, jetbrains_mono_42);
Widgets::Counter dCounter = Widgets::Counter(2, 99, jetbrains_mono_42);
bool openingRoll = true;
uint8_t currentRollHysteresis = 0;
static constexpr uint8_t rollHysteresis = 10;
Controllers::MotorController& motorController;
Controllers::MotionController& motionController;
Controllers::Settings& settingsController;
};
}
template <>
struct AppTraits<Apps::Dice> {
static constexpr Apps app = Apps::Dice;
static constexpr const char* icon = Screens::Symbols::dice;
static Screens::Screen* Create(AppControllers& controllers) {
return new Screens::Dice(controllers.motionController, controllers.motorController, controllers.settingsController);
};
};
}
}