@ Niara
Yeah, that 100 roll is crazy. It's the kind of ridiculous statline that I'm sure a DM would play around with and gently rib the player for having, spending the odd moment to describe how monsters and pawns alike are "in awe" or maybe even slightly infuriated of how chiseled and perfect the person is looking, whenever it can be fitted in. Maybe even making it a minor theme at some point that Mr Perfect is having a bad hair day and a runny nose.
I actually went back and peaked over the numbers a bit more and there are zero cases of three 18's. 935 rolls had a single 18, 29 had two. Chances of getting a character with actually three 18's and having those be in the right abilities and not ending up with ridiculous strenght values is horrible.
That being said, the chance to get a truly catastrophic roll is somewhat lower since just one roll of 5+ will essentially guarantee somewhat playable stats of at least 7 or more. Not getting a single 5+ with four dice is freaky. But of course it can happen and with strict rules you would be out of luck. You can have your 18 charisma warlock with 16 int and 17 con, but your dex is 3 and your strength is 4. That might be great fun at a table, it could lead to personal quests for a girdle of not being a weakling and maybe some elven gloves of not falling on your backside all the time. But would really anyone play that character in a video game?
However, if we consider the relaxation that Bioware decided on back in the day then it becomes very clear why it was so relatively easy to roll stat monsters in the Baldur's Gate games. If we can trade points between abilities after the roll then all that matters is the sum of dice. 297 out of 10000 rolls had a sum of 87 or more. That's roughly 3%, meaning that at 15 per minute, you'd almost certainly get a very good roll within 5-10 minutes.
Lastly, regarding cooking it up in Excel, it was indeed a bit finicky. I started out with a formula based approach, just put a randbetween(1, 6) in 24 columns, then using sum() of column 1 to 4 minus min() of column 1 to 4. And then 5-8, 9-12, 13-16, and so on. It worked but it was slow. Too many formulas needing calculation and something about formulas just rub me the wrong way. So I gave my lazy bone a swift kicking and wrote a macro instead. It isn't super optimized, but it gets the job done.
Sub RollCharacterStats(Optional ByVal lngRow As Long = 0)
Dim shOut As Worksheet
Dim arrDice() As Integer
Dim i As Integer, j As Integer
Dim intStat As Integer, intStatSum As Integer, intPointBuySum As Integer
Dim strDiceRolls As String
Dim blHas16 As Boolean, blHas18 As Boolean
Set shOut = ThisWorkbook.Sheets("4d6 drop lowest")
If lngRow = 0 Then lngRow = shOut.Cells(1000000, 1).End(xlUp).Row + 1
ReDim arrDice(1 To 4)
intStatSum = 0
intPointBuySum = 0
blHas16 = False
blHas18 = False
For i = 1 To 6
For j = 1 To 4
arrDice(j) = WorksheetFunction.RandBetween(1, 6)
shOut.Cells(lngRow, 13 + (i - 1) * 4 + j) = arrDice(j)
strDiceRolls = strDiceRolls & arrDice(j)
Next j
intStat = WorksheetFunction.Sum(arrDice(1), arrDice(2), arrDice(3), arrDice(4)) - WorksheetFunction.Min(arrDice(1), arrDice(2), arrDice(3), arrDice(4))
shOut.Cells(lngRow, i + 1) = intStat
intStatSum = intStatSum + intStat
strDiceRolls = strDiceRolls & " "
If intStat >= 16 Then blHas16 = True
If intStat >= 18 Then blHas18 = True
Next i
shOut.Cells(lngRow, 1) = lngRow - 6
shOut.Cells(lngRow, 8) = intStatSum
shOut.Cells(lngRow, 9) = Trim(strDiceRolls)
shOut.Cells(lngRow, 12) = blHas16
shOut.Cells(lngRow, 13) = blHas18
End Sub
Sub RollOnce()
Call RollCharacterStats
End Sub
Sub RollThousands()
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Application.ScreenUpdating = False
For i = 1 To 10000
Call RollCharacterStats
Next i
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub