I was fiddling around and wrote a monte carlo sim for all 4 fighter fighting styles in Python.
It takes the arguments:
nrolls - number of times to run the sim. For example 100000 would be the same as sitting down and recording the results of a 100000 attack rounds.
apr - this is the number of attacks the fighter has in a round (for twf it adds in the extra attack)
cn - critical hit number. For the starter set martial archetype this is 20 at 1st level, 19 at 3rd level, 18, at 15th level.
pn - proficiency bonus
an - ability bonus
ac - target AC you are attacking
ndice - number of dice your weapon has
dicetype - dice type your weapon uses
It returns:
h - number of hits
t - total damage
a - average damage per round
Code:
import random
def dicesim_gwf(nrolls, apr, cn, pn, an, ac, ndice, dicetype):
t = 0
h = 0
for i in range(nrolls): # repeat N experiments
for j in range(apr):
att = 0
matt = 0
att = random.randint(1,20)
matt = att+pn+an
if matt >= ac:
h = h+1
t = t+an
if att >= cn:
for k in range(ndice): #critroll 1
r = random.randint(1, dicetype) # roll die dicetype
if r <= 2: # reroll 1 or 2
r = random.randint(1, dicetype)
t = t+r
for l in range(ndice): #critroll 2
r = random.randint(1, dicetype) # roll die dicetype
if r <= 2: # reroll 1 or 2
r = random.randint(1, dicetype)
t = t+r
else:
for m in range(ndice):
r = random.randint(1, dicetype) # roll die dicetype
if r <= 2: # reroll 1 or 2
r = random.randint(1, dicetype)
t = t+r
a = float(t)/nrolls # average dpr
return h,t,a
def dicesim_twf(nrolls, apr, cn, pn, an, ac, ndice, dicetype):
t = 0
h = 0
for i in range(nrolls): # repeat N experiments
for j in range(apr+1):
att = 0
matt = 0
att = random.randint(1,20)
matt = att+pn+an
if matt >= ac:
h = h+1
t = t+an
if att >= cn:
for k in range(ndice): #critroll 1
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
for l in range(ndice): #critroll 2
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
else:
for m in range(ndice):
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
a = float(t)/nrolls # average dpr
return h,t,a
def dicesim_arch(nrolls, apr, cn, pn, an, ac, ndice, dicetype):
t = 0
h = 0
for i in range(nrolls): # repeat N experiments
for j in range(apr):
att = 0
matt = 0
att = random.randint(1,20)
matt = att+pn+an+2
if matt >= ac:
h = h+1
t = t+an
if att >= cn:
for k in range(ndice): #critroll 1
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
for l in range(ndice): #critroll 2
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
else:
for m in range(ndice):
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
a = float(t)/nrolls # average dpr
return h,t,a
def dicesim_duel(nrolls, apr, cn, pn, an, ac, ndice, dicetype):
t = 0
h = 0
for i in range(nrolls): # repeat N experiments
for j in range(apr):
att = 0
matt = 0
att = random.randint(1,20)
matt = att+pn+an
if matt >= ac:
h = h+1
t = t+an+2
if att >= cn:
for k in range(ndice): #critroll 1
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
for l in range(ndice): #critroll 2
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
else:
for m in range(ndice):
r = random.randint(1, dicetype) # roll die dicetype
t = t+r
a = float(t)/nrolls # average dpr
return h,t,a
Output 1st level:
>>> dicesim_duel(100000,1,20,2,3,14,1,8)
(59802, 590842, 5.90842)
>>> dicesim_arch(100000,1,20,2,3,14,1,10)
(69995, 622456, 6.22456)
>>> dicesim_twf(100000,1,20,2,3,14,1,6)
(119667, 813139, 8.13139)
>>> dicesim_gwf(100000,1,20,2,3,14,2,6)
(59745, 718465, 7.18465)
Output 3rd Level:
>>> dicesim_duel(100000,1,19,2,3,14,1,8)
(60419, 619405, 6.19405)
>>> dicesim_arch(100000,1,19,2,3,14,1,10)
(69815, 646214, 6.46214)
>>> dicesim_twf(100000,1,19,2,3,14,1,6)
(119790, 849033, 8.49033)
>>> dicesim_gwf(100000,1,19,2,3,14,2,6)
(59976, 762115, 7.62115)
Output 5th Level:
>>> dicesim_duel(100000,2,19,3,4,16,1,8)
(120056, 1352018, 13.52018)
>>> dicesim_arch(100000,2,19,3,4,16,1,8)
(140024, 1280541, 12.80541)
>>> dicesim_twf(100000,2,19,3,4,16,1,6)
(180287, 1457079, 14.57079)
>>> dicesim_gwf(100000,2,19,3,4,16,2,6)
(120257, 1651104, 16.51104)
Output 11th Level:
>>> dicesim_duel(100000,3,19,4,5,18,1,8)
(180125, 2206257, 22.06257)
>>> dicesim_arch(100000,3,19,4,5,18,1,8)
(210257, 2133683, 21.33683)
>>> dicesim_twf(100000,3,19,4,5,18,1,6)
(239982, 2179882, 21.79882)
>>> dicesim_gwf(100000,3,19,4,5,18,2,6)
(179996, 2651385, 26.51385)
I would say that the 11th level numbers are the fuzziest as you may very well be fighting mobs with less than 18 AC and you may have a magical item and/or a feat which will skew these numbers.
Python is free and easy to install if you want to play around with your own inputs or change the code.
TLDR: The Op is correct Fighter 1-4 does the most damage with TWF until 5th level where the fighter does the most damage with GWF. Outstanding wildcards that could change this recommendation are feats and magical weapons.