About this program...
Here are the gory details of how math is used to calculate the exact theoretical
probability. (Version 5.40+ version)
We create a probabilistic finite state machine.
Each state is of the form
(life1, life2, halfTurnNumber, attacker, attackersLeft, attacksLeft, otherCrippled, attackDice, targettingSame,
negated, enemiesToAttack, smoked/skipTurn, (blasted1, blasted2), adjacentWolves, (limiteduse1,limiteduse2), numEngaged)
So Each state keeps track of:
- life1: number hit points or units left in player #1
- life2: number hit points or units left in player #2
- halfTurnNumber: This goes from 1 to 6, the half-turn number
- attacker: This is either 1 or 2, which player is attacking.
- attackersLeft: This is the number of figures yet to attack in this turn; this
is only relevant for squads
- attacksLeft: This is the number of attacks yet to be executed by the current attacking
figure; this is only relevant for Double Attack ability (or Triple Attack).
Note that you cannot lump attackersLeft and attacksLeft together because conceivably
you could have a squad of figures with multiple attacks and it is possible a figure
could be killed in the middle of its first attack.
- otherCrippled: This is 0 or 1. It is 1 if the other player has been crippled or EMPResponse activated,
with order markers removed, or Cloud of Darkness activated with turns skipped until your next turn.
- attackDice: This number keeps track of any attack modifier for this turn. For example,
this is used for Unleashed Fury, for Wait And Fire, Stinger Drain.
- targettingSame: This is 0 or 1. It is 1 after a figure has fired and the target
has not been destroyed. This is needed for Zettian Targetting bonus
- negated: This is 0, 1, or 2. This keeps track of whether abilities have been negated by the Rod
of negation. A 1 or 2 refers to which player has been negated. Note that both players cannot
be negated simultaneously.
- enemiesToAttack: This is used for the simplified ShaolinAttack ability.
This field should have value 0 or x, where x is the number of extra attacks the last
attacker gets; so only needed whether attackersLeft > 0.
-
smoked/skipTurn: For use with Smoke Powder. 0 = normal. 1 = smoked by defender and all normal attacks are skipped.
For use with Eternal Hatred or Stinger Drain, 0 = normal, 1 = skip rest of turn (i.e. no attacks).
-
blasted1 is the number of player2's unrevealed order markers that have been discarded,
blasted2 is the number of player1's unrevealed order markers that have been discarded,
- adjacentWolves is the number of Wolves of Badru that are adjacent; this is used for the Pounce ability.
-
limiteduse1 is the number of limited use weapons left for player1, such as Ullar's Bolt, WraithAttack drows.
limiteduse2 is the number of limited use weapons left for player2, such as Ullar's Bolt, WraithAttack drows.
- numEngaged: Keeps track of number of engaged figures for use with Engagement Strike and Ice Spikes.
- We may need to keep track of more stuff in the future, as more abilities are invented
- The states are given an arbitrary indexing. For efficiency, it is likely best to use
a hash (associative array) to assign a an index to each state.
There are also initial states and final states. There are 12 possible initial states, depending
on which halfTurn and which player starts up.
The final states keep track of who won, with how many hit points or units left.
After the list of states is made up,
a big transition matrix is built.
The rows and columns correspond to the states.
So the size is the number of states (which could be well over a thousand).
What is a transition matrix?
For each state State1, we calculate all the possible states that we can end up in
after one attack (one set of dice rolls, including any Chomp or Gaze).
The probability P that we land in state State2 is stored as an entry in the
transition matrix in row State1 and Column State2.
Call this transition matrix S. The part where we land in a final state is separated
out into a matrix T.
So S has dimension n x n and T has dimension n x m
where m is the number of final states, and n is the number of non-final states.
Here is the math theory calculation...
- So T gives us the matrix of probabilities of starting in any state and landing in a final state
after exactly 1 move.
- And ST (matrix multiplication!) gives us the matrix of probabilities of starting in any state and landing in a final state
after exactly 2 moves.
- And SST gives us the matrix of probabilities of starting in any state and landing in a final state
after exactly 3 moves.
- So the matrix of probabilities of starting in any state and landing in a final state
after any number of moves is
T + ST + SST + SSST + ....
an infinite sum.
- But this infinite sum simplifies into
(I + S + S^2 + S^3 +...) T
= (InverseMatrix(I - S)) T.
- Compute
Q = InverseMatrix(I - S)
- Then QT gives the matrix of probabilities of starting in any particular state
and eventually landing in any final state.
You use QT to compute the probability of a certain player winning, given that any particular
starting state.
You can also use QT to compute the average hit points or units left with a certain player
conditioned upon that player winning.
- And finally,
Q = I + S + S^2 + S^3 +...
gives the expected number of visits to each state, so that a sum across a row
would give the average number of moves (attacks) before landing in a final state.
And there you have it, that's how we compute the exact probabilities.
The tricky part in writing this program is generating the transition matrix.
The potential time consuming part is calculating the Q matrix because it
involves a matrix inversion.
Hooray for math.
How does the web interface work?
The Perl-CGI program reads the submitted form data,
and writes a Mathematica program. The Mathematica program is then
executed on the server and the Perl program sleeps while waiting for the Mathematica
program to finish.
The Perl program will also abort the Mathematica program if it takes too long
(defined to be 150 seconds).
Only one heroscape Mathematica program is allowed to execute at atime.