Search code examples
javarandomevaljtextfielddice

Calculate Dice Roll from Text Field


QUESTION: How can I read the string "d6+2-d4" so that each d# will randomly generate a number within the parameter of the dice roll?

CLARIFIER: I want to read a string and have it so when a d# appears, it will randomly generate a number such as to simulate a dice roll. Then, add up all the rolls and numbers to get a total. Much like how Roll20 does with their /roll command for an example. If !clarifying {lstThen.add("look at the Roll20 and play with the /roll command to understand it")} else if !understandStill {lstThen.add("I do not know what to say, someone else could try explaining it better...")}

Info: I was making a Java program for Dungeons and Dragons, only to find that I have come across a problem in figuring out how to calculate the user input: I do not know how to evaluate a string such as this.

I theorize that I may need Java's eval at the end. I do know what I want to happen/have a theory on how to execute (this is more so PseudoCode than Java):

Random rand = new Random();
int i = 0;
String toEval;
String char;

String roll = txtField.getText();

while (i<roll.length) {
    check if character at i position is a d, then highlight the numbers
    after d until it comes to a special character/!aNumber
    // so if d was found before 100, it will then highlight 100 and stop
    // if the character is a symbol or the end of the string
    if d appears {
        char = rand.nextInt(#);
        i + #'s of places;
        // so when i++ occurs, it will move past whatever d# was in case
        // d# was something like d100, d12, or d5291
    } else {
        char = roll.length[i];
    }
    toEval = toEval + char;
    i++;
}

perform evaluation method on toEval to get a resulting number
list.add(roll + " = " + evaluated toEval);

EDIT: With weston's help, I have honed in on what is likely needed, using a splitter with an array, it can detect certain symbols and add it into a list. However, it is my fault for not clarifying on what else was needed. The pseudocode above doesn't helpfully so this is what else I need to figure out.

roll.split("(+-/*^)");

As this part is what is also tripping me up. Should I make splits where there are numbers too? So an equation like:

String[] numbers = roll.split("(+-/*^)");
String[] symbols = roll.split("1234567890d")

// Rough idea for long way
loop statement {
    loop to check for parentheses {
        set operation to be done first
    }

    if symbol {
        loop for symbol check {
            perform operations
    }}} // ending this since it looks like a bad way to do it...

// Better idea, originally thought up today (5/11/15)
int val[];
int re = 1;

loop {
    if (list[i].containsIgnoreCase(d)) {
        val[]=list[i].splitIgnoreCase("d");
        list[i] = 0;
        while (re <= val[0]) {
            list[i] = list[i] + (rand.nextInt(val[1]) + 1);
            re++;
        }
    }
}
// then create a string out of list[]/numbers[] and put together with
// symbols[] and use Java's evaluator for the String

wenton had it, it just seemed like it wasn't doing it for me (until I realised I wasn't specific on what I wanted) so basically to update, the string I want evaluated is (I know it's a little unorthodox, but it's to make a point; I also hope this clarifies even further of what is needed to make it work):

(3d12^d2-2)+d4(2*d4/d2)

From reading this, you may see the spots that I do not know how to perform very well... But that is why I am asking all you lovely, smart programmers out there! I hope I asked this clearly enough and thank you for your time :3


Solution

  • The trick with any programming problem is to break it up and write a method for each part, so below I have a method for rolling one dice, which is called by the one for rolling many.

    private Random rand = new Random();
    
    /**
     * @param roll can be a multipart roll which is run and added up. e.g. d6+2-d4
     */
    public int multiPartRoll(String roll) {
        String[] parts = roll.split("(?=[+-])"); //split by +-, keeping them
        int total = 0;
        for (String partOfRoll : parts) { //roll each dice specified
            total += singleRoll(partOfRoll);
        }
        return total;
    }
    
    /**
     * @param roll can be fixed value, examples -1, +2, 15 or a dice to roll
     * d6, +d20 -d100
     */
    public int singleRoll(String roll) {
        int di = roll.indexOf('d');
        if (di == -1) //case where has no 'd'
            return Integer.parseInt(roll);
        int diceSize = Integer.parseInt(roll.substring(di + 1)); //value of string after 'd'
        int result = rand.nextInt(diceSize) + 1; //roll the dice
        if (roll.startsWith("-")) //negate if nessasary
            result = -result;
        return result;
    }