|
import numpy as np |
|
from dataclasses import dataclass |
|
|
|
import param_ |
|
from settings import Settings |
|
from drone import Drone |
|
|
|
|
|
@dataclass |
|
class Playground: |
|
""" |
|
This is a cylindrical 3D-env where blue drones defend a central zone from the attack of red drones |
|
the playground manages also the interactions between foe-drones such as the firing |
|
""" |
|
|
|
perimeter = Settings.perimeter |
|
perimeter_z = Settings.perimeter_z |
|
groundzone = Settings.groundzone |
|
|
|
env: object |
|
blue_drones: [Drone] |
|
red_drones: [Drone] |
|
|
|
def __post_init__(self): |
|
|
|
self.blues_have_fired_reds = np.zeros(shape=(len(self.blue_drones), |
|
len(self.red_drones)), dtype=int) |
|
self.reds_have_fired_blues = np.zeros(shape=(len(self.red_drones), |
|
len(self.blue_drones)), dtype=int) |
|
|
|
|
|
self.blue_shots_to_kill = param_.DRONE_MODELS[param_.DRONE_MODEL[True]]['duration_to_neutralisation'] |
|
self.red_shots_to_kill = param_.DRONE_MODELS[param_.DRONE_MODEL[False]]['duration_to_neutralisation'] |
|
self.blue_shots_to_kill //= param_.STEP |
|
self.red_shots_to_kill //= param_.STEP |
|
|
|
|
|
self.distance_blue_shot = param_.DRONE_MODELS[param_.DRONE_MODEL[True]]['distance_to_neutralisation'] |
|
self.distance_red_shot = param_.DRONE_MODELS[param_.DRONE_MODEL[False]]['distance_to_neutralisation'] |
|
|
|
def reset(self): |
|
self.blues_have_fired_reds[...] = 0 |
|
self.reds_have_fired_blues[...] = 0 |
|
|
|
def get_observation(self): |
|
return self.blues_have_fired_reds / self.blue_shots_to_kill, \ |
|
self.reds_have_fired_blues / self.red_shots_to_kill |
|
|
|
def step(self): |
|
""" |
|
determines who has fired who, and who is dead in the end |
|
:return: Tuple with list of Blue and Reds dead. (if a blue or a red is dead, the sequence is over) |
|
""" |
|
|
|
blues_fire_reds = np.array([[blue.fires_(red) for red in self.red_drones] for blue in self.blue_drones]) |
|
reds_fire_blues = np.array([[red.fires_(blue) for blue in self.blue_drones] for red in self.red_drones]) |
|
|
|
|
|
self.blues_have_fired_reds *= blues_fire_reds |
|
self.reds_have_fired_blues *= reds_fire_blues |
|
|
|
|
|
self.blues_have_fired_reds += blues_fire_reds |
|
self.reds_have_fired_blues += reds_fire_blues |
|
|
|
|
|
red_deads = np.unique(np.argwhere(self.blues_have_fired_reds >= self.blue_shots_to_kill).T[1]) |
|
blue_deads = np.unique(np.argwhere(self.reds_have_fired_blues >= self.red_shots_to_kill).T[1]) |
|
|
|
|
|
|
|
for drone_id in blue_deads: |
|
self.blue_drones[drone_id].is_killed(is_blue=True) |
|
for drone_id in red_deads: |
|
self.red_drones[drone_id].is_killed(is_blue=False) |
|
|
|
|
|
blue_drones = [drone for drone in self.blue_drones if drone.is_alive] |
|
red_drones = [drone for drone in self.red_drones if drone.is_alive] |
|
|
|
bf_obs, rf_obs = self.get_observation() |
|
bf_reward = rf_reward = 0 |
|
remaining_blues, remaining_reds = len(blue_drones), len(red_drones), |
|
blue_shots, red_shots = len(blue_deads), len(red_deads) |
|
|
|
if blue_shots + red_shots > 0: |
|
print('someone is killed: {0} blues and {1} reds'.format(blue_shots, red_shots)) |
|
|
|
return bf_obs, bf_reward, remaining_blues, blue_shots, rf_obs, rf_reward, remaining_reds, red_shots |
|
|
|
|
|
|
|
|