Skip to content

Calculate exact battle outcome probabilities using a bayesian network approach.

License

Notifications You must be signed in to change notification settings

jimlischeske/BayesianAxisAlliesCalculator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

BayesianAxisAlliesCalculator

This program calculates combat outcome probabilities for Axis and Allies battles. Most of the available calculators online do Monte Carlo simulation, where each battle is simulated (using a random number generator in place of dice rolls) many times, and a count of each result is listed. In contrast, this work takes a bayesian approach, calculating the absolute probability of a node given the probability of its descendence from its parents and the absolute probability of its parents.

How it works

To understand the algorithm, consider a simple example, where two infantry units attack two defending infantry. At the beginning, the frontier is populated by a single node, containing a list of the attacking units and a list of the defending units. This node has no parents. When the node is popped, it's absolute probability of occuence is calculated (because this node is the root/has no parents, its probability is simply 1), and its children are produced, along with the probability that each child would descend from its parent.

For this example, the attacker may manage 0, 1, or 2 hits, and the defender may also manage 0, 1, or 2 hits. Children are generated by each permutation of hits, except for the permutation where both the attacker and defender achieve no hits (so as to avoid infinite recursion). Thus, with (x,y) where x is the number of remaining attacking infantry, and y is the number of remaining defending infantry, the children are, (2,1), (2,0), (1,2), (1,1), (1,0), (0,2), (0,1), and (0,0).

Note that, because there are equal numbers on each side, every node possible in this network is created by expanding the very first node.

These nodes are instantiated with a list of parents, which is at this point simply the root node, along with the probability of descent from that parent. For example, the child (2,1) depends on the attacker hitting one, and the defender hitting zero, normalized by the probability that someone hits. The probability of one attacking hit is (1/6)(5/6)(2c1)=5/18, and the probability of no defenders hitting is (2/3)^2 = 4/9. Thus, the probability of this node's descent from the root node is (5/18)*(4/9)/(1 - (5/6)^2 * (2/3)^2) = (10/36)/(1-100/324) = 0.1786.

Child nodes are sorted by their size, then placed in the frontier for expansion according to their size, so that larger nodes are expanded first.

Now consider the expansion of (2,1). First, its absolute probability is calculated. The absolute probability is the sum of the product of the conditional probabilities from each parent multiplied by the absolute probability of its parent's occurence:

p(c) = sum( p(c|p_i) * p(p_i) )

Because this node has only one parent (the root node), its probabilty is 0.1786*1.

Next, the children are expanded. Child nodes are (2,0), (1,1), and (1,0). As each of these nodes have already been instantiated, (2,1) is appended to the parent list of each, along with the probability that each of these children would descend from this node.

This brings us to an important feature of Axis and Allies: by sorting the frontier by total units, we can be sure that we do not exclude any valid parents from any node, because a node's parent must have more units than itself.

This continues on through (1,2), (1,1), (2,0), (0,2), (1,0), (0,1) and (0,0), at which point the simulation will have completed. The probabilities of the terminal nodes are summed to verify that they add up to 1 within some tolerance, and then the simulation is completed.

Testing, Verification, and Performance

This was verified against pen and paper for several small battles (e.g. 2 inf att. 1 inf), and the outcomes from larger battles were compared to outputs from Monte Carlo calculators available online (calc.axisandallies.org). In all cases, this calculator gave apparently correct answers.

This calculator appears to perform in O(m^2 n^2) (where m is the number of attackers and n is the number of defenders). This could be be improved by concentrating the search step for each child.

That said, for singlet simulations of reasonable-sized battles, this calculator is probably "fast enough". For example, a battle of 30 infantry attacking 30 infantry (about as large a battle as you'll see in a typical game) completes in approximately 30s. This is probably sufficient for an individual player interested in understanding the distribution of probable outcomes from an attack or defense.

Of course, an implementation in python is prima facie not performance focused. If the use case required iterative calls to this function (e.g. machine learning), it would have to be refactored in c++ or something similar.

Future improvements

  • Pre-combat is not yet implemented (anti-air, shore-bombardments)
  • Naval battles
  • Alternate hit-allocation methods

About

Calculate exact battle outcome probabilities using a bayesian network approach.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages