Dice Calculator (string manipulation question)

How do I…

I’m making a calculator app with extra buttons for RPG dice (d4, d6, d8, d10, d12, d20, d100) and some custom preset buttons for certain weapons and spells. Got it working like a normal calculator, and when adding dice results together like “d6+d6” it will work as intended, choosing a random result for each d6 and adding them together.
The problem I’m facing is that I want to be able to enter something like “2d6” instead of “d6+d6” to do the same thing, but I can’t figure out an elegant way to do this with events that doesn’t require me to make events checking for every unique string from 1 to 100 for each of the dice types (700+ manually created events).

Right now I have events checking for the names of each die in the expression string (when I say “expression” I mean in the mathematical sense, not gdevelop expressions) and replacing them with random numbers in the corresponding range, then using a simple little javascript code block to evaluate the expression and send the result out to a scene variable, which the next events use to display the result.

What is the wanted result

I want a mathematical expression written like “2d8” or “2*d8” to functionally do the same thing as “d8+d8” without having to tediously manually create hundreds of events that check for and replace unique strings before the calculation event.

I want to be able to type, with the calculator buttons, mathematical equations like “1d10+2d8+6” and have events translate that string into “d10+d8+d8+6” so that I can have my already-working events splice the random numbers in to change the string into its final form of something like “5+1+8+6” before it is sent to the javascript code block for calculation.

What is the current result

Currently, only dice name strings are being replaced by a random number, within the main expression string (expected, but insufficient).
This means that something like “1d4” will get translated into “11”, “12”, “13”, or “14” before getting sent into the javascript code block to be calculated.
Also, strings like “2*d4” will only have that single “d4” string be replaced by a random number from 1 to 4, which then gets multiplied by 2, when what I actually want is for the d4 to be rolled twice and added together.





Can I have more details? I didn’t understand very well what you want?

What exactly are you not understanding? Not sure how I can explain without repeating myself.

What I want is an efficient way using events to translate a string with any number (like 4) followed by the name of an RPG die (like “d8”), for example “4d8” to be converted into “d8+d8+d8+d8” in an event, before the events in my screenshot, so that each instance of the string “d8” can be separately replaced by a random number in range 1 to 8.

Or some other way to achieve the same result, if it can’t be done by manipulating the string.

Внимательно перечитывал и понял. Сделаю пример такого калькулятора так как объяснить не могу.

1 Like

Sorry, I answered in Russian. I reread it carefully. I’ll make an example of such a game, because I can’t explain it.

1 Like

It shouldn’t take “hundreds of events” to parse out the meaning of XdY. The string manipulation part should only serve to read the string and convert it into data that can then be used by the separate calculation events. At least this is what makes the most sense to me, and it has the added benefit of being able to re-roll without parsing again.

Think of the data you will need for calculation and then let the parser do all the legwork to arrive at that data set. This is how I’m imagining it. For convenience, a single die should always have a 1 before it:

  • Copy the string to a new variable so you can leave the unaltered string in the display
  • Find all operators (+, -, *) and add some sort of delimiter (a single character that you can search for, that isn’t used elsewhere. like letter O or something)
  • Get a chunk of the string up until the first delimiter
  • Look for a d in the resulting chunk. If found:
    • Copy the text leading up to this position. This is your first multiplier
    • Copy the text after this position, until the next delimiter (+, -, * etc) This is your number of faces
  • Convert these to numbers and put them in an array
  • If not found, this is just a discrete number rather than a roll. Decide a special way to put this in the array. Maybe record it as “d0” or “d1” so during calculation, you know not to roll but to just add the number instead.
  • Copy the operator into the array
  • Cut everything up to this point and repeat until the text length is 0

How you store everything is up to you. I might do a two-by-whatever array. The first number in each “row” will be the number of dice, and the second will be the number of faces.

The operators could be stored as text or numbers, since you’ll never have a 0 number of dice, a 0 in the first slot could indicate operator and the second slot would be a number to represent which operator is used.

Then to calculate, just loop through the array.

repeat Array[0][0] times
    change variable: add Random(Array[0][1])

Of course you’ll want a variable for the position:

repeat Array[index][0] times
    change variable: add Random(Array[index][1])
add 1 to index
1 Like

Thank you for taking your time to reply. It’s gonna take me a while to try and understand the advice you have given me, though.

I should maybe add for context, since I have a tiny bit of javascript in my project, that I do not know javascript at all, so any implied references to it in your advice will probably go over my head. Half of the things you are suggesting I am unsure if you mean that they can be done with gdevelop events or if they will need to be done in javascript.
Additionally, while I technically know how arrays work, mostly, I find them quite un-intuitive, like a rubik’s cube.

Congratulations🥁! The example is over! https://kotikrazrab.itch.io/calculatorotiks. I have also included a calculation function using my new extension! in gratitude, you can play one of my games using the link https://yandex.ru/games/developer/118362

@kotiks

I downloaded and tested your example…

It appears that you just remade my app, then put a link to your website on it, without attempting to solve the problem that I was having. I am not sure how this was meant to be helpful. My app could already do more than what your example can do.

Maybe my issue got lost in translation from English to Russian. I am sorry to have wasted your time if it was a misunderstanding.

I got it! Random numbers from 1 to 4 need to be added in the example.

@kotiks
No, you don’t understand. I already have my own functioning app. I don’t need you to make an example that does what I have described.

I described what the app I have already made does, and asked how to add a particular feature to it. I have already explained what I want multiple times, and @magicsofa understood my problem perfectly. I didn’t fully understand their answer, but it seems to contain the solution.

I have managed to come up with a solution to the issue, without using arrays.


I used events and a boolean to store the last number typed in a string, then when a dice button is clicked right after a number, it converts the text. For example, from “3d4” to “(d4+d4+d4)”
GDevelop_asrQCdt7Ws

I have never used custom JS in GDevelop. Everything I’ve suggested can be done with events - I only use the “code” formatting to quickly scratch out example events without having to use screenshots.

Arrays are just variables with more than one box. You can make arrays in the variable editor which might help to understand them better. An array with only one dimension is like a single row of boxes. When you first make an array in the variable editor it will be like this - basically a list of numbers on the left, with a value on the right. Each number on the left is an index, which is needed to find a specific value on the right. The value can be any variable type (number, string, etc)

Think of it this way - you could have some variables named Var0, Var1, and Var2. You’re storing three values in different variables. In the same way you could have an array called Var, with 3 elements. The advantage of this is that instead of having to type out the full variable name every time (Var1 etc), you can access each element by number. In GDevelop expressions you would do this the same way as most programming lanugages - the name of the array, then an index number in brackets. Such as Var[0], Var[1], Var[2]. Now if you have another variable, let’s call it Index, you can do Var[Index] to get a value instead. So now you can go through the array by starting the Index variable at 0, and adding 1 after each iteration.

Multi-dimensional arrays can be a little scary but they are literally just the above concept stacked together. So for a two-dimensional array, imagine a grid of boxes instead of just a single row. In the variable editor, this isn’t really how it looks. Instead you’ll have an array, where the variable type at each index is also “array”. A 3x3 array will look like this:

MyArray   (array)
  0.  (array)
     0.  value
     1.  value
     2.  value
  1.  (array)
     0.  value
     1.  value
     2.  value
  2.  (array)
     0.  value
     1.  value
     2.  value

Of course, this gets tedious if you’re doing a lot by hand, so generally if you’re using large arrays then you will want to be generating them using events instead. Anyway, this would be accessed with two brackets: MyArray[2][1]

You don’t have to use arrays. You could use objects for the dice… each “roll” could be its own object, with variables for the number and faces. So for 2d4, you create an object and set its number variable to 2, and faces variable to 4. At the end of the day the point is to store the information in some way that makes it easy to work with. It isn’t absolutely necessary in your application, but its a good thing to learn. First of all, doing it this way could open up functionality such as being able to edit pieces of the formula (like, imagine having a long formula such as 2d4 + 4d8 - 10, and you can click on 4d8 to select it and change it to 4d10, without redoing the whole thing). Second, it will allow you to eventually handle much bigger sets of data. A common use might be a save state, where you need to record a bunch of properties for many objects.