EDIT: User tussock revealed a
major error in my methodology. Leaving original post for historical reasons.
Later posts with more science:
The Effect of Equipment Material
The Effect of Weapon ChoiceThe Effect of Shield and Armor
Original post begins:You know all that received wisdom about military setup? Use blunt weapons for armored enemies, and slashing weapons for unarmored enemies? That iron is superior to copper, and steel to iron?
Yeah, you just keep thinking that.
This is a story about how I found out that everything we know is wrong. You want to know how to outfit your dwarves? At the end, you'll find out.
It started when I was looking at the Military Testing page on the wiki. I saw tests being run like "5 dwarves with adequate combat skills and iron equipment using battleaxes versus 5 similar dwarves using swords". Hey, I thought. I can contribute to that. So I started doing little tests.
My first tests were on the effect of skill. One question: "What skill level does a dwarf have to be in order to be able to beat two dwarves, similarly equipped, with no skill?" But my results were strangely inconsistent. Sometimes the Competent (III) dwarves fared better than the Skilled (IV) dwarves. That's strange. The experimental design is simple; maybe my sample sizes just weren't big enough.
So I started thinking bigger. I
rewrote the arena layout to comprise a grid of 9x9 cells, separated from each other, perfect for controlled combats.
Populating the arena by hand became too slow. I downloaded AutoHotKey, learned the syntax, and wrote scripts to duplicate dwarf layouts into many cells at the press of a hotkey. I was ready to get mass statistics. I would take all the wonderful variation possible in Dwarf Fortress's combat system, and through sheer weight of samples, beat out the noise and get the signal.
I tested the age-old debate of axe versus sword. I populated the arena with dwarves in full iron armor; one team with axes, another with swords. The results? Axe won 38%, sword won 62% of fights. Now that's a useful result! Next time goblinite comes calling, my dwarves will carry swords.
We also know that hammers are better than axes for fighting armored enemies- right? So I populated the arena with a team of axedwarves and a team of hammerdwarves. This time, axe won... 42% of fights, and hammers won... 58%. Well, hammers won, as we'd expect. But it's strange that swords would be better against full iron armor than hammers. After all, swords are supposed to be stopped by armor, but blunt weapons are specialized against armor.
Maybe swords are just better. Swords versus hammers, go! Swords win... 44%, hammers win 56%. That's strange- hammers win against swords; but swords win harder against axes than hammers do?
Let's re-establish that the combat system makes sense. A mirror match! One dwarf on each side, in a no-quarter battle to the death. With a large number of samples (>100), it should be very close to 50-50. The results were... 45% to 55%. That's funny. I would have expected the results to be closer.
Well, maybe the system is just noisy- prone to random error. What we need is more samples. I filled the entire arena, over 1,700 cells. In one corner, the iron-equipped axedwarves; in the other, iron-equipped hammerdwarves. With this massive sample size, we'll certainly eliminate the noise and get the signal. The results? Axedwarves win 54%, hammerdwarves win 46%.
Wait a second- axedwarves win? But last time, hammerdwarves won handily. The sample size is pretty massive- more than most dwarves most of us will send into battle over the entirety of our Dwarf Fortress career.
Well, let's do something that's sure to show results. There's debate over whether bronze or iron is better; but there's no debate about iron versus copper. Let's take dwarves of comparable skill, equipped entirely in iron or entirely in copper. The results? 97 to 96.
It's so close to 50-50, any respectable statistician would tell me that I fail at faking statistics. Only I didn't fake them.
You want to know how to outfit your dwarves? Outfit them in a way you think looks cool. Nothing else matters; not weapon type, not material type. The only effect will be on your imagination. Dress them to die in whatever way seems best to you.
Skills included:
Fighter
Axe/Sword/Hammer/etc.
Dodger
Shield User
Armor User
Discipline
Some tests varied skill level; but for tests mentioned above, testing equipment, all skills were at "Skilled" (IV) level.
Equipment:
Battle axe/Short sword/War hammer/etc.
1 breastplate
1 mail shirt
1 helm
1 pair of gauntlets
1 pair of high boots
1 pair of greaves
1 shield (of the same type of metal- not wood)
When material was not varied, all dwarves were equipped in iron.
Link to arena.txt.
AutoHotkey Script for populating arena:
numZ := 9
numX := 13
numY := 13
^q::
Loop, %numX%
{
Send, c
Send, {Enter}
Send, +{Right}
}
Loop, %numX%
{
Send, +{Left}
}
return
^e::
Loop, %numY%
{
Loop, %numX%
{
Send, c
Send, {Enter}
Send, +{Right}
}
Loop, %numX%
{
Send, +{Left}
}
Send, +{Down}
}
Loop, %numY%
{
Send, +{Up}
}
return
^r::
Loop, %numZ%
{
Send, <
}
Loop, %numZ%
{
Loop, %numY%
{
Loop, %numX%
{
Send, c
Send, {Enter}
Send, +{Right}
}
Loop, %numX%
{
Send, +{Left}
}
Send, +{Down}
}
Loop, %numY%
{
Send, +{Up}
}
Send, >
}
Loop, %numZ%
{
Send, <
}
return
Python 2.7 script for generating arena.txt:
class ArenaText:
def __init__( self, fileName = 'arena.txt' ):
self.fileName = fileName
self.cells = {}
self.levels = range( -4, 5 )
self.xVals = range( 144 )
self.yVals = range( 144 )
self.blank()
def blank( self ):
for z in self.levels:
for x in self.xVals:
for y in self.yVals:
self.cells[ ( z, x, y ) ] = 'P'
def setBox( self, z, startX, startY, widthX, widthY, char = '.' ):
for x in range( startX, startX + widthX ):
self.cells[ ( z, x, startY ) ] = char
self.cells[ ( z, x, startY + widthY ) ] = char
for y in range( startY, startY + widthY ):
self.cells[ ( z, startX, y ) ] = char
self.cells[ ( z, startX + widthX, y ) ] = char
def setSquare( self, z, startX, startY, widthX, widthY, char = '.' ):
for x in range( startX, startX + widthX ):
for y in range( startY, startY + widthY ):
self.cells[ ( z, x, y ) ] = char
def writeFile( self ):
fileLines = []
for z in self.levels:
fileLines.append( "Z=%s" % z )
for y in self.yVals:
yLine = ""
for x in self.xVals:
yLine += self.cells[ ( z, x, y ) ]
fileLines.append( yLine )
with open( self.fileName, 'w' ) as f:
fileText = "\n".join( fileLines )
f.write( fileText )
def writeBoxGrid( self, xSize, ySize, char = '.' ):
for z in self.levels:
endY = xSize + 1
while endY < self.yVals[-1]:
endX = xSize + 1
startY = endY - ySize
while endX < self.xVals[-1]:
startX = endX - xSize
self.setSquare( z, startX, startY, xSize, ySize )
endX += xSize + 1
endY += ySize + 1
at = ArenaText()
at.writeBoxGrid( 9, 9 )
at.writeFile()
print "All done!"