woodsja

smart agent using pysc2 2.0

Oct 19th, 2018
460
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.27 KB | None | 0 0
  1. from pysc2.agents import base_agent
  2. from pysc2.env import sc2_env
  3. from pysc2.lib import actions, features, units
  4. from absl import app
  5. import random
  6. import numpy as np
  7. import pandas as pd
  8. import time
  9.  
  10. # from Steven Brown: https://itnext.io/build-a-zerg-bot-with-pysc2-2-0-295375d2f58e
  11. # from Steven Brown: https://chatbotslife.com/building-a-smart-pysc2-agent-cdc269cb095d
  12.  
  13.  
  14. _PLAYER_SELF = 1
  15.  
  16. _NOT_QUEUED = [0]
  17. _QUEUED = [1]
  18.  
  19. ACTION_DO_NOTHING = 'donothing'
  20. ACTION_SELECT_SCV = 'selectscv'
  21. ACTION_BUILD_SUPPLY_DEPOT = 'buildsupplydepot'
  22. ACTION_BUILD_BARRACKS = 'buildbarracks'
  23. ACTION_SELECT_BARRACKS = 'selectbarracks'
  24. ACTION_BUILD_MARINE = 'buildmarine'
  25. ACTION_SELECT_ARMY = 'selectarmy'
  26. ACTION_ATTACK = 'attack'
  27.  
  28. smart_actions = [
  29.   ACTION_DO_NOTHING,
  30.   ACTION_SELECT_SCV,
  31.   ACTION_BUILD_SUPPLY_DEPOT,
  32.   ACTION_BUILD_BARRACKS,
  33.   ACTION_SELECT_BARRACKS,
  34.   ACTION_BUILD_MARINE,
  35.   ACTION_SELECT_ARMY,
  36.   ACTION_ATTACK,
  37. ]
  38.  
  39.  
  40. KILL_UNIT_REWARD = 0.2
  41. KILL_BUILDING_REWARD = 0.5
  42.  
  43.  
  44. class QLearningTable:
  45.   def __init__(self, actions, learning_rate = 0.01, reward_decay = 0.9, e_greedy = 0.9):
  46.     self.actions = actions
  47.     self.lr = learning_rate
  48.     self.gamma = reward_decay
  49.     self.epsilon = e_greedy
  50.     self.q_table = pd.DataFrame(columns=self.actions, dtype=np.float64)
  51.  
  52.   def choose_action(self, observation):
  53.     self.check_state_exists(observation)
  54.  
  55.     if np.random.uniform() < self.epsilon:
  56.       # choose best action
  57.       state_action = self.q_table.ix[observation, :]
  58.  
  59.       # some actions have the same value
  60.       state_action = state_action.reindex(np.random.permutation(state_action.index))
  61.  
  62.       action = state_action.idxmax()
  63.     else:
  64.       # choose random action
  65.       action = np.random.choice(self.actions)
  66.  
  67.     return action
  68.  
  69.   def learn(self, s, a, r, s_):
  70.     self.check_state_exists(s_)
  71.     self.check_state_exists(s)
  72.  
  73.     q_predict = self.q_table.ix[s, a]
  74.     q_target = r + self.gamma * self.q_table.ix[s_, :].max()
  75.  
  76.     # current_state = [
  77.     #   supply_depot_count,
  78.     #   barracks_count,
  79.     #   supply_limit,
  80.     #   army_supply,
  81.     # ]
  82.  
  83.     # update
  84.     self.q_table.ix[s, a] += self.lr * (q_target - q_predict)
  85.  
  86.   def check_state_exists(self, state):
  87.     if state not in self.q_table.index:
  88.       #append new state to q table
  89.       self.q_table = self.q_table.append(pd.Series([0] * len(self.actions), index=self.q_table.columns, name=state))
  90.  
  91. class SmartAgent(base_agent.BaseAgent):
  92.   def __init__(self):
  93.     super(SmartAgent, self).__init__()
  94.  
  95.     self.qlearn = QLearningTable(actions=list(range(len(smart_actions))))
  96.  
  97.     self.previous_killed_unit_score = 0
  98.     self.previous_killed_building_score = 0
  99.  
  100.     self.previous_action = None
  101.     self.previous_state = None
  102.  
  103.   def can_do(self, obs, action):
  104.     return action in obs.observation.available_actions
  105.  
  106.   def transformLocation(self, x, x_distance, y, y_distance):
  107.     if not self.base_top_left:
  108.       return [x - x_distance, y - y_distance]
  109.  
  110.     return [x + x_distance, y + y_distance]
  111.  
  112.   def unit_type_is_selected(self, obs, unit_type):
  113.     if (len(obs.observation.single_select) > 0 and
  114.             obs.observation.single_select[0].unit_type == unit_type):
  115.       return True
  116.  
  117.     if (len(obs.observation.multi_select) > 0 and
  118.             obs.observation.multi_select[0].unit_type == unit_type):
  119.       return True
  120.  
  121.     return False
  122.  
  123.   def get_units_by_type(self, obs, unit_type):
  124.     return [unit for unit in obs.observation.feature_units
  125.             if unit.unit_type == unit_type]
  126.  
  127.   def step(self, obs):
  128.     super(SmartAgent, self).step(obs)
  129.  
  130.     # Figure out where the player is: top left or bottom right
  131.     player_y, player_x = (obs.observation.feature_minimap.player_relative == _PLAYER_SELF).nonzero()
  132.     self.base_top_left = 1 if player_y.any() and player_y.mean() <= 31 else 0
  133.  
  134.     # prefetch values for current state
  135.     supply_depot_count = len(self.get_units_by_type(obs, units.Terran.SupplyDepot))
  136.     barracks_count = len(self.get_units_by_type(obs, units.Terran.Barracks))
  137.     supply_limit = obs.observation.player.food_cap
  138.     army_supply = obs.observation.player.food_army
  139.  
  140.     current_state = [
  141.       supply_depot_count,
  142.       barracks_count,
  143.       supply_limit,
  144.       army_supply,
  145.     ]
  146.  
  147.     killed_unit_score = obs.observation.score_cumulative.killed_value_units
  148.     killed_building_score = obs.observation.score_cumulative.killed_value_structures
  149.  
  150.     if self.previous_action is not None:
  151.       reward = 0
  152.  
  153.       if killed_unit_score > self.previous_killed_unit_score:
  154.         reward += KILL_UNIT_REWARD
  155.  
  156.       if killed_building_score > self.previous_killed_building_score:
  157.         reward += KILL_BUILDING_REWARD
  158.  
  159.       self.qlearn.learn(str(self.previous_state), self.previous_action, reward, str(current_state))
  160.  
  161.     rl_action = self.qlearn.choose_action(str(current_state))
  162.     smart_action = smart_actions[rl_action]
  163.  
  164.     self.previous_killed_unit_score = killed_unit_score
  165.     self.previous_killed_building_score = killed_building_score
  166.     self.previous_state = current_state
  167.     self.previous_action = rl_action
  168.  
  169.     print(smart_action)
  170.     # no_op
  171.     if smart_action == ACTION_DO_NOTHING:
  172.       return actions.FUNCTIONS.no_op()
  173.  
  174.     # select an SCV
  175.     elif smart_action == ACTION_SELECT_SCV:
  176.       scvs = self.get_units_by_type(obs, units.Terran.SCV)
  177.       #time.sleep(0.5)
  178.       if len(scvs) > 0:
  179.         #time.sleep(0.5)
  180.         scv = random.choice(scvs)
  181.         #print(scv.x, scv.y)
  182.         if (scv.x > 0) & (scv.x < 83) & (scv.y > 0) & (scv.y < 83):
  183.           return actions.FUNCTIONS.select_point("select_all_type", (scv.x,
  184.                                                                   scv.y))
  185.         else:
  186.           return actions.FUNCTIONS.no_op()
  187.  
  188.     # build a supply depot
  189.     elif smart_action == ACTION_BUILD_SUPPLY_DEPOT:
  190.       if self.can_do(obs, actions.FUNCTIONS.Build_SupplyDepot_screen.id):
  191.         x = random.randint(0, 83)
  192.         y = random.randint(0, 83)
  193.  
  194.         return actions.FUNCTIONS.Build_SupplyDepot_screen("now", (x, y))
  195.  
  196.     elif smart_action == ACTION_BUILD_BARRACKS:
  197.       if self.can_do(obs, actions.FUNCTIONS.Build_Barracks_screen.id):
  198.         x = random.randint(0, 83)
  199.         y = random.randint(0, 83)
  200.  
  201.         return actions.FUNCTIONS.Build_Barracks_screen("now", (x, y))
  202.  
  203.     elif smart_action == ACTION_SELECT_BARRACKS:
  204.       barracks = self.get_units_by_type(obs, units.Terran.Barracks)
  205.       if len(barracks) > 0:
  206.         barrack = random.choice(barracks)
  207.  
  208.         return actions.FUNCTIONS.select_point("select_all_type", (barrack.x,
  209.                                                                 barrack.y))
  210.  
  211.     elif smart_action == ACTION_BUILD_MARINE:
  212.       if self.can_do(obs, actions.FUNCTIONS.Train_Marine_quick.id):
  213.         return actions.FUNCTIONS.Train_Marine_quick("now")
  214.  
  215.     elif smart_action == ACTION_SELECT_ARMY:
  216.       if self.can_do(obs, actions.FUNCTIONS.select_army.id):
  217.         return actions.FUNCTIONS.select_army("select")
  218.  
  219.     elif smart_action == ACTION_ATTACK:
  220.       if self.can_do(obs, actions.FUNCTIONS.Attack_minimap.id):
  221.         if self.base_top_left:
  222.           return actions.FUNCTIONS.Attack_minimap("now", (39, 45))
  223.  
  224.         return actions.FUNCTIONS.Attack_minimap("now", (21, 24))
  225.  
  226.  
  227.     return actions.FUNCTIONS.no_op()
  228.  
  229.  
  230.  
  231.  
  232.  
  233. def main(unused_argv):
  234.   agent = SmartAgent()
  235.   try:
  236.     while True:
  237.       with sc2_env.SC2Env(
  238.               map_name="Simple64",
  239.               players=[sc2_env.Agent(sc2_env.Race.terran),
  240.                        sc2_env.Bot(sc2_env.Race.random,
  241.                                    sc2_env.Difficulty.very_easy)],
  242.               agent_interface_format=features.AgentInterfaceFormat(
  243.                 feature_dimensions=features.Dimensions(screen=84, minimap=64),
  244.                 use_feature_units=True,),
  245.               step_mul=16,
  246.               game_steps_per_episode=0,
  247.               visualize=True) as env:
  248.  
  249.         agent.setup(env.observation_spec(), env.action_spec())
  250.  
  251.         timesteps = env.reset()
  252.         agent.reset()
  253.  
  254.         while True:
  255.           step_actions = [agent.step(timesteps[0])]
  256.           if timesteps[0].last():
  257.             break
  258.           timesteps = env.step(step_actions)
  259.  
  260.   except KeyboardInterrupt:
  261.     pass
  262.  
  263.  
  264. if __name__ == "__main__":
  265.   app.run(main)
Advertisement
Add Comment
Please, Sign In to add comment