| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  | import gym | 
					
						
							|  |  |  | import numpy as np | 
					
						
							|  |  |  | from abc import ABC, abstractmethod | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  | from typing import Any, List, Tuple, Optional, Callable | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class EnvWorker(ABC): | 
					
						
							|  |  |  |     """An abstract worker for an environment.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, env_fn: Callable[[], gym.Env]) -> None: | 
					
						
							|  |  |  |         self._env_fn = env_fn | 
					
						
							|  |  |  |         self.is_closed = False | 
					
						
							| 
									
										
										
										
											2020-09-13 19:31:50 +08:00
										 |  |  |         self.result: Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] | 
					
						
							| 
									
										
										
										
											2021-03-02 12:28:28 +08:00
										 |  |  |         self.action_space = getattr(self, "action_space") | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @abstractmethod | 
					
						
							|  |  |  |     def __getattr__(self, key: str) -> Any: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abstractmethod | 
					
						
							|  |  |  |     def reset(self) -> Any: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abstractmethod | 
					
						
							|  |  |  |     def send_action(self, action: np.ndarray) -> None: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-30 16:06:03 +08:00
										 |  |  |     def get_result(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  |         return self.result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  |     def step( | 
					
						
							|  |  |  |         self, action: np.ndarray | 
					
						
							|  |  |  |     ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: | 
					
						
							| 
									
										
										
										
											2020-09-11 07:55:37 +08:00
										 |  |  |         """Perform one timestep of the environment's dynamic.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         "send_action" and "get_result" are coupled in sync simulation, so | 
					
						
							|  |  |  |         typically users only call "step" function. But they can be called | 
					
						
							|  |  |  |         separately in async simulation, i.e. someone calls "send_action" first, | 
					
						
							|  |  |  |         and calls "get_result" later. | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.send_action(action) | 
					
						
							|  |  |  |         return self.get_result() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  |     def wait( | 
					
						
							| 
									
										
										
										
											2021-03-30 16:06:03 +08:00
										 |  |  |         workers: List["EnvWorker"], wait_num: int, timeout: Optional[float] = None | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  |     ) -> List["EnvWorker"]: | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  |         """Given a list of workers, return those ready ones.""" | 
					
						
							|  |  |  |         raise NotImplementedError | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  |     def seed(self, seed: Optional[int] = None) -> Optional[List[int]]: | 
					
						
							| 
									
										
										
										
											2021-03-02 12:28:28 +08:00
										 |  |  |         return self.action_space.seed(seed)  # issue 299 | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @abstractmethod | 
					
						
							| 
									
										
										
										
											2020-09-12 15:39:01 +08:00
										 |  |  |     def render(self, **kwargs: Any) -> Any: | 
					
						
							|  |  |  |         """Render the environment.""" | 
					
						
							| 
									
										
										
										
											2020-08-19 15:00:24 +08:00
										 |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @abstractmethod | 
					
						
							|  |  |  |     def close_env(self) -> None: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self) -> None: | 
					
						
							|  |  |  |         if self.is_closed: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  |         self.is_closed = True | 
					
						
							|  |  |  |         self.close_env() |