At first I had planned to do this whole big complicated set up. It would have been a state machine where the states would change based on locations of cities found and the AI I created would swarm it. That became harder as my time dwindled. The first challenge I faced was getting to understand the movement.
Now setting it up seemed easy, so easy i didn’t think I needed a class or struct. I learned fast I was wrong. Every time the AI ran, the variables reset and the unit would barely move. The unit would also turn to solely moving up. Now I learned I should build a class, so I started with a simple tracker of the direction. The code tended to start as an inline function which, upon realization, had to be much larger. The original direction tracker worked with an update or set direction function which would increase an integer that then began to enter a switch.
This was the start that eventually turned into a new function with a switch and some checks.
After trying this switch I realized I needed to improve. When this ran it was moving each unit in a square making little to no progress. So I tried a turn counter.
Now this idea could have been decent, but it just did the same thing. Instead of changing for each unit only once every three turns, the direction changed every three units. This was problematic. I took the knowledge from that and started a new try. The next attempt became a pretty solid idea.
The first step was a struct. This struct held the unit ID and the direction it was moving in. This seems simple, but the idea didn’t occur until a few hours working just because I already had a list of vectors, but this way the direction wouldn’t change as frequently.
The next step beside putting it all into a vector was to set up the movement. Now the movement went quickly after this. I realized what I had to do and worked off of that. My first attempt was a few if statements after setting the initial direction to invalid.
Once this was settled I needed to care if the unit was moving in a invalid way, and find a better water check. I focused on invalid first. This led to the discover of the getCellInDirection function. All I really did was take this, check if the returned value was valid and return it. Luckily the code base already had a default value that meant it wasn’t valid. That made the check fast and easy.
All of this ended setting the returning value equal to the current direction of the unit. The next bit was harder. I needed to find a way to ensure it didn’t enter water once it left. My cities only built armies so the water was dangerous territory. The first set up made it avoid all the water, once. The direction change easily led them back in but going a new way. After thinking for a while, I realized it would be faster and better to use a while loop.
The last step was a fix when it came to both movement and attacking.
Time to Attack
Now here was easy enough. The code base had some bug filled functions so a few plans had to be thrown away. I still hit the ground running. Realizing the code was bugged took a while and I couldn’t understand why they never attacked. I learned, they were never being given a direction to attack. When I realized this I went back to the original function call of attacking the nearest enemy, but added a twist.
My twist to this was updating the direction after the direction was set up. The code was simple and created a new method of searching to take control. The simple save of direction save a lot of time and energy for the game play.
The final piece of the AI puzzle was after everything was implemented and worst bug possible was found. If two of the same player’s units collided, the entirety of that player’s units froze until one was destroyed. This bug was harder to fix than I wanted it to be and took a few trial and error ideas to solve. Eventually I found the way I needed it to be. It had to check if any of the units were about to move into that spot where the get map cell in direction function helped once again. Checking the direction of other units and forcing a change helped fix the issue that was spawning, but unfortunately added a lot to decision time due to potential unit amounts.
This was the initial idea and it worked as I said before, but I disliked the time it took. After some time away I came back and realized, I only needed to check future units not the ones which had already moved. Not wanting to search for the ID again I recalled the position variable I created and used early on. It made fixing this much easier. The only thing this causes that goes against the play style is movement on to the water, but always preventing that could create endless loops so this method was safest.
Overall the AI works well where going up against someone else’s I manage to win a decent portion of the time with quite a large margin. In the picture I was player 1 who was the color yellow, labelled with my name on the top.