Share This
Связаться со мной
Крути в низ
Categories
//Python AI в StarCraft II. Часть VIII: разведка и другие визуальные материалы

Python AI в StarCraft II. Часть VIII: разведка и другие визуальные материалы

21.05.2021Category : Python

Предыдущая статья — Python AI в StarCraft II. Часть VII: введение в глубокое обучение.

Добро пожаловать в восьмую часть серии статей про использование искусственного интеллекта в игре Starcraft II. Мы наконец-то начинаем применять методы глубокого обучения к нашему боту. В этой статье будем работать над созданием большого количества визуализированных изображений для подачи их в нашу нейронную сеть.

Для начала визуализируем остальные наши юниты. В целях экономии места мы создали словарь draw_dict. В этом словаре в качестве ключа будет использоваться тип юнита (его мы будем визуализировать), а в качестве значения — размер и цвет этого блока.

Итак, внутри метода intel:

        draw_dict = {                      NEXUS: [15, (0, 255, 0)],                      PYLON: [3, (20, 235, 0)],                      PROBE: [1, (55, 200, 0)],                      ASSIMILATOR: [2, (55, 200, 0)],                      GATEWAY: [3, (200, 100, 0)],                      CYBERNETICSCORE: [3, (150, 150, 0)],                      STARGATE: [5, (255, 0, 0)],                      VOIDRAY: [3, (255, 100, 0)]                     }

Теперь мы можем перебирать этот словарь следующим образом:

        for unit_type in draw_dict:             for unit in self.units(unit_type).ready:                 pos = unit.position                 cv2.circle(game_data, (int(pos[0]), int(pos[1])), draw_dict[unit_type][0], draw_dict[unit_type][1], -1)

Нам также нужно нарисовать здания и юниты наших врагов. Для этого мы просто нарисуем их «основную базу» (нексус, командный центр и инкубатор) того же размера, что и наши нексусы, а все остальное — размером 5.

Мы могли бы придать военным зданиям другой вид, отличный от обычных (как мы делаем с нашими собственными зданиями). Возможно, в дальнейшем мы так и поступим, но сейчас просто нарисуем все в одном стиле. Если мы сочтем этот метод успешным, будем его совершенствовать.

Итак, для вражеских зданий:

        main_base_names = ["nexus", "commandcenter", "hatchery"]         for enemy_building in self.known_enemy_structures:             pos = enemy_building.position             if enemy_building.name.lower() not in main_base_names:                 cv2.circle(game_data, (int(pos[0]), int(pos[1])), 5, (200, 50, 212), -1)         for enemy_building in self.known_enemy_structures:             pos = enemy_building.position             if enemy_building.name.lower() in main_base_names:                 cv2.circle(game_data, (int(pos[0]), int(pos[1])), 15, (0, 0, 255), -1)

Теперь займемся вражескими юнитами. Хотелось бы провести различие хотя бы между рабочими и всеми остальными. Опять же, в дальнейшем мы можем разграничить все юниты, и тогда сеть сможет изучить их более подробно. Но сейчас пока вот так:

        for enemy_unit in self.known_enemy_units:              if not enemy_unit.is_structure:                 worker_names = ["probe",                                 "scv",                                 "drone"]                 # if that unit is a PROBE, SCV, or DRONE... it's a worker                 pos = enemy_unit.position                 if enemy_unit.name.lower() in worker_names:                     cv2.circle(game_data, (int(pos[0]), int(pos[1])), 1, (55, 0, 155), -1)                 else:                     cv2.circle(game_data, (int(pos[0]), int(pos[1])), 3, (50, 0, 215), -1)

Дальше у нас возникнут определенные трудности. Нам будет трудно увидеть вражеские здания и тому подобное, кроме случаев, когда мы атакуем. Это совсем не хорошо. Самое время создать разведчика.

Разведчики немного различаются по классам, но для протоссов это наблюдатель (класс observer). Чтобы создать наблюдателя, нам нужна робототехника (robotics facility). А чтобы создать робототехнику, нам нужно Кибернетическое Ядро, для которого, в свою очередь, необходимы Врата. Слава богу, все это, кроме робототехники, у нас уже есть, так что приступим!

Для начала импортируем необходимые элементы:

from sc2.constants import NEXUS, PROBE, PYLON, ASSIMILATOR, GATEWAY,   CYBERNETICSCORE, STALKER, STARGATE, VOIDRAY, OBSERVER, ROBOTICSFACILITY

Далее добавим в наш метод offensive_force_buildings следующий код:

            if self.units(CYBERNETICSCORE).ready.exists:                 if len(self.units(ROBOTICSFACILITY)) < 1:                     if self.can_afford(ROBOTICSFACILITY) and not self.already_pending(ROBOTICSFACILITY):                         await self.build(ROBOTICSFACILITY, near=pylon)

Полностью метод будет выглядеть вот так:

    async def offensive_force_buildings(self):         #print(self.iteration / self.ITERATIONS_PER_MINUTE)         if self.units(PYLON).ready.exists:             pylon = self.units(PYLON).ready.random              if self.units(GATEWAY).ready.exists and not self.units(CYBERNETICSCORE):                 if self.can_afford(CYBERNETICSCORE) and not self.already_pending(CYBERNETICSCORE):                     await self.build(CYBERNETICSCORE, near=pylon)              elif len(self.units(GATEWAY)) < 1:                 if self.can_afford(GATEWAY) and not self.already_pending(GATEWAY):                     await self.build(GATEWAY, near=pylon)              if self.units(CYBERNETICSCORE).ready.exists:                 if len(self.units(ROBOTICSFACILITY)) < 1:                     if self.can_afford(ROBOTICSFACILITY) and not self.already_pending(ROBOTICSFACILITY):                         await self.build(ROBOTICSFACILITY, near=pylon)              if self.units(CYBERNETICSCORE).ready.exists:                 if len(self.units(STARGATE)) < (self.iteration / self.ITERATIONS_PER_MINUTE):                     if self.can_afford(STARGATE) and not self.already_pending(STARGATE):                         await self.build(STARGATE, near=pylon)

python ai v starcraft ii chast viii razvedka i drugie vizualnye materialy e293dd2 - Python AI в StarCraft II. Часть VIII: разведка и другие визуальные материалы

Больше материалов по машинному обучению

Подписывайтесь на нас в Телеграм

Подписаться ×

Дальше нужно создать разведчика и, конечно, произвести некоторую разведку. Мы планируем это сделать в одном новом методе, чтобы разведчик в любом случае имел приоритет над всем прочим. Для этого в методе on_step над всеми остальными методами напишем:

        await self.scout()

А теперь создадим сам этот метод:

    async def scout(self):         if len(self.units(OBSERVER)) > 0:             scout = self.units(OBSERVER)[0]             if scout.is_idle:                 enemy_location = self.enemy_start_locations[0]                 move_to = self.random_location_variance(enemy_location)                 print(move_to)                 await self.do(scout.move(move_to))          else:             for rf in self.units(ROBOTICSFACILITY).ready.noqueue:                 if self.can_afford(OBSERVER) and self.supply_left > 0:                     await self.do(rf.train(OBSERVER))

Сначала этот метод проверяет, есть ли у нас наблюдатель. Если он есть и при этом бездействует, то мы находим начальную точку врага и перемещаем наблюдателя в место, чуть-чуть отличное от данной точки.

А если наблюдателя у нас нет, то мы его создаем.

Для подбора местоположения нам просто нужно создать метод случайной дисперсии:

    def random_location_variance(self, enemy_start_location):         x = enemy_start_location[0]         y = enemy_start_location[1]          x += ((random.randrange(-20, 20))/100) * enemy_start_location[0]         y += ((random.randrange(-20, 20))/100) * enemy_start_location[1]          if x < 0:             x = 0         if y < 0:             y = 0         if x > self.game_info.map_size[0]:             x = self.game_info.map_size[0]         if y > self.game_info.map_size[1]:             y = self.game_info.map_size[1]          go_to = position.Point2(position.Pointlike((x,y)))         return go_to

Это не слишком сложно, нужно только понять смысл позиции. Вы не можете переместить юнит просто в некоторые координаты, вы должны переместить его на позицию. Для этого вы создаете позицию Point2 или Point3 (в зависимости от того, передаете ли вы высоту). Вам нужно, чтобы передаваемые точки были объектами класса Pointlike.

Далее мы добавляем тип юнита ROBOTICSFASILITY в наш словарь draw_dict:

ROBOTICSFACILITY: [5, (215, 155, 0)],

И затем, наконец, мы отрисуем нашего наблюдателя (разведчика):

        for obs in self.units(OBSERVER).ready:             pos = obs.position             cv2.circle(game_data, (int(pos[0]), int(pos[1])), 1, (255, 255, 255), -1)

Полный код на данный момент имеет следующий вид:

import sc2 from sc2 import run_game, maps, Race, Difficulty, position from sc2.player import Bot, Computer from sc2.constants import NEXUS, PROBE, PYLON, ASSIMILATOR, GATEWAY, CYBERNETICSCORE, STALKER, STARGATE, VOIDRAY, OBSERVER, ROBOTICSFACILITY import random import cv2 import numpy as np class SentdeBot(sc2.BotAI): def __init__(self): self.ITERATIONS_PER_MINUTE = 165 self.MAX_WORKERS = 50 async def on_step(self, iteration): self.iteration = iteration await self.scout() await self.distribute_workers() await self.build_workers() await self.build_pylons() await self.build_assimilators() await self.expand() await self.offensive_force_buildings() await self.build_offensive_force() await self.intel() await self.attack() def random_location_variance(self, enemy_start_location): x = enemy_start_location[0] y = enemy_start_location[1] x += ((random.randrange(-20, 20))/100) * enemy_start_location[0] y += ((random.randrange(-20, 20))/100) * enemy_start_location[1] if x < 0: x = 0 if y < 0: y = 0 if x > self.game_info.map_size[0]: x = self.game_info.map_size[0] if y > self.game_info.map_size[1]: y = self.game_info.map_size[1] go_to = position.Point2(position.Pointlike((x,y))) return go_to async def scout(self): if len(self.units(OBSERVER)) > 0: scout = self.units(OBSERVER)[0] if scout.is_idle: enemy_location = self.enemy_start_locations[0] move_to = self.random_location_variance(enemy_location) print(move_to) await self.do(scout.move(move_to)) else: for rf in self.units(ROBOTICSFACILITY).ready.noqueue: if self.can_afford(OBSERVER) and self.supply_left > 0: await self.do(rf.train(OBSERVER)) async def intel(self): game_data = np.zeros((self.game_info.map_size[1], self.game_info.map_size[0], 3), np.uint8) # UNIT: [SIZE, (BGR COLOR)] '''from sc2.constants import NEXUS, PROBE, PYLON, ASSIMILATOR, GATEWAY, CYBERNETICSCORE, STARGATE, VOIDRAY''' draw_dict = { NEXUS: [15, (0, 255, 0)], PYLON: [3, (20, 235, 0)], PROBE: [1, (55, 200, 0)], ASSIMILATOR: [2, (55, 200, 0)], GATEWAY: [3, (200, 100, 0)], CYBERNETICSCORE: [3, (150, 150, 0)], STARGATE: [5, (255, 0, 0)], ROBOTICSFACILITY: [5, (215, 155, 0)], VOIDRAY: [3, (255, 100, 0)], #OBSERVER: [3, (255, 255, 255)], } for unit_type in draw_dict: for unit in self.units(unit_type).ready: pos = unit.position cv2.circle(game_data, (int(pos[0]), int(pos[1])), draw_dict[unit_type][0], draw_dict[unit_type][1], -1) main_base_names = ["nexus", "supplydepot", "hatchery"] for enemy_building in self.known_enemy_structures: pos = enemy_building.position if enemy_building.name.lower() not in main_base_names: cv2.circle(game_data, (int(pos[0]), int(pos[1])), 5, (200, 50, 212), -1) for enemy_building in self.known_enemy_structures: pos = enemy_building.position if enemy_building.name.lower() in main_base_names: cv2.circle(game_data, (int(pos[0]), int(pos[1])), 15, (0, 0, 255), -1) for enemy_unit in self.known_enemy_units: if not enemy_unit.is_structure: worker_names = ["probe", "scv", "drone"] # if that unit is a PROBE, SCV, or DRONE... it's a worker pos = enemy_unit.position if enemy_unit.name.lower() in worker_names: cv2.circle(game_data, (int(pos[0]), int(pos[1])), 1, (55, 0, 155), -1) else: cv2.circle(game_data, (int(pos[0]), int(pos[1])), 3, (50, 0, 215), -1) for obs in self.units(OBSERVER).ready: pos = obs.position cv2.circle(game_data, (int(pos[0]), int(pos[1])), 1, (255, 255, 255), -1) # flip horizontally to make our final fix in visual representation: flipped = cv2.flip(game_data, 0) resized = cv2.resize(flipped, dsize=None, fx=2, fy=2) cv2.imshow('Intel', resized) cv2.waitKey(1) async def build_workers(self): if (len(self.units(NEXUS)) * 16) > len(self.units(PROBE)) and len(self.units(PROBE)) < self.MAX_WORKERS: for nexus in self.units(NEXUS).ready.noqueue: if self.can_afford(PROBE): await self.do(nexus.train(PROBE)) async def build_pylons(self): if self.supply_left < 5 and not self.already_pending(PYLON): nexuses = self.units(NEXUS).ready if nexuses.exists: if self.can_afford(PYLON): await self.build(PYLON, near=nexuses.first) async def build_assimilators(self): for nexus in self.units(NEXUS).ready: vaspenes = self.state.vespene_geyser.closer_than(15.0, nexus) for vaspene in vaspenes: if not self.can_afford(ASSIMILATOR): break worker = self.select_build_worker(vaspene.position) if worker is None: break if not self.units(ASSIMILATOR).closer_than(1.0, vaspene).exists: await self.do(worker.build(ASSIMILATOR, vaspene)) async def expand(self): if self.units(NEXUS).amount < (self.iteration / self.ITERATIONS_PER_MINUTE) and self.can_afford(NEXUS): await self.expand_now() async def offensive_force_buildings(self): #print(self.iteration / self.ITERATIONS_PER_MINUTE) if self.units(PYLON).ready.exists: pylon = self.units(PYLON).ready.random if self.units(GATEWAY).ready.exists and not self.units(CYBERNETICSCORE): if self.can_afford(CYBERNETICSCORE) and not self.already_pending(CYBERNETICSCORE): await self.build(CYBERNETICSCORE, near=pylon) elif len(self.units(GATEWAY)) < 1: if self.can_afford(GATEWAY) and not self.already_pending(GATEWAY): await self.build(GATEWAY, near=pylon) if self.units(CYBERNETICSCORE).ready.exists: if len(self.units(ROBOTICSFACILITY)) < 1: if self.can_afford(ROBOTICSFACILITY) and not self.already_pending(ROBOTICSFACILITY): await self.build(ROBOTICSFACILITY, near=pylon) if self.units(CYBERNETICSCORE).ready.exists: if len(self.units(STARGATE)) < (self.iteration / self.ITERATIONS_PER_MINUTE): if self.can_afford(STARGATE) and not self.already_pending(STARGATE): await self.build(STARGATE, near=pylon) async def build_offensive_force(self): for sg in self.units(STARGATE).ready.noqueue: if self.can_afford(VOIDRAY) and self.supply_left > 0: await self.do(sg.train(VOIDRAY)) def find_target(self, state): if len(self.known_enemy_units) > 0: return random.choice(self.known_enemy_units) elif len(self.known_enemy_structures) > 0: return random.choice(self.known_enemy_structures) else: return self.enemy_start_locations[0] async def attack(self): # {UNIT: [n to fight, n to defend]} aggressive_units = {VOIDRAY: [8, 3]} for UNIT in aggressive_units: if self.units(UNIT).amount > aggressive_units[UNIT][0] and self.units(UNIT).amount > aggressive_units[UNIT][1]: for s in self.units(UNIT).idle: await self.do(s.attack(self.find_target(self.state))) elif self.units(UNIT).amount > aggressive_units[UNIT][1]: if len(self.known_enemy_units) > 0: for s in self.units(UNIT).idle: await self.do(s.attack(random.choice(self.known_enemy_units))) run_game(maps.get("AbyssalReefLE"), [ Bot(Race.Protoss, SentdeBot()), Computer(Race.Terran, Difficulty.Hard) ], realtime=False)

Теперь мы можем добавить последние штрихи и начать создание нашего реального набора данных для глубокого обучения!

Следующая статья — Python AI в StarCraft II. Часть IX: создаем набор данных для обучения.

python ai v starcraft ii chast viii razvedka i drugie vizualnye materialy 3c9c0d7 - Python AI в StarCraft II. Часть VIII: разведка и другие визуальные материалы

Больше материалов по машинному обучению

Подписывайтесь на нас в Телеграм

Подписаться ×

  • 2 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close