-----------------------------------------------------
The ntc.AI Probability Machine
-----------------------------------------------------

Introduction
---------------------
This is a simple probability machine.  Although it's easy to simulate this on
your own, putting it in  its own object like this - a kind of black box - may
make things cleaner.

A probability machine is an object that chooses any number of choices based
on the probability of each.  For example, it might be given two choices - heads
or tails - each with a probability of 0.5.  Then you can instruct it to choose a
choice - it will do so based on the probabilities given.  So you could feed it three
choices with the following respective probabilities:
  0.5
  0.25
  0.25
And you can expect with relative certainty that 1 and 2 will be chosen with
approximately the same frequency but 0 will be chosen twice as much.


Usage
---------------------
The probability machine is a regular object, complete with constructor and
destructor.  It's inside of the ntc.AI.pm namespace, so first you would do
  #Include "ntc/pm.bas"
  Using ntc.AI.pm

To create a probability machine:
  Dim As pmObject probMachine = pmObject()

Then simply add the respective probabilities.  For example, if you want the
probability machine to act like a six-sided die, you would add six times (1/6):
  Const diceProb As Double = 1/6
  probMachine.addChoice(diceProb)
  probMachine.addChoice(diceProb)
  probMachine.addChoice(diceProb)
  probMachine.addChoice(diceProb)
  probMachine.addChoice(diceProb)
  probMachine.addChoice(diceProb)
You can add choices at any time, so the behaviour of the probability machine
can change.

You can at any time remove a specific probability - remember that the indexes
are 0-based, so the second choice is marked 1 and so on:
  probMachine.removeChoice(1)

You can also change a probability:
  probMachine.changeChoice(1, 0.2)

In case you need to check, you can find the current probability of a choice:
  Print probMachine.probabilityOf(0)

And you can find out how many choices there are:
  Print probMachine.numChoices

If you want to remove all the choices in the table, use
  probMachine.resetpTable()
and then add more choices.

When you're ready to choose - say, roll the die - use the following code:
  Print probMachine.choose()
The function probMachine.choose() returns a number between 0 and the
number of choices you've added, inclusive - but of course depending on the
probabilities you assign each choice any of these might be excluded (if you
give a 0 probability to a choice, that choice will never be chosen;  if your
probabilities sum to 1, any probabilities over 1 will never be chosen, and the
default choice will never be chosen).

The probability machine protects itself with a mutex, so it is fully
thread-safe.



Notes
---------------------
Like most things random, the probability machine uses FreeBASIC's Rnd
function.  Thus, the results will be the same every time unless you use
"Randomize Timer" at the beginning of your program.

Normally probabilities should sum to 1;  if any choices are added after the
total cumulative probability sums to 1, those choices will never be chosen.
You can also give any choice a probability of 0 and it will never be chosen.
Probabilities are checked in the order added, so if the first five probabilities sum
to 1 or greater, the sixth will never be chosen at all.  Also, if you have two
choices both with 1 probability, only the first will ever be chosen.

Note that if the probabilities are less than 1, an extra default choice is
automatically present which is given the remaining probability.  This
keeps things consistent, so for example if you don't add any choices at
all then choice 0 will receive a 100% chance so it will be returned every time.
Since the choices are 0 based, the probabilities you add are from choice 0 to
the number of choices you've added minus one.  The default choice is the
number of choices you've added.

For example, if you added the following probabilities:
  0.1
  0.2
  0.3
Then 0 would have a 10% chance of being chosen each time, 1 would have a
20% chance, 2 would have a 30% chance, and 3 (the default choice) would get
the leftover - in this case, 60%.  This is something very important to remember,
as all kinds of bugs may occur if you forget about the default choice.  On the
other hand, it can be very helpful for creating an "other" option - as in
Select Case or If blocks where you check for certain values and all other
values fall under the "Else" clause.  Likewise here you add certain
probabilities for specific values and everything else falls under the default
choice.

It's very important to keep track of your probabilities - remember if they don't
sum to 1, unexpected behaviour can occur.