def run(self): self.conn.sendto("cb".encode('utf-8'), (self.addr, self.serverport)) while self.running: msg, addr = self.conn.recvfrom(2048) msg = msg.decode('utf-8') # Coordinates of all players AllZombiePose = [] splitted_msg = msg.split('|') x, y, a, _ = splitted_msg[0].split(',') x = float(x) y = float(y) a = float(a) self_pos = (x, y, a) for position in msg.split('|')[1:-1]: x, y, angle, tag = position.split(',') x = float(x) y = float(y) angle = float(angle) tag = int(tag) if tag == 0: AllZombiePose.append((x, y, angle)) server_map_index = int(splitted_msg[-1]) if server_map_index != self.map_index: del self.world self.world = StaticWorld( "../Maps/map_{0}.csv".format(server_map_index)) self.map_index = server_map_index movement = self.dummy_escape_policy(self_pos, AllZombiePose) self.conn.sendto(movement.encode('utf-8'), (self.addr, self.serverport))
def setup_pygame(self): self.world = StaticWorld('../Maps/map_1.csv') self.screen = pygame.display.set_mode( (self.world.local_width * self.world.zoom, self.world.local_length * self.world.zoom)) pygame.event.set_allowed(None) pygame.event.set_allowed([pygame.locals.QUIT, pygame.locals.KEYDOWN]) pygame.key.set_repeat(100, 100) #move faster
def __init__(self, addr="127.0.0.1", serverport=9009): self.botport = random.randrange(8000, 8999) self.conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.conn.bind(("127.0.0.1", self.botport)) self.addr = addr self.serverport = serverport self.read_list = [self.conn] self.write_list = [] self.map_index = 0 self.world = StaticWorld('../Maps/map_0.csv') self.running = True
def __init__(self, port=9009, visualize = True): print(time.asctime(time.localtime(time.time()))) self.listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Bind to localhost - set to external ip to connect from other computers self.listener.bind(("127.0.0.1", port)) self.read_list = [self.listener] self.write_list = [] self.players_pose = {} self.players_ready = {} self.players_reward = {} self.map_index = 0 self.world = StaticWorld('../Maps/map_0.csv') self.screen = pygame.display.set_mode((self.world.zoom * self.world.length, self.world.zoom * self.world.width)) \ if sys.platform.startswith('win') and visualize else None
def init_players_pose(self): while True: self.map_index = np.random.randint(0, self.map_count) del self.world self.world = StaticWorld("../Maps/map_{0}.csv".format(self.map_index)) section_x = [(0, self.world.width // 2), (self.world.width // 2, self.world.width)][np.random.randint(0, 2)] section_y = [(0, self.world.length // 2), (self.world.length // 2, self.world.length)][np.random.randint(0, 2)] start_position = [] for p in range(len(self.players_pose)): trial_cnt = 0 while trial_cnt < 5: new_pose = (np.random.randint(*section_x), np.random.randint(*section_y), np.random.random() * 2 * PI) if self.world[(new_pose[0], new_pose[1])] == 1: continue noncollision = True for existing_pose in start_position: if abs(existing_pose[0] - new_pose[0]) + abs(existing_pose[1] - new_pose[1]) < 8: noncollision = False break if noncollision: start_position.append(new_pose) break trial_cnt += 1 # If cannot find a suitable location for a new player, move to new map if trial_cnt == 5: break # If all playerStarts are ready, break from main loop if len(start_position) == len(self.players_pose): for k in zip(self.players_pose.keys(), start_position): self.players_pose[k[0]] = *(k[1]), self.players_pose[k[0]][3] break
class ZombieChasePlayerEnv(Env): def __init__(self): self.map_index = 0 self.world = StaticWorld('Maps/map_0.csv') self.clientport = random.randrange(8000, 8999) self.conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.conn.bind(("127.0.0.1", self.clientport)) self.addr = "127.0.0.1" self.serverport = 9009 self.conn.sendto("cz".encode('utf-8'), (self.addr, self.serverport)) self.action_space = Discrete(4) self.observation_space = Box(low=0, high=3, shape=(self.world.radar_length, 1), dtype=np.float) self.saved_self_pose = None self.saved_all_zombie_pose = None self.saved_rew = 0.0 self.screen = None self.stepcount = 0 #block if no data received def _fetch_pos_from_server(self): msg, addr = self.conn.recvfrom(2048) msg = msg.decode('utf-8') # Coordinates of all players splitted_msg = msg.split('|') x, y, a, _ = splitted_msg[0].split(',') x = float(x) y = float(y) a = float(a) self_pos = (x, y, a) AllZombiePose = [] for position in splitted_msg[1:-1]: x, y, angle, tag = position.split(',') x = float(x) y = float(y) angle = float(angle) tag = int(tag) AllZombiePose.append((x, y, angle, tag)) map_index = int(splitted_msg[-1]) return self_pos, AllZombiePose, map_index def _calculate_reward(self, self_pos, AllZombiePose, last_self_pose, last_allZombiePose): if last_allZombiePose is None: return 0, False old_distance, _ = self._get_closest_bot_distance( last_self_pose, last_allZombiePose) curr_distance, _ = self._get_closest_bot_distance( self_pos, AllZombiePose) rew = 0 # reward for approaching target if max(old_distance, curr_distance) < self.world.perception_grids: if curr_distance < old_distance: rew += (old_distance - curr_distance) * 0.01 # reward for moving , weight 0.1 => 0.05 # old_x, old_y, _ = last_self_pose # x, y, _ = self_pos # dist = np.sqrt(np.square(x - old_x) + np.square(y - old_y)) # rew += dist * 0.01 # range[0, 0.05] # reward for staying near if curr_distance < Bot.alertRadius: blocked_distance = self._projection_blocking_distance( self_pos, AllZombiePose) clipped_curr_distance = max(2, curr_distance) rew += 2 / clipped_curr_distance * ( curr_distance - blocked_distance) / curr_distance # reward for catching if curr_distance < 2: rew += 10 return rew, True return rew, False def _projection_blocking_distance(self, self_pos, allActorPose): x, y, angle = self_pos distance, target = self._get_closest_bot_distance( self_pos, allActorPose) if distance > self.world.perception_grids or target is None: return 0 target_x, target_y, _, _ = target me_to_target = np.asarray([target_x - x, target_y - y]) me_to_target_unit = me_to_target / np.linalg.norm(me_to_target) maximum_proj_length = 0 for actor in allActorPose: ax, ay, aa, atag = actor if atag == 0 and (x != ax or y != ay): actor_to_target = np.asarray([target_x - ax, target_y - ay]) if np.linalg.norm(actor_to_target) < Bot.alertRadius: actor_proj_len = np.dot(me_to_target_unit, actor_to_target) if 0 < actor_proj_len < distance: maximum_proj_length = max(maximum_proj_length, actor_proj_len) return maximum_proj_length def _get_closest_bot_distance(self, self_pos, allZombiePose): x, y, _ = self_pos closest_dist_sqr = 100000000 target_actor = None for actor in allZombiePose: ax, ay, _, atag = actor if atag == 1: dist_sqr = (ax - x)**2 + (ay - y)**2 if dist_sqr < closest_dist_sqr: closest_dist_sqr = dist_sqr target_actor = actor return np.sqrt(closest_dist_sqr), target_actor #returns (obs, reward, finish) def step(self, action): cmd = None if action == 0: cmd = "uu" elif action == 1: cmd = "ui" elif action == 2: cmd = "ul" else: cmd = "ur" cmd += "|" cmd += str(self.saved_rew) # For Manual debugging # if self.saved_self_pose is not None: # print(self.saved_self_pose) # print(self.world.to_local_radar_obs(self.saved_self_pose, self.saved_all_zombie_pose)[:, 0]) # cmd = input('please input cmd') # else: # cmd = 'ui' self.conn.sendto(cmd.encode('utf-8'), (self.addr, self.serverport)) self_pos, AllZombiePos, server_map_index = self._fetch_pos_from_server( ) if self.map_index != server_map_index: del self.world self.world = StaticWorld( "Maps/map_{0}.csv".format(server_map_index)) self.map_index = server_map_index rew, done = self._calculate_reward(self_pos, AllZombiePos, self.saved_self_pose, self.saved_all_zombie_pose) self.saved_self_pose = self_pos self.saved_all_zombie_pose = AllZombiePos self.saved_rew = rew #if done or self.stepcount == 4000: # self.reset() done = done or self.stepcount == 4000 self.stepcount += 1 # return self.world.to_local_obs(self_pos, AllZombiePos), rew, done, {'episode': {'r':rew, 'l':self.stepcount}} return self.world.to_local_radar_obs(self_pos, AllZombiePos), rew, done, { 'episode': { 'r': rew, 'l': self.stepcount } } def reset(self): self.conn.sendto("r".encode('utf-8'), (self.addr, self.serverport)) self_pos, AllZombiePos, server_map_index = self._fetch_pos_from_server( ) if self.map_index != server_map_index: del self.world self.world = StaticWorld( "Maps/map_{0}.csv".format(server_map_index)) self.map_index = server_map_index self.stepcount = 0 return self.world.to_local_radar_obs(self_pos, AllZombiePos) metadata = {'render.modes': ['human', 'rgb_array']} def render(self, mode='human'): if self.saved_self_pose is not None: if mode == 'human': if self.screen == None: self.screen = pygame.display.set_mode( (self.world.local_width * self.world.zoom, self.world.local_length * self.world.zoom)) self.world.draw_local(self.screen, self.saved_self_pose, self.saved_all_zombie_pose) pygame.display.update() return else: super(ZombieChasePlayerEnv, self).render(mode=mode) def close(self): self.conn.sendto("d".encode('utf-8'), (self.addr, self.serverport)) if self.screen is not None: pygame.quit() def seed(self, seed=None): return [0]
class GameClient(object): def __init__(self, addr="127.0.0.1", serverport=9009): self.clientport = random.randrange(8000, 8999) self.conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Bind to localhost - set to external ip to connect from other computers self.conn.bind(("127.0.0.1", self.clientport)) self.addr = addr self.serverport = serverport self.read_list = [self.conn] self.write_list = [] self.setup_pygame() def setup_pygame(self): self.world = StaticWorld('../Maps/map_1.csv') self.screen = pygame.display.set_mode( (self.world.local_width * self.world.zoom, self.world.local_length * self.world.zoom)) pygame.event.set_allowed(None) pygame.event.set_allowed([pygame.locals.QUIT, pygame.locals.KEYDOWN]) pygame.key.set_repeat(100, 100) #move faster def run(self): running = True clock = pygame.time.Clock() tickspeed = 30 try: # Initialize connection to server self.conn.sendto("cz".encode('utf-8'), (self.addr, self.serverport)) while running: clock.tick(tickspeed) # select on specified file descriptors readable, writable, exceptional = (select.select( self.read_list, self.write_list, [], 0)) for f in readable: if f is self.conn: msg, addr = f.recvfrom(2048) msg = msg.decode('utf-8') #Coordinates of all players self_pos = None AllZombiePose = [] for position in msg.split('|')[:-1]: x, y, angle, tag = position.split(',') x = float(x) y = float(y) angle = float(angle) tag = int(tag) if self_pos is None: self_pos = (x, y, angle) AllZombiePose.append((x, y, angle, tag)) self.world.draw_local(self.screen, self_pos, AllZombiePose) #self.world.draw_global(self.screen) #self.world.draw_zombie_global(self.screen, (x, y, angle)) for event in pygame.event.get(): if event.type == pygame.QUIT or event.type == pygame.locals.QUIT: running = False break elif event.type == pygame.locals.KEYDOWN: if event.key == pygame.locals.K_UP: self.conn.sendto("uu".encode('utf-8'), (self.addr, self.serverport)) elif event.key == pygame.locals.K_LEFT: self.conn.sendto("ul".encode('utf-8'), (self.addr, self.serverport)) elif event.key == pygame.locals.K_RIGHT: self.conn.sendto("ur".encode('utf-8'), (self.addr, self.serverport)) pygame.event.clear(pygame.locals.KEYDOWN) pygame.display.update() finally: self.conn.sendto("d".encode('utf-8'), (self.addr, self.serverport))
class GameServer(object): map_count = 2 def __init__(self, port=9009, visualize = True): print(time.asctime(time.localtime(time.time()))) self.listener = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Bind to localhost - set to external ip to connect from other computers self.listener.bind(("127.0.0.1", port)) self.read_list = [self.listener] self.write_list = [] self.players_pose = {} self.players_ready = {} self.players_reward = {} self.map_index = 0 self.world = StaticWorld('../Maps/map_0.csv') self.screen = pygame.display.set_mode((self.world.zoom * self.world.length, self.world.zoom * self.world.width)) \ if sys.platform.startswith('win') and visualize else None # mv is in format [l/r/u][(optional)float] def do_movement(self, move, player): pos = self.players_pose[player] mv = move[0] if len(move) > 1: stepsize = float(move[1:]) else: if self.players_pose[player][3] == 0: if mv == "u": stepsize = 1 else: stepsize = 0.5 else: if mv == "u": stepsize = 1.5 else: stepsize = 0.5 if mv == "u": angle = pos[2] _x = pos[0] + stepsize * cos(angle) _y = pos[1] + stepsize * sin(angle) _x = np.clip(_x, 0, self.world.width) _y = np.clip(_y, 0, self.world.length) new_pos = (_x, _y, angle, pos[3]) if self.world[new_pos[:2]] == 0: self.players_pose[player] = new_pos elif mv == "l": angle = pos[2] + stepsize if angle > 2 * PI: angle -= 2 * PI self.players_pose[player] = (pos[0], pos[1], angle, pos[3]) elif mv == "r": angle = pos[2] - stepsize if angle < 0: angle += 2 * PI self.players_pose[player] = (pos[0], pos[1], angle, pos[3]) else: # stand idle pass def init_players_pose(self): while True: self.map_index = np.random.randint(0, self.map_count) del self.world self.world = StaticWorld("../Maps/map_{0}.csv".format(self.map_index)) section_x = [(0, self.world.width // 2), (self.world.width // 2, self.world.width)][np.random.randint(0, 2)] section_y = [(0, self.world.length // 2), (self.world.length // 2, self.world.length)][np.random.randint(0, 2)] start_position = [] for p in range(len(self.players_pose)): trial_cnt = 0 while trial_cnt < 5: new_pose = (np.random.randint(*section_x), np.random.randint(*section_y), np.random.random() * 2 * PI) if self.world[(new_pose[0], new_pose[1])] == 1: continue noncollision = True for existing_pose in start_position: if abs(existing_pose[0] - new_pose[0]) + abs(existing_pose[1] - new_pose[1]) < 8: noncollision = False break if noncollision: start_position.append(new_pose) break trial_cnt += 1 # If cannot find a suitable location for a new player, move to new map if trial_cnt == 5: break # If all playerStarts are ready, break from main loop if len(start_position) == len(self.players_pose): for k in zip(self.players_pose.keys(), start_position): self.players_pose[k[0]] = *(k[1]), self.players_pose[k[0]][3] break def _send_to_client(self, addr = None): if addr is not None: send = [] for pos in list(self.players_pose): if pos == addr: send.insert(0, "{0},{1},{2},{3}".format(*self.players_pose[pos])) else: send.append("{0},{1},{2},{3}".format(*self.players_pose[pos])) send.append(str(self.map_index)) self.listener.sendto('|'.join(send).encode('utf-8'), addr) else: for player in list(self.players_pose): send = [] for pos in list(self.players_pose): if player == pos: send.insert(0, "{0},{1},{2},{3}".format(*self.players_pose[pos])) else: send.append("{0},{1},{2},{3}".format(*self.players_pose[pos])) send.append(str(self.map_index)) self.listener.sendto('|'.join(send).encode('utf-8'), player) def run(self): last_updated_time = time.time() try: while True: if self.screen is not None: if time.time() - last_updated_time > 0.03: self.world.draw_global(self.screen, self.players_pose, self.players_reward) pygame.display.update() last_updated_time = time.time() for event in pygame.event.get(): if event.type == pygame.QUIT or event.type == pygame.locals.QUIT: pygame.quit() pygame.display.update() readable, writable, exceptional = ( select.select(self.read_list, self.write_list, []) ) for f in readable: if f is self.listener: msg, addr = f.recvfrom(2048) msg = msg.decode('utf-8') if len(msg) >= 1: cmd = msg[0] if cmd == "c": # New Connection if msg[1] == "z": # New Connection from zombie (model) self.players_pose[addr] = (0, 0, 0, 0) else: self.players_pose[addr] = (0, 0, 0, 1) self.players_ready[addr] = True self.init_players_pose() elif cmd == "u": # Movement Update ul0.3|0.5 # left 0.3, reward 0.5 if len(msg) >= 2 and addr in self.players_pose: if "|" in msg: msg_mv, msg_rew = msg[1:].split('|') else: msg_mv = msg[1:] msg_rew = None self.do_movement(msg_mv, addr) self.players_ready[addr] = True if msg_rew is not None: self.players_reward[addr] = float(msg_rew) elif cmd == "d": # Player Quitting if addr in self.players_pose: del self.players_pose[addr] del self.players_ready[addr] elif cmd == "r": self.init_players_pose() self._send_to_client(addr) else: print ("Unexpected: {0}".format(msg)) allready = all(elem for elem in self.players_ready.values()) if allready: self._send_to_client() self.players_ready = dict.fromkeys(self.players_ready, False) except KeyboardInterrupt as e: pass
class Bot(object): alertRadius = 10 def __init__(self, addr="127.0.0.1", serverport=9009): self.botport = random.randrange(8000, 8999) self.conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.conn.bind(("127.0.0.1", self.botport)) self.addr = addr self.serverport = serverport self.read_list = [self.conn] self.write_list = [] self.map_index = 0 self.world = StaticWorld('../Maps/map_0.csv') self.running = True def run(self): self.conn.sendto("cb".encode('utf-8'), (self.addr, self.serverport)) while self.running: msg, addr = self.conn.recvfrom(2048) msg = msg.decode('utf-8') # Coordinates of all players AllZombiePose = [] splitted_msg = msg.split('|') x, y, a, _ = splitted_msg[0].split(',') x = float(x) y = float(y) a = float(a) self_pos = (x, y, a) for position in msg.split('|')[1:-1]: x, y, angle, tag = position.split(',') x = float(x) y = float(y) angle = float(angle) tag = int(tag) if tag == 0: AllZombiePose.append((x, y, angle)) server_map_index = int(splitted_msg[-1]) if server_map_index != self.map_index: del self.world self.world = StaticWorld( "../Maps/map_{0}.csv".format(server_map_index)) self.map_index = server_map_index movement = self.dummy_escape_policy(self_pos, AllZombiePose) self.conn.sendto(movement.encode('utf-8'), (self.addr, self.serverport)) def dummy_escape_policy(self, self_pos, zombies): dir_score = [0 for _ in range(24)] x, y, angle = self_pos zombie_in_sight = False for z in zombies: zx, zy, zangle = z relative_angle = degrees(atan2(zy - y, zx - x)) if relative_angle < 0: relative_angle += 360 #[0, 360] center_sector = round(relative_angle / 15) z_distance_sqr = (zx - x)**2 + (zy - y)**2 for sector in range(center_sector - 11, center_sector + 11): dir_score[sector % 24] -= 1 / ( (abs(sector - center_sector) + 1) * z_distance_sqr) #score if z_distance_sqr < Bot.alertRadius * Bot.alertRadius: zombie_in_sight = True input() if not zombie_in_sight: return "ui" for s in range(24): wangle = s * 15 wallDistance = self.world.rayCastWall((x, y), wangle) if wallDistance < 2: dir_score[s] = -99999 else: dir_score[s] -= 1 / self.world.rayCastWall((x, y), wangle)**2 now_heading_index = round(degrees(angle) / 15) % 24 best_index = dir_score.index(max(dir_score)) if dir_score[now_heading_index] == max(dir_score): return "uu" else: # if best_index - now_heading_index < -12 or 0 < best_index - now_heading_index < 12: # return "ul" # else: # return "ur" angle_diff_rad = radians(abs(best_index - now_heading_index) * 15) if best_index > now_heading_index: return "ul" + str(angle_diff_rad) else: return "ur" + str(angle_diff_rad)