import os
import random
import logging
import copy
import queue
import math
from pygame.math import Vector2
from .base_agent import BaseAgent
[docs]class BotAgent(BaseAgent):
'''
Overview:
A simple script bot
'''
def __init__(self, name=None, level=3):
self.name = name
self.actions_queue = queue.Queue()
self.last_clone_num = 1
self.level = level
def step(self, obs):
if self.level == 1:
return self.step_level_1(obs)
if self.level == 2:
return self.step_level_2(obs)
if self.level == 3:
return self.step_level_3(obs)
def step_level_1(self, obs):
if self.actions_queue.qsize() > 0:
return self.actions_queue.get()
overlap = obs['overlap']
overlap = self.preprocess(overlap)
food_balls = overlap['food']
thorns_balls = overlap['thorns']
spore_balls = overlap['spore']
clone_balls = overlap['clone']
my_clone_balls, others_clone_balls = self.process_clone_balls(clone_balls)
min_distance, min_food_ball = self.process_food_balls(food_balls, my_clone_balls[0])
if min_food_ball is not None:
direction = (min_food_ball['position'] - my_clone_balls[0]['position']).normalize()
else:
direction = (Vector2(0, 0) - my_clone_balls[0]['position']).normalize()
action_type = 0
self.actions_queue.put([direction.x, direction.y, action_type])
action_ret = self.actions_queue.get()
return action_ret
def step_level_2(self, obs):
if self.actions_queue.qsize() > 0:
return self.actions_queue.get()
overlap = obs['overlap']
overlap = self.preprocess(overlap)
food_balls = overlap['food']
thorns_balls = overlap['thorns']
spore_balls = overlap['spore']
clone_balls = overlap['clone']
my_clone_balls, others_clone_balls = self.process_clone_balls(clone_balls)
min_distance, min_thorns_ball = self.process_thorns_balls(thorns_balls, my_clone_balls[0])
min_distance, min_food_ball = self.process_food_balls(food_balls, my_clone_balls[0])
if min_thorns_ball is not None:
direction = (min_thorns_ball['position'] - my_clone_balls[0]['position'])
else:
if min_food_ball is not None:
direction = (min_food_ball['position'] - my_clone_balls[0]['position'])
else:
direction = (Vector2(0, 0) - my_clone_balls[0]['position'])
action_type = 0
if direction.length()>0:
direction = direction.normalize()
else:
direction = Vector2(1, 1).normalize()
self.actions_queue.put([direction.x, direction.y, action_type])
action_ret = self.actions_queue.get()
return action_ret
def step_level_3(self, obs):
if self.actions_queue.qsize() > 0:
return self.actions_queue.get()
overlap = obs['overlap']
overlap = self.preprocess(overlap)
food_balls = overlap['food']
thorns_balls = overlap['thorns']
spore_balls = overlap['spore']
clone_balls = overlap['clone']
my_clone_balls, others_clone_balls = self.process_clone_balls(clone_balls)
if len(my_clone_balls) >= 9 and my_clone_balls[4]['radius'] > 4:
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([0, 0, 0])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
self.actions_queue.put([None, None, 1])
action_ret = self.actions_queue.get()
return action_ret
if len(others_clone_balls) > 0 and self.can_eat(others_clone_balls[0]['radius'], my_clone_balls[0]['radius']):
direction = (my_clone_balls[0]['position'] - others_clone_balls[0]['position'])
action_type = 0
else:
min_distance, min_thorns_ball = self.process_thorns_balls(thorns_balls, my_clone_balls[0])
if min_thorns_ball is not None:
direction = (min_thorns_ball['position'] - my_clone_balls[0]['position'])
else:
min_distance, min_food_ball = self.process_food_balls(food_balls, my_clone_balls[0])
if min_food_ball is not None:
direction = (min_food_ball['position'] - my_clone_balls[0]['position'])
else:
direction = (Vector2(0, 0) - my_clone_balls[0]['position'])
action_random = random.random()
if action_random < 0.02:
action_type = 1
if action_random < 0.04 and action_random > 0.02:
action_type = 2
else:
action_type = 0
if direction.length()>0:
direction = direction.normalize()
else:
direction = Vector2(1, 1).normalize()
direction = self.add_noise_to_direction(direction).normalize()
self.actions_queue.put([direction.x, direction.y, action_type])
action_ret = self.actions_queue.get()
return action_ret
def process_clone_balls(self, clone_balls):
my_clone_balls = []
others_clone_balls = []
for clone_ball in clone_balls:
if clone_ball['player'] == self.name:
my_clone_balls.append(copy.deepcopy(clone_ball))
my_clone_balls.sort(key=lambda a: a['radius'], reverse=True)
for clone_ball in clone_balls:
if clone_ball['player'] != self.name:
others_clone_balls.append(copy.deepcopy(clone_ball))
others_clone_balls.sort(key=lambda a: a['radius'], reverse=True)
return my_clone_balls, others_clone_balls
def process_thorns_balls(self, thorns_balls, my_max_clone_ball):
min_distance = 10000
min_thorns_ball = None
for thorns_ball in thorns_balls:
if self.can_eat(my_max_clone_ball['radius'], thorns_ball['radius']):
distance = (thorns_ball['position'] - my_max_clone_ball['position']).length()
if distance < min_distance:
min_distance = distance
min_thorns_ball = copy.deepcopy(thorns_ball)
return min_distance, min_thorns_ball
def process_food_balls(self, food_balls, my_max_clone_ball):
min_distance = 10000
min_food_ball = None
for food_ball in food_balls:
distance = (food_ball['position'] - my_max_clone_ball['position']).length()
if distance < min_distance:
min_distance = distance
min_food_ball = copy.deepcopy(food_ball)
return min_distance, min_food_ball
def preprocess(self, overlap):
new_overlap = {}
for k, v in overlap.items():
if k =='clone':
new_overlap[k] = []
for index, vv in enumerate(v):
tmp={}
tmp['position'] = Vector2(vv[0],vv[1])
tmp['radius'] = vv[2]
tmp['player'] = int(vv[-2])
tmp['team'] = int(vv[-1])
new_overlap[k].append(tmp)
else:
new_overlap[k] = []
for index, vv in enumerate(v):
tmp={}
tmp['position'] = Vector2(vv[0],vv[1])
tmp['radius'] = vv[2]
new_overlap[k].append(tmp)
return new_overlap
def preprocess_tuple2vector(self, overlap):
new_overlap = {}
for k, v in overlap.items():
new_overlap[k] = []
for index, vv in enumerate(v):
new_overlap[k].append(vv)
new_overlap[k][index]['position'] = Vector2(*vv['position'])
return new_overlap
def add_noise_to_direction(self, direction, noise_ratio=0.1):
direction = direction + Vector2(((random.random() * 2 - 1)*noise_ratio)*direction.x,
((random.random() * 2 - 1)*noise_ratio)*direction.y)
return direction
def radius_to_score(self, radius):
return (math.pow(radius,2) - 0.15) / 0.042 * 100
def can_eat(self, radius1, radius2):
return self.radius_to_score(radius1) > 1.3 * self.radius_to_score(radius2)