was it actually the reason?
It was fairly simple to get significant performance gains (without changing AI behavior or results) just by applying straight forward changes. Eliminating macro's hiding chained method calls. Saving the result of nested calls, e.g. save a pointer to the game map instead of making the same call repeatedly in a tight loop.
There's a huge difference between "premature optimization" and just sloppy coding. Too many take the idea too far that the (C++) optimizer is better than you'll ever be and that you should let it do it's job. Yes, the optimizer is/can be very good and can make surprising and unintuitive changes to make code faster. But, it's not a miracle worker. Optimizers work best on clear, concise, code with minimal data dependencies.
FWIW, back on my Core I2 Duo, a single late-game turn on a huge map could take upwards of 30 minutes to complete, most of that spent in AI's turns. I was able to get it down to about 5 minutes without too much effort. Along the way, RAM usage also plummeted. If I had full access to the source, I could have made even greater gains that would have broken the DLL ABI...
Sadly, I never released my changes anywhere (and I only had local SVN at the time), and they haven't survived my PC upgrades since.
There was an article [0] and subsequent discussion on HN [1] about reverse engineering and patching the binaries.
[0] https://nee.lv/2021/02/28/How-I-cut-GTA-Online-loading-times...
It's really not in the same vein as using bubblesort instead of a mergesort: failures aren't in algorithm design but in the actual mechanics of the implementation that is ancillary to the algorithm itself.
tl:dr; O(n^2) string parsing and O(n^2) duplicate removal