Developing a Base-Building AI From the Top Down

This is the place to request new mods or give ideas about what could be done.
Post Reply
0111narwhalz
Burner Inserter
Burner Inserter
Posts: 7
Joined: Tue Nov 01, 2016 3:35 pm
Contact:

Developing a Base-Building AI From the Top Down

Post by 0111narwhalz »

Over the course of this thread, I plan to construct a mod from the extremely abstract to the nitty-gritty. I'll be using pseudocode so that, should I be successful, it should be a relatively trivial matter to "port" it to game-ready real code.

The first step in this process is the most abstract: defining what I want the mod to be. I want to build an AI mod.
What does that mean? Well, I want an AI that will acquire resources and processes them. I want the acquisition to happen concurrently with the processing. I'll formalize this:

Code: Select all

//In thread 0:
while(true)
{
 AcquireResources();
}
//In thread 1:
while(true)
{
 ProcessResources();
}
Each of these "modules" is bound to get rather complex on its own, so I'll only look at one at a time. For now, I'll focus on the acquisition module.
How does a player acquire resources? First he must decide that he needs them; next he must find them; then he must mine or pump them; and finally he must bring them home.

Code: Select all

void AcquireResources()
{
 Resource[] neededResources = AnalyzeResourceNeeds();
 Vector2[] positions = FindResources(neededResources);
 Mine(positions);
 Transport(positions, homePosition);
}
Now, we have a new target. How does a player decide which resources he needs? The usual way I do is to look at the empty feed lines—in essence, finding the supply bottlenecks. He might do this by finding which resources have too many consumers compared to their producers. Because the things that can be mined are only the "primary resources" (e.g. ores), the acquisition module should consider only these.

Code: Select all

Resource[] AnalyzeResourceNeeds()
{
 Resource[] requiredResources;
 foreach(Resource res in primaryResources)
 {
  if(CalculateConsumers(res) >= CalculateProduction(res))
  {
   requiredResources.Add(res);
  }
 }
 return requiredResources;
}
Calculation of consumers and producers should be relatively simple.

Code: Select all

double CalculateConsumers(Resource res)
{
 double consumption;
 foreach(Processor proc in processors)
 {
  if(proc.recipe.ingredients.ContainsKey(res))
  {
   consumption += proc.recipe.ingredients[res] / proc.recipe.time;
  }
 }
 return consumption;
}

Code: Select all

double CalculateProducers(Resource res)
{
 double production
 foreach(Processor proc in processors)
 {
  if(proc.recipe.products.ContainsKey(res))
  {
   production += proc.recipe.products[res] / proc.recipe.time;
  }
 }
 return production;
}
I've taken some liberties in assuming that somewhere there's a list of all processors (assemblers, furnaces, and extractors) somewhere, but hypothetically it shouldn't be hard to generate such a list. Especially if the AI as a whole keeps a record of its processors. For now, though, we're going to leave this rabbit-hole where it is and move on to the next submodule.
How might a player find resources? He might first check the map to search for promising ore patches above a certain size and, should he find none, expand his radar range.

Code: Select all

Vector2[] FindResources(Resource[] neededResources)
{
 Vector2[] positions;
 foreach(Resource res in neededResources)
 {
  if(BestOrePatch(res).amount > minimumExploitationSetpoint)
  {
   positions.Add(BestOrePatch(res).position);
  }else
  {
   ExpandRadarCoverage();
  }
 }
 return positions;
}
—————————————————
I still have an awful lot to do, and the actual placement of blueprint ghosts will be a daunting task, but it's a good start. I'll update the spoiler below with the pseudocode developed in future updates.
The Code So Far

Post Reply

Return to “Ideas and Requests For Mods”