Come on, I didn't want to disrupt your programming or thought process. Just wanted to contribute my train of thought, sorry if I upset you in some way. If this is too disruptive for you, ignore what's following.
One does not simply randomly generate a random number generator.
Yes, you cannot *simply* write a customized random number generator, at least when you are not having function objects, clozures and the like. But well, you can just write a function like (sorry for the Lispy syntax, I guess you will be able to interpret it)
(custom-rng min max list-of-polynome-coefficients)
that rolls a random float between 0 and one and maps it via a polynome (or some other type of function, which might be better suited for example for being monotonously growing) to values between min and max. In Lisp I wouldn't do this with a list but with function objects, which, I guess, you don't have in Flash. If you have them, use them!
Nor would randomly generating the upper and lower bounds of the stats actually help, as they come in ratios. "Three of this is one of that, but this maxes twice as high as that," etc.
Ratios are also just values. You can choose them by hand, generate them randomly or evolve them. I don't see the problem, given that the computation I propose would be a one time thing as long as you don't change game mechanics (including AI, for that matter).
"How close to a triangle?" That requires running 3 tests and determining the direction of outcome for each, as well as the relative win strength for each fight.
And then trying to figure out what that means in terms of altering one or more units. Not to mention that the genome "code" itself referred to the random numbers, which while robust, didn't work well, as there was not enough mutation happening.
No, you misunderstood me, the rng should be constructed in a way that smoothly influences standard distribution and expected value. Those are the importand parameters, besides the maximum and minimum values, as described above. And crossing polynomials should give a fluent transition - that's all that counts!
"How close to a triangle?" is indeed a tough question, but when you answered it once you run the algorithm once for a while and then you have your parameters for ever and ever and ever, until you change some other rules. How much mutation is happening is just up to you. When you answered the question how to measure tictactoeness it's only the question of choosing the right population size and mutation and crossover rates. (Heck, you could even evolve those based on average improvement between generations, but I guess this is far out of the scope of your project.)
They're not being changed by hand. I don't know what this means.
As I understood a good chunk of this thread (sorry if I misunderstood, I am really awake for too long) you have problems finding boundaries and distributions for reasonable stats - you adjusted the rng for range iirc a few times and spend quite a while adjusting mapping between primary and derived attributes further. Either you do this by hand or you let a algorithm do this. You did (as I understand) the first, I propose the second.