Commit 582f74c7 authored by m1ndgames's avatar m1ndgames

update

parent 24ee2f64
......@@ -3,6 +3,8 @@ import random
import os
import configparser
from pathlib import Path
from collections import Counter
class GameManager():
def __init__(self, bot=None):
......@@ -41,6 +43,9 @@ class GameManager():
self.bot.data_attacktime = None
self.bot.data_attackunits = None
self.bot.data_race_strategy = None
self.terran_strategies = []
self.protoss_strategies = []
self.zerg_strategies = []
self.bot.not_squadunit = []
self.bot.not_commanderunit = []
......@@ -50,13 +55,6 @@ class GameManager():
else:
_ = os.system('clear')
async def savedata(self, data):
if self.bot.opponent_id:
datafile = "./data/" + str(self.bot.opponent_id) + ".db"
file = open(datafile, "a+")
file.write(data)
file.close()
async def readdata(self, id):
botdata = configparser.ConfigParser()
botdata.read("./data/" + id + ".db")
......@@ -70,6 +68,92 @@ class GameManager():
if botdata.has_option(str(self.bot.race_self), "strategy"):
self.bot.data_race_strategy = botdata.get(str(self.bot.race_self), 'strategy')
async def updatestats(self, result):
#if self.bot.opponent_id:
if not os.path.isfile('./data/stats.txt'):
Path('./data/stats.txt').touch()
newstats = configparser.ConfigParser()
newstats.read('./data/stats.txt')
newstats.add_section('Stats')
newstats.set('Stats', 'gamecount', "0")
newstats.set('Stats', 'wins', "0")
newstats.set('Stats', 'losses', "0")
newstats.set('Stats', 'ties', "0")
newstats.add_section('Terran')
newstats.set('Terran', 'gamecount', "0")
newstats.set('Terran', 'wins', "0")
newstats.set('Terran', 'losses', "0")
newstats.set('Terran', 'ties', "0")
newstats.add_section('Zerg')
newstats.set('Zerg', 'gamecount', "0")
newstats.set('Zerg', 'wins', "0")
newstats.set('Zerg', 'losses', "0")
newstats.set('Zerg', 'ties', "0")
newstats.add_section('Protoss')
newstats.set('Protoss', 'gamecount', "0")
newstats.set('Protoss', 'wins', "0")
newstats.set('Protoss', 'losses', "0")
newstats.set('Protoss', 'ties', "0")
with open('./data/stats.txt', 'w') as statsfile:
newstats.write(statsfile)
for file in os.listdir("./data"):
if file.endswith(".db"):
datafile = "./data/" + file
botdata = configparser.ConfigParser()
botdata.read(datafile)
if botdata.has_option("Terran", "strategy"):
terran_strategy = botdata.get('Terran', 'strategy')
self.terran_strategies.append(terran_strategy)
if botdata.has_option("Protoss", "strategy"):
protoss_strategy = botdata.get('Protoss', 'strategy')
self.protoss_strategies.append(protoss_strategy)
if botdata.has_option("Zerg", "strategy"):
zerg_strategy = botdata.get('Zerg', 'strategy')
self.zerg_strategies.append(zerg_strategy)
terran_strategy_occurence = Counter(self.terran_strategies).most_common(1)
protoss_strategy_occurence = Counter(self.protoss_strategies).most_common(1)
zerg_strategy_occurence = Counter(self.zerg_strategies).most_common(1)
statsupdate = configparser.ConfigParser()
statsupdate.read('./data/stats.txt')
statsgamecount = statsupdate.get('Stats', 'gamecount')
newgamecount = int(statsgamecount) + 1
statsupdate.set('Stats', 'gamecount', str(newgamecount))
statsracegamecount = statsupdate.get(str(self.bot.race_self), 'gamecount')
newracegamecount = int(statsracegamecount) + 1
statsupdate.set(str(self.bot.race_self), 'gamecount', str(newracegamecount))
if terran_strategy_occurence:
statsupdate.set('Terran', 'best_strategy', str(terran_strategy_occurence[0][0]))
if protoss_strategy_occurence:
statsupdate.set('Protoss', 'best_strategy', str(protoss_strategy_occurence[0][0]))
if zerg_strategy_occurence:
statsupdate.set('Zerg', 'best_strategy', str(zerg_strategy_occurence[0][0]))
if result == Result.Victory:
wingamecount = statsupdate.get(str(self.bot.race_self), 'wins')
newwingamecount = int(wingamecount) + 1
statsupdate.set(str(self.bot.race_self), 'wins', str(newwingamecount))
elif result == Result.Defeat:
defeatgamecount = statsupdate.get(str(self.bot.race_self), 'losses')
newdefeatgamecount = int(defeatgamecount) + 1
statsupdate.set(str(self.bot.race_self), 'losses', str(newdefeatgamecount))
elif result == Result.Tie:
tiegamecount = statsupdate.get(str(self.bot.race_self), 'ties')
newtiegamecount = int(tiegamecount) + 1
statsupdate.set(str(self.bot.race_self), 'ties', str(newtiegamecount))
with open('./data/stats.txt', 'w') as statsfile:
statsupdate.write(statsfile)
async def startGame(self):
if not self.bot.real_time and self.bot.last_game_loop == self.bot.state.game_loop:
self.bot.real_time = True
......
......@@ -29,6 +29,9 @@ class m1ndb0t(sc2.BotAI):
self.showstatus = False
self.printdebug = True
# Chat
self.usechat = True
async def on_start(self):
await self.gamemanager.startGame()
......@@ -78,3 +81,4 @@ class m1ndb0t(sc2.BotAI):
async def on_end(self, game_result):
await self.warmanager.savewinningstrategy(game_result)
await self.gamemanager.updatestats(game_result)
import random
import os
import configparser
from strategies.protoss.StalkerRush import *
from strategies.protoss.ZealotRush import *
from strategies.protoss.SkyToss import *
......@@ -30,6 +32,13 @@ class ProtossManager():
'DarkTemplar': DarkTemplar(self.bot)
}
# DEBUG Overrides
# self.bot.strategy = StalkerRush(self.bot)
# self.bot.strategy = ZealotRush(self.bot)
# self.bot.strategy = SkyToss(self.bot)
# self.bot.strategy = DarkTemplar(self.bot)
# return
if self.bot.data_race_strategy in strategies:
self.bot.strategy = strategies[self.bot.data_race_strategy]
print("Using strategy: " + str(self.bot.strategy))
......@@ -37,9 +46,3 @@ class ProtossManager():
print("No Data - Picking random strategy")
self.bot.strategy = random.choice(list(strategies.values()))
print("Using strategy:" + str(self.bot.strategy))
# DEBUG Overrides
# self.strategy = StalkerRush(self.bot)
# self.strategy = ZealotRush(self.bot)
# self.strategy = SkyToss(self.bot)
# self.strategy = DarkTemplar(self.bot)
......@@ -4,7 +4,7 @@ from sc2 import Race, Difficulty
from sc2.player import Bot, Computer
from m1ndb0t import m1ndb0t
bot = Bot(Race.Random, m1ndb0t())
bot = Bot(Race.Zerg, m1ndb0t())
# Start game
if __name__ == '__main__':
......
......@@ -6,17 +6,20 @@ class DarkTemplar:
"""Protoss DarkTemplar"""
def __init__(self, bot=None):
self.bot = bot
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
async def Run(self):
"""Runs on every GameStep"""
self.bot.current_strategy = 'DarkTemplar'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
if self.bot.iteration == 1:
self.bot.current_strategy = 'DarkTemplar'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: DarkTemplar", team_only=False)
await self.Macro()
await self.Micro()
......@@ -42,12 +45,8 @@ class DarkTemplar:
await self.bot.unitmanager.createUnit("DarkTemplar", 100)
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 300:
await self.bot.warmanager.scout()
# Check if expansion is needed
if (self.bot.units(race_worker[self.bot.race]).ready.amount / 1.1) >= self.bot.neededworkers:
......
......@@ -7,7 +7,6 @@ class SkyToss:
def __init__(self, bot=None):
self.bot = bot
self.ramp_supply_built = False
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
......@@ -15,12 +14,16 @@ class SkyToss:
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'SkyToss'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
self.bot.not_squadunit.extend([UnitTypeId.ADEPT, UnitTypeId.INTERCEPTOR])
self.bot.not_commanderunit.extend([UnitTypeId.ADEPT, UnitTypeId.MOTHERSHIP, UnitTypeId.INTERCEPTOR])
self.bot.current_strategy = 'SkyToss'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: SkyToss", team_only=False)
if int(self.bot.time) <= 360:
self.bot.attack_count = 5
......@@ -46,12 +49,8 @@ class SkyToss:
await self.bot.unitmanager.createUnit("Mothership", 1)
await self.bot.unitmanager.createUnit("Tempest", 3)
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 330:
await self.bot.warmanager.scout()
# Check if expansion is needed
if (self.bot.units(race_worker[self.bot.race]).ready.amount / 1.1) >= self.bot.neededworkers:
......
......@@ -10,7 +10,6 @@ class StalkerRush:
self.bot = bot
self.ramp_supply_built = False
self.coreboosted = None
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
......@@ -18,11 +17,15 @@ class StalkerRush:
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'StalkerRush'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
self.bot.not_commanderunit.append(UnitTypeId.SENTRY)
self.bot.current_strategy = 'StalkerRush'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: StalkerRush", team_only=False)
if int(self.bot.time) <= 360:
self.bot.attack_count = 5
......@@ -61,12 +64,8 @@ class StalkerRush:
if self.bot.units(UnitTypeId.STALKER).amount >= 5:
await self.bot.unitmanager.createUnit("Sentry", 3)
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 120:
await self.bot.warmanager.scout()
# Check if expansion is needed
if (self.bot.units(race_worker[self.bot.race]).ready.amount / 1.1) >= self.bot.neededworkers:
......
......@@ -6,17 +6,20 @@ class ZealotRush:
"""Protoss ZealotRush"""
def __init__(self, bot=None):
self.bot = bot
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
async def Run(self):
"""Runs on every GameStep"""
self.bot.current_strategy = 'ZealotRush'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
if self.bot.iteration == 1:
self.bot.current_strategy = 'ZealotRush'
self.bot.squadsize = 10
self.bot.attack_count = 1
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: ZealotRush", team_only=False)
await self.Macro()
await self.Micro()
......@@ -33,12 +36,8 @@ class ZealotRush:
await self.bot.unitmanager.createUnit("Zealot", 100)
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 120:
await self.bot.warmanager.scout()
# Check if expansion is needed
if (self.bot.units(race_worker[self.bot.race]).ready.amount / 1.1) >= self.bot.neededworkers:
......
......@@ -14,10 +14,14 @@ class MarineRush:
async def Run(self):
"""Runs on every GameStep"""
self.bot.attack_count = 10
self.bot.retreat_count = 2
self.bot.current_strategy = 'MarineRush'
self.bot.squadsize = 10
if self.bot.iteration == 1:
self.bot.attack_count = 10
self.bot.retreat_count = 2
self.bot.current_strategy = 'MarineRush'
self.bot.squadsize = 10
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: MarineRush", team_only=False)
await self.Macro()
await self.Micro()
......@@ -25,8 +29,8 @@ class MarineRush:
async def Macro(self):
"""Macro Routine"""
#if not self.bot.structures(race_gas[self.bot.race]):
# await self.bot.ressources.createGas()
if not self.bot.structures(race_gas[self.bot.race]):
await self.bot.ressources.createGas()
# await self.bot.unitmanager.createUnit("Medivac", 3)
await self.createWall()
......
......@@ -6,7 +6,6 @@ class BanelingSpam:
"""Zerg BanelingSpam"""
def __init__(self, bot=None):
self.bot = bot
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
......@@ -14,12 +13,16 @@ class BanelingSpam:
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'BanelingSpam'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
self.bot.not_squadunit.append(UnitTypeId.QUEEN)
self.bot.not_commanderunit.append(UnitTypeId.QUEEN)
self.bot.current_strategy = 'BanelingSpam'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: BanelingSpam", team_only=False)
await self.Macro()
await self.Micro()
......@@ -43,12 +46,8 @@ class BanelingSpam:
await self.bot.warmanager.expand()
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 120:
await self.bot.warmanager.scout()
async def Micro(self):
# zergling
......@@ -73,6 +72,7 @@ class BanelingSpam:
distance2enemy = zergling.position.distance_to(next_enemy.position)
if distance2enemy < 20:
self.bot.do(zergling.attack(next_enemy))
break
structures = self.bot.enemy_structures
if structures and not enemies:
......@@ -92,6 +92,7 @@ class BanelingSpam:
distance2structure = zergling.position.distance_to(next_structure.position)
if distance2structure < 20:
self.bot.do(zergling.attack(next_structure))
break
# baneling
banelings = self.bot.units(UnitTypeId.BANELING).ready
......@@ -115,6 +116,7 @@ class BanelingSpam:
distance2enemy = baneling.position.distance_to(next_enemy.position)
if distance2enemy < 20:
self.bot.do(baneling.attack(next_enemy))
break
structures = self.bot.enemy_structures
if structures and not enemies:
......@@ -134,10 +136,12 @@ class BanelingSpam:
distance2structure = baneling.position.distance_to(next_structure.position)
if distance2structure < 20:
self.bot.do(baneling.attack(next_structure))
if distance2structure <= 3:
break
if distance2structure <= 2:
abilities = await self.bot.get_available_abilities(baneling)
if AbilityId.EXPLODE_EXPLODE in abilities:
self.bot.do(baneling(AbilityId.EXPLODE_EXPLODE))
break
# queen
queens = self.bot.units(UnitTypeId.QUEEN).ready
......
......@@ -6,7 +6,6 @@ class MutaliskRush:
"""Zerg MutaliskRush"""
def __init__(self, bot=None):
self.bot = bot
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
......@@ -14,12 +13,16 @@ class MutaliskRush:
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'MutaliskRush'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 3
self.bot.not_squadunit.append(UnitTypeId.QUEEN)
self.bot.not_commanderunit.append(UnitTypeId.QUEEN)
self.bot.current_strategy = 'MutaliskRush'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 3
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: MutaliskRush", team_only=False)
await self.Macro()
await self.Micro()
......@@ -39,12 +42,8 @@ class MutaliskRush:
if self.bot.units(UnitTypeId.MUTALISK):
await self.bot.warmanager.expand()
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 330:
await self.bot.warmanager.scout()
async def Micro(self):
# mutalisk
......@@ -52,7 +51,7 @@ class MutaliskRush:
if mutalisks:
for mutalisk in mutalisks:
if self.bot.commandertarget:
if mutalisk.position.distance_to(self.bot.commandertarget.position) <= 10 and mutalisk.tag != self.bot.commander:
if mutalisk.position.distance_to(self.bot.commandertarget.position) <= 15 and mutalisk.tag != self.bot.commander:
self.bot.do(mutalisk.attack(self.bot.commandertarget))
else:
enemies = self.bot.enemy_units
......@@ -72,11 +71,13 @@ class MutaliskRush:
break
distance2enemy = mutalisk.position.distance_to(next_enemy.position)
if distance2enemy < 20:
if distance2enemy < 30:
self.bot.do(mutalisk.attack(next_enemy))
break
if distance2enemy <= 3:
moveposition = mutalisk.position.towards(next_enemy.position, -1)
self.bot.do(mutalisk.move(moveposition))
break
structures = self.bot.enemy_structures
if structures and not enemies:
......@@ -94,11 +95,13 @@ class MutaliskRush:
break
distance2structure = mutalisk.position.distance_to(next_structure.position)
if distance2structure < 20:
if distance2structure < 30:
self.bot.do(mutalisk.attack(next_structure))
break
if distance2structure <= 3:
moveposition = mutalisk.position.towards(next_structure.position, -1)
self.bot.do(mutalisk.move(moveposition))
break
# queen
queens = self.bot.units(UnitTypeId.QUEEN).ready
......
from sc2.constants import *
from sc2 import race_worker
from sc2 import race_gas
class RoachSpam:
"""Zerg RoachSpam"""
def __init__(self, bot=None):
self.bot = bot
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'RoachSpam'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
self.bot.not_squadunit.append(UnitTypeId.QUEEN)
self.bot.not_commanderunit.append(UnitTypeId.QUEEN)
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: RoachSpam", team_only=False)
await self.Macro()
await self.Micro()
async def Macro(self):
"""Macro Routine"""
await self.bot.unitmanager.createUnit("Roach", 100)
roachs = self.bot.units(UnitTypeId.ROACH).ready
if self.bot.vespene <= 300:
await self.bot.ressources.createGas()
if self.bot.townhalls.ready.amount >= 3:
await self.bot.unitmanager.createUnit("Queen", self.bot.townhalls.ready.amount)
await self.bot.warmanager.expand()
if self.bot.time >= 300:
await self.bot.warmanager.scout()
async def Micro(self):
# Roach
roachs = self.bot.units(UnitTypeId.ROACH).ready
if roachs:
for roach in roachs:
enemies = self.bot.enemy_units
if enemies:
closeenemies = enemies.closer_than(30, roach)
if closeenemies:
for e in closeenemies:
if not self.bot.techtree.can_attack(roach, e) or not e.can_be_attacked:
closeenemies.remove(e)
if not closeenemies:
break
next_enemy = closeenemies.closest_to(roach)
if not next_enemy:
break
distance2enemy = roach.position.distance_to(next_enemy.position)
if distance2enemy < 30:
self.bot.do(roach.attack(next_enemy))
break
structures = self.bot.enemy_structures
if structures and not enemies:
closestructures = structures.closer_than(30, roach)
if closestructures:
for s in closestructures:
if not self.bot.techtree.can_attack(roach, s):
closestructures.remove(s)
if not closestructures:
break
next_structure = closestructures.closest_to(roach)
if not next_structure:
break
distance2structure = roach.position.distance_to(next_structure.position)
if distance2structure < 30:
self.bot.do(roach.attack(next_structure))
break
# queen
queens = self.bot.units(UnitTypeId.QUEEN).ready
if queens:
for queen in queens:
nearhq = self.bot.townhalls.closer_than(10, queen.position)
if nearhq:
abilities = await self.bot.get_available_abilities(queen)
if AbilityId.EFFECT_INJECTLARVA in abilities:
self.bot.do(queen(AbilityId.EFFECT_INJECTLARVA, nearhq[0]))
else:
hqs = self.bot.townhalls
for hq in hqs:
nearqueen = queens.closer_than(5, hq)
if nearqueen:
hqs.remove(hq)
if hqs:
self.bot.do(queen.move(hqs[0].position))
break
......@@ -6,7 +6,6 @@ class ZerglingRush:
"""Zerg ZerglingRush"""
def __init__(self, bot=None):
self.bot = bot
self.workerscout = None
self.bot.squadsize = 0
self.bot.attack_count = 0
self.bot.retreat_count = 0
......@@ -14,13 +13,16 @@ class ZerglingRush:
async def Run(self):
"""Runs on every GameStep"""
if self.bot.iteration == 1:
self.bot.current_strategy = 'ZerglingRush'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
self.bot.not_squadunit.append(UnitTypeId.QUEEN)
self.bot.not_commanderunit.append(UnitTypeId.QUEEN)
self.bot.current_strategy = 'ZerglingRush'
self.bot.squadsize = 10
self.bot.attack_count = 10
self.bot.retreat_count = 0
if self.bot.usechat:
await self.bot._client.chat_send("Strategy: ZerglingRush", team_only=False)
await self.Macro()
await self.Micro()
......@@ -41,12 +43,8 @@ class ZerglingRush:
await self.bot.warmanager.expand()
# Send a worker scout
if self.bot.units(race_worker[self.bot.race]).ready and not self.workerscout:
worker = self.bot.units(race_worker[self.bot.race]).ready.first
if worker:
self.workerscout = True
await self.bot.warmanager.scout(worker)
if self.bot.time >= 120:
await self.bot.warmanager.scout()
async def Micro(self):
# zergling
......@@ -71,6 +69,7 @@ class ZerglingRush:
distance2enemy = zergling.position.distance_to(next_enemy.position)
if distance2enemy < 20:
self.bot.do(zergling.attack(next_enemy))
break
structures = self.bot.enemy_structures
if structures and not enemies:
......@@ -90,6 +89,7 @@ class ZerglingRush:
distance2structure = zergling.position.distance_to(next_structure.position)
if distance2structure < 20:
self.bot.do(zergling.attack(next_structure))
break
# queen