Using imbricated rand checks

For builders to discuss and ask building questions.
Post Reply
Dalvyn
Sword Grand Master
Sword Grand Master
Posts: 4708
Joined: Tue Jul 15, 2003 9:26 pm
Location: House of Wonder, Waterdeep

Using imbricated rand checks

Post by Dalvyn » Wed Aug 06, 2003 12:39 am

I've been exploring the use of 'if rand(%)' to make
the actions of mobs less predictable. For example this
prog on a watch wizard:

Code: Select all

>fight_prog 100~
if rand(10)
  cast 'stone skin'
else
  if rand(50)
    cast 'magic missile' $n
  else
    if rand(10)
      cast 'shield'
    else
      if rand(10)
        cast 'armor'
      else
        if rand(10)
          cast 'bulls strength'
        else
          if rand(10)
            cast 'fire shield'
          else
            cast 'shocking grasp' $n
          endif
        endif
      endif
    endif
  endif
endif 
~
Is there any reason this might be a bad idea? If I had
the patience, I could make mobs do some neat stuff
with code like this.
The answer below is a rather long and boring explanation for those who want to know the details. If you just want a balanced program (where you have 3, 4, 5, ... options all of them with the same chance of happening) and do not want the details, check the second post below.

All classes come with a standard fight_prog I think. But if you really want your mob to be efficient and if you don't want it to just do some standard actions / cast some standard spells, I think it's a very good idea to add a fight_prog with some random actions.

A note about imbricated rand tests, that is, rand tests in other rand tests... you have to remember that each "rand" test is like a choice with 2 options: the "if" part and the "else" part. I saw in your program above that you have rand(..) tests with numbers summing up to 100%. This program above won't make the mob cast "magic missile" with 50% chance, or "fire shield" with 10% chance though... it's a bit more tricky.

I'll use the (smaller) program below to explain

Code: Select all

if rand(40)
  cast 'magic missile'
else
  if rand(50)
    cast 'lightning bolt'
  else
     cast 'shocking grasp'
  endif
endif
In this program, the first test is "if rand(40)". That means that there is 40% chance that the mob casts 'magic missile' and thus, 60% chance that the "else" part is used. In this else part, there is 50% chance that the mob casts "lightning bolt" and, if not, the mob casts "shocking grasp". So, if you want to sum it up with a small diagram...

Code: Select all

      /-- 40% -- magic missile
      |
------|
      |                              /-- 50% -- lightning bolt
      |                              |
      \-- 60% -- first else part ----|
                                     |
                                     \-- 50% -- shocking grasp
That means that, when this fight_prog is triggered,
- there is 40% chance that the mob casts 'magic missile'
- and 60% chance that the mob does something else.

In these 60%, there are 2 options:
- 50% chance to cast lightning bolt
- 50% chance to cast shocking grasp

Code: Select all

/---------------------|----------------------------\
|        40 %         |            60 %            |
\---------------------|----------------------------/
    magic missile     /--------------|-------------\
                      |    50 %      |    50 %     |
                      \--------------|-------------/    
                       lightning bolt shocking grasp
So, finally, there is
- 40% chance for magic missile
- 30% chance for lightning bolt (50% of 60%)
- 30% chance for shocking grasp (the last 50% of 60%)

In your longer program above, you would have
- 10% for stone skin (90% left for the else part)
- 45% (50% of 90%) for magic missile (45% left for the second else part)
- 4.5% (10% of 45%) for shield (40.5% left for the third else part)
- 4.05% (10% of 40.5%) for armor (36.45% left for the fourth else part)
- 3.645% (10% of 36.45%) for bulls strength (32.803% left for the fifth else part)
- 3.2803% (10% of 32.803%) for fire shield (29.5247% left for last else part)
- 29.5247% for shocking grasp

All that sums up to "the numbers in rand() tests can be tricky".

For example, if you want a rand_prog with 4 options that all have the same chance of happening, you can't use

Code: Select all

if rand(25)
  option 1
else
  if rand(25)
    option 2
  else
    if rand(25)
      option 3
    else
      option 4
    endif
  endif
endif
Because that would make
- 25% for option 1 (75% left)
- 18.75% (25% of 75%) for option 2 (56.25% left)
- 14.0625% (25% of 56.25%) for option 3 (42.1875% left)
- 42.1875% for option 4

So, option 4 is very likely to be be chosen in this case. What you want is 25% for each of those options.
- So, rand(25) for option 1, and there's 75% left
- You want 25%, that is, 1/3rd of what is left, so you'll use rand(33) for option 2, then there's 50% left
- You want 25%, that is, 1/2 of what is left, so you'll use rand(50) for option 3

Code: Select all

if rand(25)
  option 1
else
  if rand(33)
    option 2
  else
    if rand(50)
      option 3
    else
      option 4
    endif
  endif
endif
That is not too surprising actually... option 1 is a one-in-four chance of happening, so 25%. If option 1 is NOT chosen, you only have 3 options left... so option 2 is a one-in-three chance of happening, rand(33). Then, if neither option1 nor option2 is chosen, you have only 2 options left, so option 3 is rand(50).
Dalvyn
Sword Grand Master
Sword Grand Master
Posts: 4708
Joined: Tue Jul 15, 2003 9:26 pm
Location: House of Wonder, Waterdeep

Post by Dalvyn » Wed Aug 06, 2003 12:48 am

For 2 options with the same chance to happen:

Code: Select all

if rand(50)
  option1
else
  option2
endif
For 3 options with the same chance to happen:

Code: Select all

if rand(33)
  option1
else
  if rand(50)
    option2
  else
    option3
  endif
endif
For 4 options with the same chance to happen:

Code: Select all

if rand(25)
  option1
else
  if rand(33)
    option 2
  else
    if rand(50)
      option3
    else
      option4
    endif
  endif
endif
The numbers for the rand checks are (from the most inner one to the most outer one): 50, 33, 25, 20, 17, 14, 12, ...
Dalvyn
Sword Grand Master
Sword Grand Master
Posts: 4708
Joined: Tue Jul 15, 2003 9:26 pm
Location: House of Wonder, Waterdeep

Re: Using imbricated rand checks

Post by Dalvyn » Mon May 25, 2009 4:14 pm

Bumping for a builder.

The correct link for the lesson is: http://www.forgottenkingdoms.org/builde ... dprogs.php
Image
Post Reply