• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Where to start with creating AI

Level 14
Joined
Oct 16, 2010
Messages
749
Hi,

I'd like to look at creating an AI for my map, however I'm not sure I know where to start....so here I am!

My map is an autobattler where you have a single "shop" unit that gets given random units you can then buy, the units are removed from the shop when you buy them and you then can reroll for more units, you can lock/unlock your shop so the units are held across rounds. The units are automatically rolled at the start of each round.
The units you buy are copied at the start of the round and compete against other players. You can move the units freely in your zone to change the formation of your team.

The units have special faction/trait bonuses which give you bonuses for having more of the same type of units (Orc's gain extra damage and health for example)

There's a lot of different aspects to think about with creating computer players for this map...so yeah not been a great a start already!! Here's my list of things that the computer would need to be able to do...

1. Buy units - as I'm using a merchant shop style system I can't make them train or build anything, so I would have to simulate the purchasing side of it.
2. Read their unit roll - there are 4 slots available so they would need to "read" their roll to see if anything is worth buying. This to could be to improve their team, or counter an opponents team. (So they need to be able to read their own team and possibly other player's teams?)
3. Position their team - there's quite a large area you are given to move units, there isn't any terrain to worry about or anything like that but there is probably more to it than just "melee in front, range in back". For example their is an assassin trait that makes you units teleport to the back line of the enemy at the start of the round, the best counter so far to this is to move your units to the back. In the same vain you can move your assassins to try and counter this too.
4. Upgrade units - Each unit has 3 tiers, with increasing gold and food costs. I guess this works with reading their unit roll? They would need to decide whether to spend their gold/food on a new unit or upgrading one they already have

I think that covers the "basics" of it... the most complicated bit that I'm looking at is (2). Each player has a different unit group for each different faction/trait so those are "readable" but translating that into something the computer can use as logic...is confusing me just thinking about it!!

Any suggestions of how to get this going would be much appreciated!
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,876
0. First and foremost, you should have a database which contains information about every single Unit-Type available to be purchased as well as data about Player's decisions so far. A Hashtable as the database would be ideal if you plan to stick with GUI. Integers can be used to create "Weighted" stats which you can use to determine the AI's next course of action. They could also serve useful to determine each player's "random" rolls if you wanted some pseudo-rng. So for example a Footman has a 2 for it's Ground stat, a 0 for it's Air stat, a 2 for it's Anti-Ground stat, a 0 for it's Anti-Air stat, and a 4 for it's Affordability stat. Each player would accumulate these values after purchasing a unit, and the AI can use these values to determine what it's lacking or to see what it's opponent has which could influence it's final decision.

IE:
My opponent has an Air stat of 20, this new Anti-Air unit I have available is considered high priority.
My opponent has an Anti-Air stat of 0, this new Air unit I have available is considered high priority.
I have low resources, this high Affordability unit is considered high priority.

1. Separate the unit purchasing logic from the Event(s) that fire it:
  • Shop Purchased Unit
    • Events
      • Unit - A unit Sells a unit
    • Conditions
    • Actions
      • Set Variable Shop_Unit_Type = (Unit-type of (Sold unit))
      • Set Variable Shop_Player = (Owner of (Sold unit))
      • Set Variable Shop_PN = (Player number of Shop_Player)
      • -------- Handle any other generic User-buys-a-unit logic --------
      • Unit - Remove (Sold unit) from the game
      • Trigger - Run Shop Register Purchased Unit (ignoring conditions)
  • Shop Register Purchased Unit
    • Events
    • Conditions
    • Actions
      • Unit - Create 1 Shop_Unit_Type for Shop_Player at Shop_Point[Shop_PN] facing default degrees
      • -------- Store it in a Unit Group, store it's Shop_Unit_Type in a database, etc... --------
      • If all conditions are true then do (Actions)
        • If - Conditions
          • Is_Computer[Shop_PN] Equal to True
        • Then - Actions
          • ...
        • Else - Actions
          • ...
So all you have to do is Set those Shop_ variables before running the Shop Register Purchased Unit trigger and you can simulate the purchasing of a Unit. Variables like Shop_Point would be set at the start of the game when Players are being setup. You should be able to plug a PN variable into an Array or as the Parent Key in a Hashtable to get each Player's Shop, Unit Group, Unit-Types purchased, etc.

2. Refer back to #0, and reference the data that each Player has stored. Comparing Integers is easy enough to find which has the highest value and thus the highest priority. If it's turn 1, have some special exception since nothing has been established yet and just have the CPU choose something affordable and good against Ground or whatever is most common.

3. Create your own Grid logic which allows swapping and moving of units without collisions. Tiles on the grid can be designated as Front, Middle, Back, and the AI can make decisions based on this. Grids are not a very complicated concept, two For Loops which handle the Rows (X) and the Columns (Y) along with a database that maps these using Integers, ie: Grid[0,0] represents a Tile in the bottom left corner. Grid[2,0] represents two tiles to the right of it. You could reverse the grid so that Grid[0,0] represents a Tile in the bottom right corner for the opposite team, if say Team 1 was on the left side of the map and Team 2 was on the right side. Or however way you want to manage it, whatever makes sense to you.

4. Same or similar to #2. I don't fully understand what you mean by this "upgrade". But I suppose you could have Weighted stats that tell you information about the unit's upgrade choices. Maybe look at how many units the CPU has (food supply or unit count) and use that as a determining factor. I would need more information on how these upgrades work to give a concrete answer.
 
Last edited:
Level 14
Joined
Oct 16, 2010
Messages
749
0. I think I understand what you mean by this as I think I have attempted this in a previous map. My map doesn't have any ground/air unit differences and attack/armor types aren't a thing. So it's more the unit designs themselves plus the faction/traits that create their "value" for or against different things if that makes sense?

Example - Fighter classes tend to be strong against Ranger classes, so these would be "preferable" to buy against opponents with lots of Rangers? And then also the player with the Rangers would find it "preferable" to purchase something to protect their Rangers (in my map the Brawler or Protector classes?).

So would you suggest something like a Anti-Ranger stat and Ranger stat for example?

1. I think I've got this part already working, so I should be able to add the SHOP stuff and a run trigger bit onto the 2 triggers I already have

2. I'm currently storing the unit-types themselves for each player individually for each roll, so I have an Integer Array with 4 spaces per player, these 4 are filled when you do a roll and are cleared when you buy units or re-roll. I was currently just checking them in numerical order (slot 1, slot 2, etc). So at the moment they will pick the first unit that "fits" even if a better unit is further in the roll, how do I deal with this?

3. Would this require lots of regions or?

4. By upgrade I mean like upgrading a tower from Scout to Guard, you can upgrade all the units twice at a cost of gold and food to make them stronger. The AI ideally would need to work out whether it is better to save gold/food for an upgrade or to buy a new unit. I guess I could get them to check the rolls, I guess I would need to decide whether they check units for upgrades first or check the roll first?
 

Uncle

Warcraft Moderator
Level 73
Joined
Aug 10, 2018
Messages
7,876
0. I think I understand what you mean by this as I think I have attempted this in a previous map. My map doesn't have any ground/air unit differences and attack/armor types aren't a thing. So it's more the unit designs themselves plus the faction/traits that create their "value" for or against different things if that makes sense?

Example - Fighter classes tend to be strong against Ranger classes, so these would be "preferable" to buy against opponents with lots of Rangers? And then also the player with the Rangers would find it "preferable" to purchase something to protect their Rangers (in my map the Brawler or Protector classes?).

So would you suggest something like a Anti-Ranger stat and Ranger stat for example?

1. I think I've got this part already working, so I should be able to add the SHOP stuff and a run trigger bit onto the 2 triggers I already have

2. I'm currently storing the unit-types themselves for each player individually for each roll, so I have an Integer Array with 4 spaces per player, these 4 are filled when you do a roll and are cleared when you buy units or re-roll. I was currently just checking them in numerical order (slot 1, slot 2, etc). So at the moment they will pick the first unit that "fits" even if a better unit is further in the roll, how do I deal with this?

3. Would this require lots of regions or?

4. By upgrade I mean like upgrading a tower from Scout to Guard, you can upgrade all the units twice at a cost of gold and food to make them stronger. The AI ideally would need to work out whether it is better to save gold/food for an upgrade or to buy a new unit. I guess I could get them to check the rolls, I guess I would need to decide whether they check units for upgrades first or check the roll first?
0. Yes, you're just comparing values. Larger number = The player has more of something. If a CPU sees that their opponent has a large number of Rangers then it will try to prefer Fighters.

1. Sounds good, it shouldn't be too difficult to separate the logic with clever use of Variables + Run Trigger.

2. That's a good approach. You can then Loop over the Array, tally up the values contained for each Unit-Type (get this information from the database), then compare these values afterwards. This is something you'll want to experiment with as the complexity will vary depending on how "smart" you want your AI to be. I would aim for somewhere in the middle, where the AI is smart enough to avoid the objectively worst choice, but at the same time makes "random" decisions. An AI that is too predictable can be boring and... predictable. Your AI-decision-making trigger would likely use a lot of: Integer arrays, For Loops, and If Then Else statements.

3. No Regions are necessary, although you may want to use one Region to represent a starting point. A Grid is just a collection of Point variables that are mapped to a pair of Integers. A Hashtable would handle this nicely with the Parent Key representing the X row and the Child Key representing the Y columns. Here's a 10x10 Grid:
  • Set Variable Start_Point = (Center of Grid_Start_Region[PN])
  • Set Variable X = 0.00
  • Set Variable Y = 0.00
  • For each Integer ROW from 1 to 10 do (Actions)
    • Loop - Actions
      • For each Integer COL from 1 to 10 do (Actions)
        • Loop - Actions
          • Set Variable Grid_Point = (Start_Point offset by Y towards 90.00 degrees)
          • Hashtable - Save Grid_Point as COL of ROW in Grid_Hashtable[PN]
          • Set Variable Y = (Y + 128.00)
      • Set Variable X = (X + 128.00)
      • Custom script: call RemoveLocation( udg_Start_Point )
      • Set Variable Start_Point = ((Center of Grid_Start_Region[PN]) offset by X towards 0.00 degrees)
Now you can Load these Points easily:
  • Set Variable Grid_Point = (Load 1 of 1 from Grid_Hashtable[PN]
  • Unit - Create 1 Footman for Player 1 (Red) at Grid_Point facing default degrees
  • -------- Do NOT remove this location! It's meant to be permanent. --------
^ That'll get you a position centered at the first "Tile" created in the Grid, which in my example was the bottom left corner. You can adjust the X/Y values and the Grid_StarT_Region[] to build the grid any way you'd like.

4. I see, you'll have to figure out what's more important most of the time. To simplify things, upgrading could be a mostly RNG type of thing unless the CPU has run out of food, then it could take priority as the only decision the CPU makes. Again, you can tally up data for these Unit-Types and compare these Integer values to come to a decision.

The final design should be that as long as you have reference to a Unit-Type then you will also have access to ALL of it's information -> Fighter, Ranger, etc. Look into the methods used to determine the Greatest or Least value, I've definitely posted some examples on Hive in the past, especially for how to Get the "closest unit" which uses the same logic.
 
Last edited:
Top