Through this tutorial, you will build a Protoss agent capable of train zealots and sentry units step by step.

Juan Pablo Aboytes Novoa
7 min readNov 6, 2020

System requirements

  • PySC2 2.0 framework installed
  • Basic Python programming skills
  • Python 2.7 or above installed.

1.- Import base_agent, sc2_env, actions, features, units, random and app from Abseil Python for agent and environment settings.

2.- Define the step function: Is an inherited method from the parent class BaseAgent, the first parameter is the subclass and the second refers to an instance of ProtossAgent.

3.- Build the environment: Here you use the sc2_env, base_agent and features imports.

Define the agent as ProtossAgent, then the while true is a loop that is going to be happening until we press the keyboard, the game will be playing by itself.

Inside sc2_env.SC2Env you can define the map that you want to use, remember that you should have the Melee maps installed and you have it inside a folder named “Maps” in the Starcraft2 folder.

In this case the map is Simple64…

After we chose the map we need to define the players, first we define the player that will be our agent and then the bot. In this case we chose Protoss as our agent race and the bot is going to be a random race.

Next you need to decide the difficulty, in this case is very_easy but it can be to select very_easy, easy, medium, medium_hard, harder, very_hard, cheat_vision, cheat_money, and cheat_insane.

Then we can specify the resolution for the screen. The values in this case are 84 and 64 pixels.

step_mul is a variable that simulates the gamespeed and the action performed after that number of gamesteps

game_steps_per_episode defines the length of the game length. In this case we put 0 because we want to wait until we win o we lose.

with visualize you can see detailed information of the environment.

Next you reset the agent and the timesteps, the timesteps are relevant when you define a maximum steps per game.

5.- Helper functions

This functions are going to be make the things easy, so let’s see each function.

In the __init__ function define the constructor for class ProtossAgent class, then we define to none our first pylon and the attack coordinates, we are going to assign the values later.

The function unit_type_is_selected checks if the input unit is selected, it can be a single or multiple select.

get_units_by_type is a function that returns a list with instances of the input unit.

can_do is a function to check if the input action is available
For example, when you have a Gateway and a CyberneticsCore you unlock the Sentry unit, after you build Cybernetic Core when you click the Gateway the can_do will show you that you can use “actions.FUNCTIONS.Train_Sentry_quick” that it means that you can train a Sentry unit.

6.- Step function: Here you define the actions that the agent is going to do, so let’s see each part of the corde.

First you need to define the xmean and ymean in order to define the player coordinate, so if the xmean ≤ 31 and y ≤ 31 it means that the player is at the top side of the map and you need to define attack_coordinates to the bot side of the map, else the player is at the bot side of the map.

Next we define a minerals to know how many minerals we have and not using the obs.observation.player.minerals all the time and the same happens with the vespene variable.

Build Pylons

As you may know you need to have space for your army, so that’s why we are going to make 4 pylons (remember that we defined a first pylon before)

First declare a pylons variable as we did with the minerals and vespene in order to acess to the list elements that are the pylons built. The first if is to check if we already have 4 pylons built and we have ≥100 minerals that is the cost to build the pylon, next you check if a Probe is selected, then you check if you can build the pylon with the can_do function. The x and y value are the possible values, this possible values are the screen that is in the scene and then you return de action of build the pylon at the random x and y value.

Build gateways and assimilators

The gateways are the building where you can generate the zealots and the sentry and the assimilators are the building where you can harvest the vespene gas.

First define de gates variable that is going to be a list of Gateway objects, then the first if checks if we have 2 gateways built and ≥ 150 minerals that is the cost of the building, then you check if a probe is selected, the last if is to check if the probe can do the building. It returns an action that builds the gateway at the random x and y.

Define a gas variable that is going to be a list of Assimilator objects, then check if we already have 2 gates, ≥ 75 minerals and we have no Assimilators built, then check if a probe is selected, the last if is to check if the probe can do the building. It returns an action that builds the gateway at the random x and y.

Build Cybernetics Core

The cybernetics core inlocks the sentry unit at the gateway, so you need to build at least 1.

Same steps, define the cybernetic variable, check if you have 2 gateways and ≥ 150 minerals and there is no cybernetics core built.

Train units Zealots and Sentrys

After you get minerals, the buildings and the vespene you can start training units!

First check if you have 2 gateways and ≥100 minerals, then check if a gateway selected,if not, select a random gateway, next in this case i decided to limit the number of zealots to 7 for each gateway so if ≤7 then check if you can train a Zealot, it returns an action that is train a Zealot.

Same happens with the Sentry units, checks if a cybernetic core is built and ≥ 100 vespene and ≥50 minerals but i decided to generate just 1 at the time at the gateways.

Probe units

If Probe units are not selected it will not be possible to build any building. Add the instruction to select them in case previous actions were not performed.

ATTACK!

Here we are going to send the units to attack, remember that we already defined the sentry and zealot lists and the we already built all we need.

First check if we have ≥ 7 zealots trained, then checks if all the units selected are zealots, if not it will selected the zealots, then check if you can send the attack and it returns the attack action to the attack_coordinates that we defined at the beginning.

Same thing happens with sentry units but just 1 sentry trained.

At this point you can run the code and see how it works, the enemy is going to surrender and will show you the output of 1 in the command line, that means that your agent won and got the reward +1.

The code is here

References:

--

--