# Wargame Tank Simulation

Some of you may have heard of the Wargame series of computer based real time strategy game. These games pit teams of players with primarily cold war era units to see how a hot cold war would have played out. The goal of this challenge is to simulate a tank battle in these games.

Input

• Two "tanks" (one red and one blue) will be entered into your program or function. Each tank is classified by a rate of fire, accuracy, armor value, and attack power value.

Challenge

From the inputs above, simulate the two tanks fighting. You will do this by having each tank fire according to its rate of fire. If it hits (randomly determined by accuracy), a tank will do damage according to the armor value of its target and its own attack power. The formula for damage is floor[(attackpower - armor)/2]. Therefore a tank with 10 attack power against a tank with 5 armor would do 2 damage.

Tank crews also have morale, which follows the following rule

• There are four possible morale values; calm, worried, scared, and panicked. Tanks always start calm. These names do not need to be in your code, in the sample below I've used calm = 1, worried = 2, etc.
• Each morale value reduces the accuracy as follows: Calm -> 100% (no change), worried -> 75%, scared -> 50%, panicked -> 25%. Therefore a panicked tank which normally has 60% accuracy now has 0.25 * 0.6 = 15% accuracy
• Each hit by the opposing tank degrades morale by one level, each miss upgrades the morale by one level.

For example:

morale: calm  |  worried  |  calm  |  worried  |  scared
hit:         hit         miss     hit         hit


Rules:

• Input should be two parameters to repesent each tank (I've used two tuples in the example below). Inputs may be provided in any order, just be sure to state which one is which. Input may be provided by user input via STDIN, read from a file, or parameters passed to a function call.
• Each tank starts with 10 health.
• Rate of fire will either be 8.5, 7.5, 6.5, 6, 5, or 3 seconds between shots.
• Tanks start loaded, so each fires at time = 0. Because Communists are sneaky, red fires first.
• Accuracy must be randomly rolled.
• Ineffective hits (hits which do no damage) have an effect on morale! (because it probably sounds terrifying)
• Naturally since we want to see the action, output will be an update after each shot. The update will contain the time of the shot, whom it was made by (red or blue), health of both tanks, and the morale of both tank crews. Output maybe be presented in any format so long as it contains all of the required information in a human readable fashion (items must be delimited in some way). Similar to input, please describe your output format in the answer.
• Engagements are limited to 100 seconds. If you play the game you know this is because a plane has swooped in by then. For our purposes if both tanks are alive at this point, it is a draw.
• After one tank reaches 0 health (or after 100 seconds), print which tank is victorious ("Red" or "Blue") or "Draw" if appropriate. I don't care about trailing whitespace or newlines.
• Printing output may be printing to STDOUT or writing to a file
• Shortest answer in bytes wins

Sample Python Implementation

This is a little sample I worked up to demonstrate some of the methodology. It takes the two tanks as tuples to the main() function, then outputs a nice little table. Your output does not need to be so fancy. For the curious, it's 1,930 bytes. You can do better.

Sample Tanks:

Some tanks to use for you, the numbers are ROF, accuracy, armor, and power.

• T-72A: 8.5, 45%, 12, 16
• T-72BU: 8.5, 55%, 22, 23
• T-80: 7.5, 40%, 14, 16
• T-80U: 7.5, 60%, 20, 23
• M1 Abrams: 7.5, 55%, 16, 18
• M1A2 Abrams: 7.5, 60%, 22, 24
• Leclerc: 6, 65%, 20, 20
• STRV-103D: 5, 60%, 18, 16
• Zhalo (I know, not a tank): 3, 60%, 2, 18
• How do half second rates of fire work? – Morgan Thrapp Mar 28 '16 at 17:55
• It's not really rate of fire, but time in between shots. So 8.5 corresponds to about 7 rounds per minute – wnnmaw Mar 28 '16 at 17:59
• Right, but each round is a second right? Should a tank with 8.5 fire on 0, 9, 17, 25, etc? – Morgan Thrapp Mar 28 '16 at 18:00
• Nice new name. But no, they fire on exact values, so 0, 8.5, 17, etc. Check out the sample output in the python reference case – wnnmaw Mar 28 '16 at 18:02
• I see what you're getting at now. In the sample implementation, I pre-computed all of the shot times. You could simulate actual time step however as you are suggesting. In this case you are free to select whatever time step you want, so long as you don't miss any shots – wnnmaw Mar 28 '16 at 18:10

# Python 3, 465

Saved 8 bytes thanks to wnnmaw.
Saved 34 bytes thanks to DSM.

Expects tanks as lists as follows, [Rate of Fire, Accuracy, Armor, Attack]

from random import*
def f(r,b):
r+=10,1;b+=10,1
for x in range(200):
if r[4]<1:return"Blue"
if b[4]<1:return"Red"
if x%int(r[0]*2)<1:
if random()>=(r[1]*r[5]):b[4]-=(r[3]-b[2])//2;b[5]-=(b[5]!=0.25)/4
else:b[5]+=(b[5]<1)/4
print('r,%f,%d,%f,%d,%f'%(x/2,*r[4:],*b[4:]))
if x%int(b[0]*2)<1:
if random()>=(b[1]*b[5]):r[4]-=(b[3]-r[2])//2;r[5]-=(r[5]!=0.25)/4
else:r[5]+=(r[5]<1)/4
print('b,%f,%d,%f,%d,%f'%(x/2,*r[4:],*b[4:]))
return"Draw"


Prints the output as Attacker,TimeOfShot,RedHealth,RedMorale,BlueHealth,BlueMorale. Morale is represented as a float.

• You can save 9 bytes with from random import* – wnnmaw Mar 28 '16 at 18:23
• If you use Python 2 you can save some bytes by using tabs as 2nd and 3rrd intendation level. It might also be worth it to get the input via input() and not using a function. This way you get rid of one intendation level. – Denker Mar 28 '16 at 18:26
• @DenkerAffe I'd lose the ability to splat in the format string (plus I don't have 2 installed). – Morgan Thrapp Mar 28 '16 at 18:27
• You can save some by changing instances of 0.25 to 1/4, since this is Python 3. – Hannes Karppila Mar 28 '16 at 22:11
• You could probably save some bytes by moving the ¼ factor into the random calculation. – Neil Mar 29 '16 at 8:39