BTW, this can be accomplished in many ways. The best way, in my opinion, is to use a lock-step movement strategy with threaded events. It would work like this:
Each AI runs in its own thread.
Each AI builds a list of all units that have moves left and puts them in a priority queue.
Each AI picks the top unit and checks all adjacent spaces to see if there is an attack target in one of them.
If no attack target is found, it moves to an empty square based on any pre-calculated path and strategy information. Then, it gets placed back into the priority queue with normal priority if it has moves left.
If an attack target is found, an attack decision is made. If no attack will occur, it moves into a free adjacent square and gets put back into the priority queue with normal priority if it has moves left.
If an attack takes place, the units involved are given a "waiting" priority and put back into the priority queue (at the end) and a thread is spawned to handle the entire battle. This thread may spawn other threads, depending on how multi-threaded you want each battle. When the battle thread finishes, it marks the two units involved as normal priority.
The AI thread keeps looping through these unit movements until all non-waiting units have been processed. Once it has only waiting units left, it basically just sleeps until one of the units is freed up. Then movement of those units commences.
Each time through the loop, if an AI detects that an attack is possible by the unit being inspected, it locks a mutex that will halt all AI threads when they finish moving their current piece. Each AI thread would have its own mutex to lock and all AI threads would check the mutexes of all other AI threads and synchronize on a single global mutex before starting their next iteration through the loop. This way, any time there is a battle possibility, those participating in the possible battle can be strictly ordered to ensure only one of them makes the move to attack, with each one getting the chance to make that move, without worrying about whether another AI will move a unit into the same area and run into a possible battle with the same pieces while one is unresolved. This forces a deterministic resolution of battle possibilities.
Since the video updating thread would run separately from the AI threads, you could see several AI pieces moving on the screen all at once just like a real-time strategy game. However, it is all still coordinated in turns. In addition, each AI would have the ability to re-decide strategy or path information after each unit moved one space. Further, it prevents two fast moving units from completely bypassing each other and completely missing each other because one took all their movement points and then the other did the same. By moving one square at a time, you would actually encounter the opposing pieces and have the ability to decide on a war.
Slotting the human player into the orchestrated movement would be easy or difficult, depending on how you want to do things. If you want them slotted in, you could have the user pick their path for the unit and not actually move the unit until they hit next turn. Then, if it crossed paths with another unit during AI movement, you could stop everything and wait for the human to resolve things by either moving past the AI unit or attacking it. That would draw-out next turn actions, but would be more realistic. Or, you could take the easy route and just let players take all their moves at once. You could even make it a game option!
But this would give you multi-threaded AI that could be computed across potentially dozens of processor cores. In addition, putting the sleep statements in the code would allow you to tout "green gaming".