Skip to content

Conversation

@stoehraj
Copy link

@stoehraj stoehraj commented Aug 9, 2021

Preview Video

dice_demo_vid.mp4

Description

This PR adds a new dice rolling app. I play D&D and thought it would be fun to be able to roll dice on my PineTime, so here we are. I thought others might enjoy it too.

This is what the basic UI looks like:

dice_ui

There are buttons to select the number and size of dice. The number of dice can be between 1 and 99, and the supported dice sizes are d2, d3, d4, d6, d8, d12, d20, and d100.

When the desired number and size of dice have been configured, the "Roll" button will, well, roll the dice. Rolls can also be made by slowly rolling the wrist, as shown below:

wrist_roll_demo.mp4

If the roll is made using the motion control, the watch will vibrate, giving feedback that the roll occurred.

After rolling, the first line of the output box at the top of the screens shows the total result, and, if multiple dice are rolled, the second line shows each individual die roll.

Copy link
Contributor

@Riksu9000 Riksu9000 left a comment

Choose a reason for hiding this comment

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

A very nice looking app and well written code.

@hubmartin
Copy link
Contributor

I might overlook something - but if you use rand() and do not set seed by srand(), do you get the same pseudorandom numbers again after InfiniTime reboots?
I cannot see srand anywhere in the InfiniTime code, so either it should be set system-wide after boot based on NRF52832 RNG peripheral, or in the app where seed could be for example uptime in milliseconds.
Otherwise, nice app. Thanks for adding this feature!

@stoehraj
Copy link
Author

stoehraj commented Aug 9, 2021

I might overlook something - but if you use rand() and do not set seed by srand(), do you get the same pseudorandom numbers again after InfiniTime reboots?
I cannot see srand anywhere in the InfiniTime code, so either it should be set system-wide after boot based on NRF52832 RNG peripheral, or in the app where seed could be for example uptime in milliseconds.
Otherwise, nice app. Thanks for adding this feature!

I saw that another app was using rand() (Twos) without anything additional, so I figured everything was all set up for it. I just tested and do indeed get the same output if I do the same roll after a reboot. I'll take care of that.

@stoehraj
Copy link
Author

@hubmartin I could use some help with the srand call for seeding the random number generator. I tried using srand(time(nullptr)); in my object's constructor and also tried doing srand(std::chrono::system_clock::now().time_since_epoch().count()); and neither seemed to have an impact -- that's to say, I could still reproduce getting the same roll each time after a reboot. Would it be better to get the system time using the DateTimeController functions? Also would it be better to have the seed set system-wide as you mentioned? What would that look like?

@hubmartin
Copy link
Contributor

My guess is that constructors are run immediatelly after start and they are called cycle-perfect every time, so you seed the random, but it is same every time. You have to call srand somewhere where the called function is run based on user's input. It might be Dice::createScreen() which if i'm not mistaken is called when you run application

Then I would suggest to seed rather some milliseconds counter/timer. But your srand(std::chrono::system_clock::now().time_since_epoch().count()); might work, or I see also dateTimeController.Uptime().count() value. Its seconds counter so it might be ok, but I would suggest to find millisecond counter somewhere. Not sure whether it has some function or it needs to be added, because it seems like lot of them returns just a seconds.

@virtualbeehive
Copy link

This is a cool idea

@geekbozu
Copy link
Member

With @hubmartin suggestion of using the screen constructor using the current time should be much more effective, dateTimeController.CurrentDateTime().count() should work well as long as the clock is set.

@stoehraj
Copy link
Author

@hubmartin @geekbozu I did a bit more looking at this -- I ended up using srand(dateTimeController.CurrentDateTime().time_since_epoch().count()); in the constructor, and that seemed to do the trick. No repeat rolls after rebooting and trying the same roll (10 six-sided dice) three times.

I believe the constructor is actually called every time the app is opened, rather than once every boot, though with this implementation (using current time rather than uptime) it shouldn't really matter either way.

@geekbozu
Copy link
Member

I gave this a try the other day and it worked really well I will try the new changes and see if it works out well. Never can go wrong with more features.

Is there any plans to actually make apps configurable on compile time so we can remove stuff we don't want when we finally get to the point of running out of room. Not necessarily something you need to figure out just more of a curiosity.

Copy link
Contributor

@Riksu9000 Riksu9000 left a comment

Choose a reason for hiding this comment

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

This code generates some tidy warnings and I copied them here. Other than that this PR looks good.

@toitoinou
Copy link

For the seed part for the random number generation, in an embedded software project I participate with we used ADC values on unused pins or very fluctuant voltage in order to have something different each time. I don't know if we have an ADC on the nrf but we can try to use something proportional to the battery voltage for example before filtering if possible.

@hubmartin
Copy link
Contributor

@toitoinou NRF52 has special and certified RNG peripheral exactly for this reason. I did some quick tests and had something wrong, the numbers did not come. If anyone could look into that it would be great to have system-wide random seed right after boot for the whole system.

@tmilburn
Copy link

tmilburn commented Sep 1, 2021

Using the RNG is pretty simple on the NRF52 https://devzone.nordicsemi.com/f/nordic-q-a/19429/random-number-without-softdevice. I suggest seeding using srand on boot-up.

@geekbozu
Copy link
Member

geekbozu commented Sep 1, 2021

If we are going to use the hardware RNG maybe consider making an "RNG" driver so it can maintain portability between different platforms with more "ease".....aka just have it default to std::rand() when not on an NRF platform

@hubmartin
Copy link
Contributor

@geekbozu we don't need to use RNG for rand. Single RNG number on boot and applying it to the random seed srand should be enough. Then srand gives us number immediatelly. RNG is "slow" if you need many numbers in a row. Maybe could be an issue, maybe not.

@jp-bennett
Copy link

This is such a cool idea. Bump, to see this finished and included in the next build.

@geekbozu
Copy link
Member

geekbozu commented Sep 24, 2021

@geekbozu we don't need to use RNG for rand. Single RNG number on boot and applying it to the random seed srand should be enough. Then srand gives us number immediatelly. RNG is "slow" if you need many numbers in a row. Maybe could be an issue, maybe not.

Yeah this makes a ton of sense. Even more so for applications where randomness is only partially critical.

@stoehraj
Copy link
Author

This is such a cool idea. Bump, to see this finished and included in the next build.

Hey -- thanks for the support. I'd love to finish this up and get it included in the next build.

Unfortunately life has gotten in the way a bit -- I hopefully should have some time in the next couple weeks to come back to it.

@ObiKeahloa
Copy link
Contributor

A small recommendation.

When the icon is pressed change the icon to the number that has been rolled , for other things long pressing it can open the full app.

@stoehraj
Copy link
Author

I just pushed new changes that make the dice app compatible with 1.6.0. I likely still have to revisit the tidy warnings, and also the wrist-motion rolling seems to not work on the new version. I'll try to look into these items over the next few days.

The app itself runs fine otherwise.

@Riksu9000
Copy link
Contributor

There are actually two shake detection algorithms in the works. #691 #660. Seems like the roll detection is quite sensitive, so would a shake work better here too?

@geekbozu
Copy link
Member

geekbozu commented Oct 1, 2021

I would recommend removing the roll and adding it back later. There should be some changes coming down the pipeline on how the BMA interface is defined...one less thing to update with that PR would be nice ;)

@hubmartin
Copy link
Contributor

@stoehraj Hi, was working on other PR and discovered that Nimble is already using RNG peripheral and it has nice driver and wrapper for rand(). All I had to do was:

#include <controller/ble_ll.h>
and then call uint32_t r = ble_ll_rand(); to get the value.

It seems like Nimble has some buffer of pre-generated values so it seems like you can call ble_ll_rand instead of rand directly without any waiting for RNG to generate numbers.
This also explains why I was not able to use RNG, since Nimble reconfigured registers for its own use.

@Riksu9000 Riksu9000 mentioned this pull request Jan 8, 2022
@Riksu9000
Copy link
Contributor

@stoehraj Hi. Could you update this PR, so we can merge it hopefully?

@medeyko
Copy link
Contributor

medeyko commented Jan 8, 2022

I think that in the case when n1, d2 the indicator also should write (heads) or (tails) for those who wishes to flip a coin, see #919

@medeyko
Copy link
Contributor

medeyko commented Feb 6, 2022

@Riksu9000

update this PR, so we can merge it hopefully

As far as I see, @stoehraj doesn't respond. What should be updated in this PR? Maybe it could be done w/o @stoehraj?

@stoehraj
Copy link
Author

@stoehraj Hi. Could you update this PR, so we can merge it hopefully?

@Riksu9000 Hey -- apologies for the extremely late response and lack of activity. I see you've changed some stuff over the past few days. I just flashed the latest stuff onto my unit to play around with a bit.

I do want to try out what @hubmartin suggested with using ble_ll_rand rather than just rand for getting the random values. I'll report back.

Also, if nothing else, I want to squash all of my prior commits to clean up the git history a bit before this gets merged in.

@stoehraj
Copy link
Author

@hubmartin -- the ble_ll_rand() call seems to work really nicely. Just pushed up changes to move to that over the normal rand().

@stoehraj
Copy link
Author

@Riksu9000 -- do you care if I squash your commits in with mine? Or would you prefer to keep yours separate?

@Riksu9000
Copy link
Contributor

@stoehraj Nah I don't care. Do what you want.

src/CMakeLists.txt: Added entry for Dice app.

src/displayapp/Apps.h: Added Dice to list of apps.

src/displayapp/DisplayApp.cpp: Added include for Dice.h. Added entry in
switch case for creating the Dice screen.

src/displayapp/fonts/README.md: Added dice symbol to range.

src/displayapp/fonts/jetbrains_mono_bold_20.c: Added dice symbol.

src/displayapp/screens/ApplicationList.cpp: Added third screen and added
dice app to it.

src/displayapp/screens/ApplicationList.h: Added third application
screen.

src/displayapp/screens/Dice.cpp: New file implementing an app for
rolling dice. User can configure number of dice and size of dice. User
can roll dice with the "Roll" button. The total of the dice roll is shown
in an area at the top of the screen, and if multiple dice are rolled, the
individual rolls are shown underneath the total.

src/displayapp/screens/Dice.h: New header file for Dice.cpp.

src/displayapp/screens/Symbols.h: Added dice symbol.
@stoehraj
Copy link
Author

@Riksu9000 -- just took care of all of the squashing. Got everything into one nice commit and (hopefully) ready to merge in.

@medeyko
Copy link
Contributor

medeyko commented Feb 11, 2022

It is a miniscule issue, but I think it might be a right thing to handle it:
roll = ble_ll_rand() % diceSizes[diceSizeIndex] + 1; introduces so called "modulo bias".
See f.e. https://funloop.org/post/2015-02-27-removing-modulo-bias-redux.html

This commit modifies the roll logic in such a way to avoid modulo bias,
based on an algorithm from the PCG family of random number generators.
@stoehraj
Copy link
Author

It is a miniscule issue, but I think it might be a right thing to handle it: roll = ble_ll_rand() % diceSizes[diceSizeIndex] + 1; introduces so called "modulo bias". See f.e. https://funloop.org/post/2015-02-27-removing-modulo-bias-redux.html

@medeyko -- I just implemented this in the latest changes.

@medeyko
Copy link
Contributor

medeyko commented Apr 17, 2022

Sorry for persisting, but I have a question again: are there any issues left with this app?
It looks well-written and compact, but still useful.

Is it possible to do anything in order to help to include it in the firmware?

@Avamander
Copy link
Collaborator

@medeyko It's difficult to say, the amount of available RAM and storage is getting very very close. It's difficult to choose which new features should be merged first, if there's even space available.

How to keep track of features that depend on additional resources, or do not change the memory footprint and could be instantly merged, is currently WIP.

Hopefully we'll be able to more clearly communicate what's the status of each PR soon.

@Riksu9000 Riksu9000 added the new app This thread is about a new app label May 2, 2022
@Riksu9000 Riksu9000 mentioned this pull request Jun 24, 2022
2 tasks
@w4tsn
Copy link

w4tsn commented Jun 24, 2022

@Avamander a bit off-topic to this PR but as a reply to your thoughts: maybe, just maybe, there need to be some straight-forward way of selecting which apps to include in the build or even have "editions/presets"

@JF002
Copy link
Collaborator

JF002 commented Jun 25, 2022

@Avamander a bit off-topic to this PR but as a reply to your thoughts: maybe, just maybe, there need to be some straight-forward way of selecting which apps to include in the build or even have "editions/presets"

This is something I have in mind : adding the possibility to select which apps will be installed at build time. This is something that is definitely possible to do. However, I think it'll be very difficult to maintain and test : we'll have to maintain and test multiple 'editions', and/or ensure that every combination of apps will work well, ensure that there's enough RAM memory available for all the apps,...

@medeyko
Copy link
Contributor

medeyko commented Jul 27, 2022

Sorry for asking again, but could anyone please write what is the state of this app?
Is there anything left to do with it before inlcusion?
How much resources does it really need?
How much resources are relly left?
I guess this app is one of the smallest possible apps, as it doesn't use any unusual library functions, which may significantly increase code size. It is compact itself.
But it is still usable and also useful.

@Ertain
Copy link

Ertain commented Oct 23, 2022

Just a little neat addition: I think it would be cool if, when the user has set up the "dice" (that is, the dice number and such), they can shake the PineTime, and it "rolls" the dice.

@stoehraj
Copy link
Author

@Ertain hey, thanks for the comment -- if you look at the original description and some of the earlier comments, that actually is a feature I had initially, but we ended up pulling it out when there was some investigation on standardizing gestures a bit more across apps. I think it's a really cool idea, though! Makes the rolling a bit more tangible, especially combined with vibration.

Either way, looks like there's a PR for a different dice app that seems more likely to get merged in than this one (#1326) so may be worth it to request that feature over there as well.

@NeroBurner
Copy link
Contributor

closing in favor of merged #1326

@NeroBurner NeroBurner closed this Jan 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new app This thread is about a new app

Projects

None yet

Development

Successfully merging this pull request may close these issues.