kugelblitz
kugelblitz

Reputation: 33

How to generate random arithmetic expressions for game

i would like to know if you can help me with this problem for my game. I'm currently using lots of switch, if-else, etc on my code and i'm not liking it at all.

I would like to generate 2 random arithmethic expressions that have one of the forms like the ones bellow:

1) number

e.g.: 19

2) number operation number

e.g.: 22 * 4

3) (number operation number) operation number

e.g.: (10 * 4) / 5

4) ((number operation number) operation number) operation number

e.g.: ((25 * 2) / 10) - 2

After i have the 2 arithmetic expresions, the game consist in matching them and determine which is larger.

I would like to know how can i randomly choose the numbers and operations for each arithmetic expression in order to have an integer result (not float) and also that both expression have results that are as close as possible. The individual numbers shouldn't be higher than 30.

I mean, i wouldn't like a result to be 1000 and the other 14 because they would be probably too easy to spot which side is larger, so they should be like:

expresion 1: ((25 + 15) / 10) * 4 (which is 16)

expression 2: (( 7 * 2) + 10) / 8 (which is 3)

The results (16 and 3) are integers and close enough to each other.

the posible operations are +, -, * and /

It would be possible to match between two epxressions with different forms, like

(( 7 * 2) + 10) / 8 and (18 / 3) * 2

I really appreciate all the help that you can give me. Thanks in advance!!

Best regards.

Upvotes: 3

Views: 1727

Answers (1)

beaker
beaker

Reputation: 16810

I think a reasonable way to approach this is to start with a value for the total and recursively construct a random expression tree to reach that total. You can choose how many operators you want in each equation and ensure that all values are integers. Plus, you can choose how close you want the values of two equations, even making them equal if you wish. I'll use your expression 1 above as an example.

((25 + 15) / 10) * 4 = 16

We start with the total 16 and make that the root of our tree:

   16

To expand a node (leaf), we select an operator and set that as the value of the node, and create two children containing the operands. In this case, we choose multiplication as our operator.

Multiplication is the only operator that will really give us trouble in trying to keep all of the operands integers. We can satisfy this constraint by constructing a table of divisors of integers in our range [1..30] (or maybe a bit more, as we'll see below). In this case our table would have told us that the divisors of 16 are {2,4,8}. (If the list of divisors for our current value is empty, we can choose a different operator, or a different leaf altogether.)

We choose a random divisor, say 4 and set that as the right child of our node. The left child is obviously value/right, also an integer.

    *
   / \
  4   4

Now we need to select another leaf to expand. We can randomly choose a leaf, randomly walk the tree until we reach a leaf, randomly walk up and right from our current child node (left) until we reach a leaf, or whatever.

In this case our selection algorithm chooses to expand the left child and the division operator. In the case of division, we generate a random number for the right child (in this case 10), and set left to value*right. (Order is important here! Not so for multiplication.)

     *
    / \
   ÷    4
  / \
 40 10

This demonstrates why I said that the divisor table might need to go beyond our stated range as some of the intermediate values may be a bit larger than 30. You can tweak your code to avoid this, or make sure that large values are further expanded before reaching the final equation.

In the example we do this by selecting the leftmost child to expand with the addition operator. In this case, we can simply select a random integer in the range [1..value-1] for the right child and value-right for the left.

      *
     / \
    ÷    4
   / \
  +  10
 / \
25 15

You can repeat for as many operations as you want. To reconstruct the final equation, you simply need to perform an in-order traversal of the tree. To parenthesize as in your examples, you would place parentheses around the entire equation when leaving any interior (operator) node during the traversal, except for the root.

Upvotes: 3

Related Questions