Battle Analysis in Mathematica



(* Warlords II Combat Simulator *)
(* Bob Heeter, May 21, 1995 *)
(* Some assembly may be required! :)  *)

(* This is Mathematica source which allows you to determine the odds *)
(* for different events to occur in a Warlords II battle between *)
(* any two specified sets of units. *) 

(* Let each attacking and defending unit be labeled *)
(* A1, A2, ..., D1, D2, ...  and let each unit An, Dm, *)
(* have a strength value Hn, Hm. *)
(* Then we can define things: *)

(*Initialize these two lists with the strengths of the attacking *)
(*and defending stacks, taking all bonuses into account. Order is *)
(*the same as the fight order in Warlords II, i.e. peons first. *)

(*Attacker Status *)
(*Pattern: Att={A1,A2,A3,A4,A5,A6,A7,A8} (8 unit maximum) *)
Att={9,13}
(*Defender Status*)
(*Pattern: Def={D1,D2,D3,D4,D5,D6,D7,D8} (8 unit maximum) *)
Def={6,7,7,6,6,10}
(* The above example is for a strength 9 and 13 pair attacking *)
(* defenders with strengths 6, 7, 7, 6, 6, 10. *) 

(* The single-die-roll hit probabilities can be found easily: *)
(* Set Die to 24 for Intense Combat, 20 for normal combat. *)
Die = 20
(*Probability that, if An and Dm are fighting, *)
(* next hit is on Attacker: *)
Pa[An_,Dm_]:=(Dm/Die - (Dm/Die)*(An/Die))/
                         (An/Die + Dm/Die - 2*(An/Die)*(Dm/Die))
(*Probability that next hit is on Defender*)
Pd[An_,Dm_]:=(An/Die - (An/Die)*(Dm/Die))/
                         (An/Die + Dm/Die - 2*(An/Die)*(Dm/Die))


(* Now we can recursively determine the odds of a *) 
(* given battle being fought. *)

(* First specify that n and m are integers only. *)
n/: IntegerQ[n] = True
m/: IntegerQ[m] = True

(* Odds of battle between units An, Dm, with hit points Hn, Hm: *)
Clear[Bat]
Bat[n_,Hn_,m_,Hm_,Att,Def]:= Bat[n,Hn,m,Hm,Att,Def] = 
     Which[(Hn==2)&&(Hm==2),  
                  (Bat[n-1,1,m,2,Att,Def]*Pa[Att[[n-1]],Def[[m]]]
                  +Bat[n,2,m-1,1,Att,Def]*Pd[Att[[n]],Def[[m-1]]]),
           (Hn==2)&&(Hm==1),
                  (Bat[n-1,1,m,1,Att,Def]*Pa[Att[[n-1]],Def[[m]]]
                  +Bat[n,2,m,2,Att,Def]*Pd[Att[[n]],Def[[m]]]),
           (Hn==1)&&(Hm==2),
                  (Bat[n,2,m,2,Att,Def]*Pa[Att[[n]],Def[[m]]]
                  +Bat[n,1,m-1,1,Att,Def]*Pd[Att[[n]],Def[[m-1]]]),
           (Hn==1)&&(Hm==1),
                  (Bat[n,2,m,1,Att,Def]*Pa[Att[[n]],Def[[m]]]
                  +Bat[n,1,m,2,Att,Def]*Pd[Att[[n]],Def[[m]]]) ]
(* Trust me on this; it takes a long time to explain! *)

(* Need to throw in some boundary conditions to end recursion. *)
Bat[1,2,1,2,Att,Def] = 1 (* gotta start with the first 2 units *)
Bat[8,Ha_,0,Hd_,Att,Def] = 0
Bat[7,Ha_,0,Hd_,Att,Def] = 0
Bat[6,Ha_,0,Hd_,Att,Def] = 0
Bat[5,Ha_,0,Hd_,Att,Def] = 0
Bat[4,Ha_,0,Hd_,Att,Def] = 0 (* can't fight unit #0! *)
Bat[3,Ha_,0,Hd_,Att,Def] = 0
Bat[2,Ha_,0,Hd_,Att,Def] = 0
Bat[1,Ha_,0,Hd_,Att,Def] = 0
Bat[0,Ha_,0,Hd_,Att,Def] = 0
Bat[0,Ha_,1,Hd_,Att,Def] = 0
Bat[0,Ha_,2,Hd_,Att,Def] = 0
Bat[0,Ha_,3,Hd_,Att,Def] = 0
Bat[0,Ha_,4,Hd_,Att,Def] = 0
Bat[0,Ha_,5,Hd_,Att,Def] = 0
Bat[0,Ha_,6,Hd_,Att,Def] = 0
Bat[0,Ha_,7,Hd_,Att,Def] = 0
Bat[0,Ha_,8,Hd_,Att,Def] = 0



(* After plugging in for each stack, now just plug in *)
(* below the unit numbers you want to view fighting.  *)
(* Output is the odds that they battle with the given *)
(* number of hit points on each side: *)
(* i.e., enter Bat[Attacker#, Attacker Hit Points, 
                   Defender#, Defender Hit Points,Att,Def] *)
Bat[2,1,6,1,Att,Def]
(* This gives the odds of a wounded (strength 1) attacker *) 
(* unit 2 fighting a wounded defender unit 6.  i.e. the *)
(* strength 13 attacker in the example above is fighting *)
(* the strength 10 defender. *)
N[%]
(* Gives decimal result instead of exact rational number. *)

(* Generally we really want to know the probability that *)
(* a given unit survives to a given point in the battle. *)
(* Just plug in the n (p), m (q) for the units in question. *)
Clear[Sa]
Clear[Sb]
(* Templates: *)
(* Sa = Bat[n,2,m,1,Att,Def]*Pd[Att[[n]],Def[[m]]] *)
(*     +Bat[n,1,m,1,Att,Def]*Pd[Att[[n]],Def[[m]]] *)
(* Sa gives odds that unit n fights and beats unit m. *)
(* Sd = Bat[n,1,m,2,Att,Def]*Pa[Att[[n]],Def[[m]]] *)
(*     +Bat[n,1,m,1,Att,Def]*Pa[Att[[n]],Def[[m]]] *)
(* Sd gives odds that unit n fights and loses to unit m. *)

(* use p for n, q for m to avoid confusing Mathematica. *)
p = 2
q = 6
Sa = (Bat[p,2,q,1,Att,Def]*Pd[Att[[p]],Def[[q]]] 
    +Bat[p,1,q,1,Att,Def]*Pd[Att[[p]],Def[[q]]])
N[%]
Sd = (Bat[p,1,q,2,Att,Def]*Pa[Att[[p]],Def[[q]]] 
    +Bat[p,1,q,1,Att,Def]*Pa[Att[[p]],Def[[q]]]) 
N[%]

(* The example p=2, q=6 gives the odds (Sa) that the *)
(* attacker with strength 13 defeats the defender with *)
(* strength 10, and wins the battle. The total odds that *)
(* the attacker wins are the sum over all attacking units *)
(* of the survival odds Sa against the last defender. *)
(* Just run the simulator once for each possible surviving *)
(* attacker, and add up the probabilities.  In the example *)
(* above, you'd take the result for (p=2, q=6) and add *)
(* the result for (p=1, q=6). *)