Saturday, August 6, 2011

Modelling Axis and Allies

I've been trying to mathematically model an arbitrary Axis and Allies battle for a while now. Not having managed to do that, I went one lower, and taught my calculator to simulate the battles. I'm going to post the code.

Program: AXIS
{0,0,0,0,0}->AT2
{0,0,0,0,0,0}->DE2
0->WIN
Just setting up a couple variables here. Rather than individual units we list attacking units that fire at 1, 2, and so forth. The list also includes attack at zero for the first hit on battleships, for example. The Defense list has six entries, for the possibility of jet fighters defending at 5

Input "Attackers at zero:",A
Input "...at one:",B
Input "...at two:",C
Input "...at three:",DD
Input "and at four",E
{A,B,C,DD,E}->ATTACK
{A,B,C,DD,E}->AT1
Input "Defenders at zero:",A
Input "...at one:",B
Input "...at two:",C
Input "...at three:",DD
Input "...at four",E
Input "...and at five",F
{A,B,C,DD,E,F}->DEFENSE
{A,B,C,DD,E,F}->DE1

So, seeing as I"m doing this on my calculator, there are... interface issues. Basically I've got to express the question as a series of queries. The ABC variables can be ignored. "D" was used for something else important that I didn't want to mess with.

Input "Number of simulations",A
For(N,1,A)
ALLIES
"ALLIES" Is the command to run the eponymous program. After this is a bunch of stuff tallying results of a particular run of the battle.
[snip]
End

The specifics of tallying are moved to afterwards, where they'll make a bit more narrative sense. Moving on to the subroutine:

Program: ALLIES
0->HIT
0->DHIT
Clearing up some variables. From here there are going to be a number of nested loops, it's going to get complicated.
While (sum ATTACK)*(sum DEFENSE)>0
Recall from above that the sum of either list is the number of units on that side left on the battlefield. When one of them zeroes out the program ends.
For (M,2,5)
...makes sure what follows goes down each attack value of attacking units
For (O,0,ATTACK(M))
And this one does the operation for each individual attacking unit
If randInt(1,6)=HIT
Rolls one six sided die per unit, adding up the total number of hits.
End
End
Ends both for loops. We're still inside a while loop, and the for loop from the previous program. If you're keeping track, this is the attacker doing one round of attacking.
For(M,2,6)
For(O,0,DEFENSE(M))
If randInt(1,6)=DHIT
End
End
A mirror image of the attacker's code, with the usual exception for jet fighters. Note that casualties haven't been removed yet, so all defensive units in the casualty zone get their parting shot. Naturally, this means the model is invalid for submarines with first strike.
For (M,1,5)
If ATTACK(M))>DHIT
Then ATTACK(M)-DHIT->ATTACK(M)
0->DHIT
Else DHIT-ATTACK(M)->DHIT
0->ATTACK(M)
End
End
A more complicated equation, I'm separating it out a bit to make it more readable. Parse the logic if you like, basically it removes casualties while ensuring it never goes to negative numbers. The first End is for the If statement, the second for the For loop.
The defense has an identical loop, only with the variables DEFENSE for ATTACK and HIT for DHIT. Oh, and the For loop goes up to six.
End
And that's the finish of that While loop at the start of this program. If after a particular round of combat one or both armies is eliminated, the while loop triggers and we go back to the main program, to finish out that For loop.

If sum ATTACK>0 Then WIN+1->WIN

If there are still attackers at the end of the battle, the sum of the ATTACK list will be greater than zero; indicating the attacker took the country.

(Back to AXIS)
ATTACK+AT2->AT2
DEFENSE+DE2->DE2
AT1->ATTACK
DE1->DEFENSE

If any units survived on the invading side, they'll be expressed as integers in the ATTACK list. AT2 gives you a running sum of all the units that survive in each simulation. Same with DE2. The other two lines reset the lists to your original inputs before you go back for another jog through the loop. (Remember, this is all in the context of a For loop from above.)

Once the loop stops, once the simulation is run, we can tally up the results:
Disp (Win/A),(AT2/A),(DE2/A)
Stop
Hammertime
The first number you get is the percentage of the simulations where the attackers took the country. The second list gives you how many units the attacking army can expect to survive, and the third list is the expected survivors on the defense. Stop stops the program, so it never actually gets to the necessary sequel, which is a comment on the code. Or a comment on my taste in jokes.

And one general, vital question: Do I trust the results? In a word, no. I'm always suspicious of computer models in any situation, and I'm not convinced my logic is satisfactory in this case in particular. And even if my logic holds up this is still based on rolling a large number of dice; while you won't get too far away from the law of averages it's still an inexact predictor.

Yeah, ok, so we can't necessarily trust the results; what sort of results does the program give? Bad ones. By setting up a battle that can have only one outcome (attackers at zero, defenders not) I find the modeled results don't match up to reality. So it looks like I'm going to have to save this post, do some debugging and come back. Grr.

After saving this post, doing some debugging, and finally coming back, I don't have a solution. My logic is fine, as far as I can read it, so I'm not sure where the errors are creeping in. Even so, I'm lacking in content, so I'll post this now and maybe give you an update if I ever figure out where I'm going wrong.

No comments:

Post a Comment