This is awesome! I've been thinking about how to tackle this problem analytically since the PMFs for any given action are pretty well specified. However, this script saves me so much work that I had to stop lurking just to remark.

Any rate, one way you could avoid the "casters get creamed" problem with your target picking algorithm is to make a directed graph of who is putting damage where. Each character would be a node on the graph and the connectivity would represent where their attacks were headed each turn. This could simulate a "front rank" and "back rank" by requiring that nodes be adjacent to attack each other with melee attacks. Similarly, the model could incorporate shoving, attacks of opportunity and other attempts to block bodies by updating the graph connectivity based on some actions that individual actors pick. For instance, casting misty step could let you skip past a rank and become adjacent to ranged attackers.

I'll play around with this and see if I can codify the graph thing.