예제 #1
0
 def __init__(self,  **kwargs):
     self.kwargs = kwargs
     self.window_name = kwargs.get("window_name")
     self.is_launched = True
     self.if_move_window = kwargs.get('move_window')
     self.window_controller = WindowController()
     self.game_launcher = ExecutableGameLauncher(**kwargs)
예제 #2
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.config = config.get(f"{self.__class__.__name__}Plugin")

        self.platform = kwargs.get("platform")

        self.window_id = None
        self.window_name = kwargs.get("window_name")
        self.window_geometry = None

        self.window_controller = WindowController()

        self.is_launched = False

        self.frame_grabber_process = None
        self.game_frame_limiter = GameFrameLimiter(
            fps=self.config.get("fps", 4))

        self.api_class = None
        self.api_instance = None

        self.sprites = self._discover_sprites()

        self.redis_client = StrictRedis(**config["redis"])

        self.kwargs = kwargs
예제 #3
0
def window_name():
    clear_terminal()
    print("Open the Game manually.")

    input("\nPress Enter and then focus the game window...")

    window_controller = WindowController()

    time.sleep(5)

    focused_window_name = window_controller.get_focused_window_name()

    print(
        f"\nGame Window Detected! Please set the kwargs['window_name'] value in the Game plugin to:"
    )
    print("\n" + focused_window_name + "\n")
예제 #4
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.config = config.get(f"{self.__class__.__name__}Plugin", dict())

        self.platform = kwargs.get("platform")

        default_input_controller_backend = InputControllers.CLIENT
        self.input_controller = kwargs.get(
            "input_controller") or default_input_controller_backend

        self.window_id = None
        self.window_name = kwargs.get("window_name")
        self.window_geometry = None

        self.dashboard_window_id = None

        self.window_controller = WindowController()

        self.is_launched = False

        self.frame_grabber_process = None
        self.frame_transformation_pipeline_string = None

        self.crossbar_process = None
        self.input_controller_process = None

        self.game_frame_limiter = GameFrameLimiter(
            fps=self.config.get("fps", 30))

        self.api_class = None
        self.api_instance = None

        self.environments = dict()
        self.environment_data = dict()

        self.sprites = self._discover_sprites()

        self.redis_client = StrictRedis(**config["redis"])

        self.pause_callback_fired = False

        self.kwargs = kwargs
예제 #5
0
class Game:
    def __init__(self,  **kwargs):
        self.kwargs = kwargs
        self.window_name = kwargs.get("window_name")
        self.is_launched = True
        self.if_move_window = kwargs.get('move_window')
        self.window_controller = WindowController()
        self.game_launcher = ExecutableGameLauncher(**kwargs)



    def launch(self, dry_run=False):
        self.before_launch()

        if not dry_run:
            self.game_launcher.launch(**self.kwargs)

        self.after_launch()

    def before_launch(self):
        pass


    def after_launch(self):
        self.is_launched = True

        time.sleep(3)

        self.window_id = self.window_controller.locate_window(self.window_name)
        if self.if_move_window:
            self.window_controller.move_window(self.window_id, 0, 0)
        self.window_controller.focus_window(self.window_id)

        self.window_geometry = self.extract_window_geometry()

        print(self.window_geometry)
        return self.window_geometry

    def extract_window_geometry(self):
        if self.is_launched:
            return self.window_controller.get_window_geometry(self.window_id)

        return None

    def is_focused(self):
        return self.window_controller.is_window_focused(self.window_id)
예제 #6
0
class Game(offshoot.Pluggable):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.config = config.get(f"{self.__class__.__name__}Plugin", dict())

        self.platform = kwargs.get("platform")

        default_input_controller_backend = InputControllers.CLIENT
        self.input_controller = kwargs.get(
            "input_controller") or default_input_controller_backend

        self.window_id = None
        self.window_name = kwargs.get("window_name")
        self.window_geometry = None

        self.dashboard_window_id = None

        self.window_controller = WindowController()

        self.is_launched = False

        self.frame_grabber_process = None
        self.frame_transformation_pipeline_string = None

        self.crossbar_process = None
        self.input_controller_process = None

        self.game_frame_limiter = GameFrameLimiter(
            fps=self.config.get("fps", 30))

        self.api_class = None
        self.api_instance = None

        self.environments = dict()
        self.environment_data = dict()

        self.sprites = self._discover_sprites()

        self.redis_client = StrictRedis(**config["redis"])

        self.pause_callback_fired = False

        self.kwargs = kwargs

    @property
    @offshoot.forbidden
    def game_name(self):
        return self.__class__.__name__.replace("Serpent",
                                               "").replace("Game", "")

    @property
    @offshoot.forbidden
    def game_launcher(self):
        return self.game_launchers.get(self.platform)

    @property
    @offshoot.forbidden
    def game_launchers(self):
        return {
            "steam": SteamGameLauncher,
            "executable": ExecutableGameLauncher,
            "web_browser": WebBrowserGameLauncher
        }

    @property
    @offshoot.expected
    def screen_regions(self):
        raise NotImplementedError()

    @property
    @offshoot.forbidden
    def api(self):
        if self.api_instance is None:
            self.api_instance = self.api_class(game=self)
        else:
            return self.api_instance

    @property
    @offshoot.forbidden
    def is_focused(self):
        return self.window_controller.is_window_focused(self.window_id)

    @offshoot.forbidden
    def launch(self, dry_run=False):
        self.before_launch()

        if not dry_run:
            self.game_launcher().launch(**self.kwargs)

        self.after_launch()

    @offshoot.forbidden
    def relaunch(self, before_relaunch=None, after_relaunch=None):
        clear_terminal()
        print("")
        print("Relaunching the game...")

        self.stop_frame_grabber()

        time.sleep(1)

        if before_relaunch is not None:
            before_relaunch()

        time.sleep(1)

        subprocess.call(shlex.split(f"serpent launch {self.game_name}"))
        self.launch(dry_run=True)

        self.start_frame_grabber()
        self.redis_client.delete(config["frame_grabber"]["redis_key"])

        while self.redis_client.llen(
                config["frame_grabber"]["redis_key"]) == 0:
            time.sleep(0.1)

        self.window_controller.focus_window(self.window_id)

        if after_relaunch is not None:
            after_relaunch()

    def before_launch(self):
        pass

    def after_launch(self):
        self.is_launched = True

        current_attempt = 1

        while current_attempt <= 100:
            self.window_id = self.window_controller.locate_window(
                self.window_name)

            if self.window_id not in [0, "0"]:
                break

            time.sleep(0.1)

        time.sleep(3)

        if self.window_id in [0, "0"]:
            raise SerpentError("Game window not found...")

        self.window_controller.move_window(self.window_id, 0, 0)

        self.dashboard_window_id = self.window_controller.locate_window(
            "Serpent.AI Dashboard")

        # TODO: Test on macOS and Linux
        if self.dashboard_window_id is not None and self.dashboard_window_id not in [
                0, "0"
        ]:
            self.window_controller.bring_window_to_top(
                self.dashboard_window_id)

        self.window_controller.focus_window(self.window_id)

        self.window_geometry = self.extract_window_geometry()

        print(self.window_geometry)

    def play(self,
             game_agent_class_name="GameAgent",
             frame_handler=None,
             **kwargs):
        if not self.is_launched:
            raise GameError(
                f"Game '{self.__class__.__name__}' is not running...")

        self.start_crossbar()
        time.sleep(3)

        self.start_input_controller()

        game_agent_class = offshoot.discover(
            "GameAgent",
            selection=game_agent_class_name).get(game_agent_class_name,
                                                 GameAgent)

        if game_agent_class is None:
            raise GameError(
                "The provided Game Agent class name does not map to an existing class..."
            )

        game_agent = game_agent_class(game=self,
                                      input_controller=InputController(
                                          game=self,
                                          backend=self.input_controller),
                                      **kwargs)

        # Look if we need to auto-append PNG to frame transformation pipeline based on given frame_handler
        png_frame_handlers = ["RECORD"]

        if frame_handler in png_frame_handlers and self.frame_transformation_pipeline_string is not None:
            if not self.frame_transformation_pipeline_string.endswith("|PNG"):
                self.frame_transformation_pipeline_string += "|PNG"

        self.start_frame_grabber()
        self.redis_client.delete(config["frame_grabber"]["redis_key"])

        while self.redis_client.llen(
                config["frame_grabber"]["redis_key"]) == 0:
            time.sleep(0.1)

        self.window_controller.focus_window(self.window_id)

        # Override FPS Config?
        if frame_handler == "RECORD":
            self.game_frame_limiter = GameFrameLimiter(fps=10)

        try:
            while True:
                self.game_frame_limiter.start()

                game_frame, game_frame_pipeline = self.grab_latest_frame()

                try:
                    if self.is_focused:
                        self.pause_callback_fired = False
                        game_agent.on_game_frame(game_frame,
                                                 game_frame_pipeline,
                                                 frame_handler=frame_handler,
                                                 **kwargs)
                    else:
                        if not self.pause_callback_fired:
                            print("PAUSED\n")

                            game_agent.on_pause(frame_handler=frame_handler,
                                                **kwargs)
                            self.pause_callback_fired = True

                        time.sleep(1)
                except Exception as e:
                    raise e
                    # print(e)
                    # time.sleep(0.1)

                self.game_frame_limiter.stop_and_delay()
        except Exception as e:
            raise e
        finally:
            self.stop_frame_grabber()
            self.stop_input_controller()
            self.stop_crossbar()

    @offshoot.forbidden
    def extract_window_geometry(self):
        if self.is_launched:
            return self.window_controller.get_window_geometry(self.window_id)

        return None

    @offshoot.forbidden
    def start_frame_grabber(self, pipeline_string=None):
        if not self.is_launched:
            raise GameError(
                f"Game '{self.__class__.__name__}' is not running...")

        if self.frame_grabber_process is not None:
            self.stop_frame_grabber()

        frame_grabber_command = f"serpent grab_frames {self.window_geometry['width']} {self.window_geometry['height']} {self.window_geometry['x_offset']} {self.window_geometry['y_offset']}"

        pipeline_string = pipeline_string or self.frame_transformation_pipeline_string

        if pipeline_string is not None:
            frame_grabber_command += f" {pipeline_string}"

        self.frame_grabber_process = subprocess.Popen(
            shlex.split(frame_grabber_command))

        signal.signal(signal.SIGINT, self._handle_signal_frame_grabber)
        signal.signal(signal.SIGTERM, self._handle_signal_frame_grabber)

        atexit.register(self._handle_signal_frame_grabber, 15, None, False)

    @offshoot.forbidden
    def stop_frame_grabber(self):
        if self.frame_grabber_process is None:
            return None

        self.frame_grabber_process.kill()
        self.frame_grabber_process = None

        atexit.unregister(self._handle_signal_frame_grabber)

    @offshoot.forbidden
    def grab_latest_frame(self):
        game_frame_buffer, game_frame_buffer_pipeline = FrameGrabber.get_frames_with_pipeline(
            [0])

        return game_frame_buffer.frames[0], game_frame_buffer_pipeline.frames[
            0]

    @offshoot.forbidden
    def start_crossbar(self):
        if self.crossbar_process is not None:
            self.stop_crossbar()

        crossbar_command = f"crossbar start --config crossbar.json"

        self.crossbar_process = subprocess.Popen(shlex.split(crossbar_command))

        signal.signal(signal.SIGINT, self._handle_signal_crossbar)
        signal.signal(signal.SIGTERM, self._handle_signal_crossbar)

        atexit.register(self._handle_signal_crossbar, 15, None, False)

    @offshoot.forbidden
    def stop_crossbar(self):
        if self.crossbar_process is None:
            return None

        self.crossbar_process.kill()
        self.crossbar_process = None

        atexit.unregister(self._handle_signal_crossbar)

    @offshoot.forbidden
    def start_input_controller(self):
        if self.input_controller_process is not None:
            self.stop_input_controller()

        self.redis_client.set("SERPENT:GAME", self.__class__.__name__)

        input_controller_command = f"python -m serpent.wamp_components.input_controller_component"

        self.input_controller_process = subprocess.Popen(
            shlex.split(input_controller_command))

        signal.signal(signal.SIGINT, self._handle_signal_input_controller)
        signal.signal(signal.SIGTERM, self._handle_signal_input_controller)

        atexit.register(self._handle_signal_input_controller, 15, None, False)

    @offshoot.forbidden
    def stop_input_controller(self):
        if self.input_controller_process is None:
            return None

        self.input_controller_process.kill()
        self.input_controller_process = None

        atexit.unregister(self._handle_signal_input_controller)

    def _discover_sprites(self):
        plugin_path = offshoot.config["file_paths"]["plugins"]
        sprites = dict()

        sprite_path = f"{plugin_path}/{self.__class__.__name__}Plugin/files/data/sprites"

        if os.path.isdir(sprite_path):
            files = os.scandir(sprite_path)

            for file in files:
                if file.name.endswith(".png"):
                    sprite_name = "_".join(
                        file.name.split("/")[-1].split("_")[:-1]).replace(
                            ".png", "").upper()

                    sprite_image_data = skimage.io.imread(
                        f"{sprite_path}/{file.name}")
                    sprite_image_data = sprite_image_data[..., np.newaxis]

                    if sprite_name not in sprites:
                        sprite = Sprite(sprite_name,
                                        image_data=sprite_image_data)
                        sprites[sprite_name] = sprite
                    else:
                        sprites[sprite_name].append_image_data(
                            sprite_image_data)

        return sprites

    def _handle_signal_frame_grabber(self,
                                     signum=15,
                                     frame=None,
                                     do_exit=True):
        if self.frame_grabber_process is not None:
            if self.frame_grabber_process.poll() is None:
                self.frame_grabber_process.send_signal(signum)

                if do_exit:
                    exit()

    def _handle_signal_crossbar(self, signum=15, frame=None, do_exit=True):
        if self.crossbar_process is not None:
            if self.crossbar_process.poll() is None:
                self.crossbar_process.send_signal(signum)

                if do_exit:
                    exit()

    def _handle_signal_input_controller(self,
                                        signum=15,
                                        frame=None,
                                        do_exit=True):
        if self.input_controller_process is not None:
            if self.input_controller_process.poll() is None:
                self.input_controller_process.send_signal(signum)

                if do_exit:
                    exit()
예제 #7
0
class Game(offshoot.Pluggable):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.config = config.get(f"{self.__class__.__name__}Plugin")

        self.platform = kwargs.get("platform")

        self.window_id = None
        self.window_name = kwargs.get("window_name")
        self.window_geometry = None

        self.window_controller = WindowController()

        self.is_launched = False

        self.frame_grabber_process = None
        self.game_frame_limiter = GameFrameLimiter(
            fps=self.config.get("fps", 4))

        self.api_class = None
        self.api_instance = None

        self.sprites = self._discover_sprites()

        self.redis_client = StrictRedis(**config["redis"])

        self.kwargs = kwargs

    @property
    @offshoot.forbidden
    def game_launcher(self):
        return self.game_launchers.get(self.platform)

    @property
    @offshoot.forbidden
    def game_launchers(self):
        return {
            "steam": SteamGameLauncher,
            "executable": ExecutableGameLauncher
        }

    @property
    @offshoot.expected
    def screen_regions(self):
        raise NotImplementedError()

    @property
    @offshoot.expected
    def ocr_presets(self):
        raise NotImplementedError()

    @property
    @offshoot.forbidden
    def api(self):
        if self.api_instance is None:
            self.api_instance = self.api_class(game=self)
        else:
            return self.api_instance

    @property
    @offshoot.forbidden
    def is_focused(self):
        return self.window_controller.is_window_focused(self.window_id)

    @offshoot.forbidden
    def launch(self, dry_run=False):
        self.before_launch()

        if not dry_run:
            self.game_launcher().launch(**self.kwargs)

        self.after_launch()

    def before_launch(self):
        pass

    def after_launch(self):
        self.is_launched = True

        time.sleep(5)

        self.window_id = self.window_controller.locate_window(self.window_name)

        self.window_controller.move_window(self.window_id, 0, 0)
        self.window_controller.focus_window(self.window_id)

        self.window_geometry = self.extract_window_geometry()
        print(self.window_geometry)

    def play(self, game_agent_class_name=None, frame_handler=None, **kwargs):
        if not self.is_launched:
            raise GameError(
                f"Game '{self.__class__.__name__}' is not running...")

        game_agent_class = offshoot.discover("GameAgent").get(
            game_agent_class_name, GameAgent)

        if game_agent_class is None:
            raise GameError(
                "The provided Game Agent class name does not map to an existing class..."
            )

        game_agent = game_agent_class(
            game=self, input_controller=InputController(game=self))

        self.start_frame_grabber()
        self.redis_client.delete(config["frame_grabber"]["redis_key"])

        while self.redis_client.llen(
                config["frame_grabber"]["redis_key"]) == 0:
            time.sleep(0.1)

        self.window_controller.focus_window(self.window_id)

        while True:
            self.game_frame_limiter.start()

            game_frame = self.grab_latest_frame()
            try:
                if self.is_focused:
                    game_agent.on_game_frame(game_frame,
                                             frame_handler=frame_handler,
                                             **kwargs)
                else:
                    serpent.utilities.clear_terminal()
                    print("PAUSED\n")

                    game_agent.on_pause(frame_handler=frame_handler, **kwargs)

                    time.sleep(1)
            except Exception as e:
                raise e
                # print(e)
                # time.sleep(0.1)

            self.game_frame_limiter.stop_and_delay()

    @offshoot.forbidden
    def extract_window_geometry(self):
        if self.is_launched:
            return self.window_controller.get_window_geometry(self.window_id)

        return None

    @offshoot.forbidden
    def start_frame_grabber(self):
        if not self.is_launched:
            raise GameError(
                f"Game '{self.__class__.__name__}' is not running...")

        if self.frame_grabber_process is not None:
            self.stop_frame_grabber()

        frame_grabber_command = f"serpent grab_frames {self.window_geometry['width']} {self.window_geometry['height']} {self.window_geometry['x_offset']} {self.window_geometry['y_offset']}"
        self.frame_grabber_process = subprocess.Popen(
            shlex.split(frame_grabber_command))

        signal.signal(signal.SIGINT, self._handle_signal)
        signal.signal(signal.SIGTERM, self._handle_signal)

        atexit.register(self._handle_signal, 15, None, False)

    @offshoot.forbidden
    def stop_frame_grabber(self):
        if self.frame_grabber_process is None:
            return None

        self.frame_grabber_process.kill()
        self.frame_grabber_process = None

        atexit.unregister(self._handle_signal)

    @offshoot.forbidden
    def grab_latest_frame(self):
        game_frame_buffer = FrameGrabber.get_frames(
            [0], (self.window_geometry.get("height"),
                  self.window_geometry.get("width"), 3))

        return game_frame_buffer.frames[0]

    def _discover_sprites(self):
        plugin_path = offshoot.config["file_paths"]["plugins"]
        sprites = dict()

        sprite_path = f"{plugin_path}/{self.__class__.__name__}Plugin/files/data/sprites"

        if os.path.isdir(sprite_path):
            files = os.scandir(sprite_path)

            for file in files:
                if file.name.endswith(".png"):
                    sprite_name = "_".join(
                        file.name.split("/")[-1].split("_")[:-1]).replace(
                            ".png", "").upper()

                    sprite_image_data = skimage.io.imread(
                        f"{sprite_path}/{file.name}")
                    sprite_image_data = sprite_image_data[..., np.newaxis]

                    if sprite_name not in sprites:
                        sprite = Sprite(sprite_name,
                                        image_data=sprite_image_data)
                        sprites[sprite_name] = sprite
                    else:
                        sprites[sprite_name].append_image_data(
                            sprite_image_data)

        return sprites

    def _handle_signal(self, signum=15, frame=None, do_exit=True):
        if self.frame_grabber_process is not None:
            if self.frame_grabber_process.poll() is None:
                self.frame_grabber_process.send_signal(signum)

                if do_exit:
                    exit()
예제 #8
0
    def __init__(self, fake=False, metrics_key='001'):
        with open('running', 'w') as f:
            f.write(str(os.getpid()))
        
        self._episode_ended = False

        self.game = serpent.initialize_game('T4TF1')

        game_frame = self.game.screen_regions['GAME_REGION']
        self.width = 10
        self.height = 10

        self.state_shape = (int(self.height / 2), int(self.width / 2), 1)
        self._action_spec = array_spec.BoundedArraySpec(
            shape=(), dtype=np.int32, minimum=0, maximum=1, name='action')
        self._observation_spec = array_spec.BoundedArraySpec(
            shape=self.state_shape, dtype=np.float32, minimum=0.0, name='observation')


        self._state = np.zeros(self.state_shape).astype(np.float32)

        if fake:
            return
        self.interrupted = False

        self.game.launch()
        self.game.start_frame_grabber()
        self.input_controller = InputController(game=self.game)
        # self.input_proc = 

        self.frame_buffer = FrameGrabber.get_frames([0])
        self.frame_buffer = self.extract_game_area(self.frame_buffer)

        self.width = self.frame_buffer[0].shape[1]
        self.height = self.frame_buffer[0].shape[0]
        print('width: %d' % self.width)
        print('height: %d' % self.height)
        self.state_shape = (self.height, self.width, 3)
        self._action_spec = array_spec.BoundedArraySpec(
            shape=(), dtype=np.int32, minimum=0, maximum=1, name='action')
        self._observation_spec = array_spec.BoundedArraySpec(
            shape=self.state_shape, dtype=np.float32, minimum=0.0, name='observation')

        self._state = np.zeros(self.state_shape).astype(np.float32)

        # print('created input with pid: %s' % self.input_proc.pid)
        self.sell_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_S]
        self.buy_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_B]
        self.step_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_F]


        self.visual_debugger = VisualDebugger()

        self.scraper = T4Scraper(game=self.game, visual_debugger=self.visual_debugger)
        frame = self.game.grab_latest_frame()
        self.scraper.current_frame = frame
        self.pl = 0
        self.working_trade = 0
        self.current_action = ''
        self.held = False
        self.fill_count = 0

        self.window_controller = WindowController()
        self.window_id = self.window_controller.locate_window(".*Mini-Dow .*")
        # self.window_id = self.window_controller.locate_window(".*S&P .*")

        self.keys = RedisKeys(metrics_key)
#         self.redis = redis.Redis(port=6001)
    
        self.number_of_trades = 0
        self.number_of_wins = 0
        self.buys = 0
        self.sells = 0
        self.holds = 0
        self.history = list()
        self.actions = 0
        self.last_action = ''

        self.previous_write = -1
        self.get_metadata()
        
        self.active_frame = None
        
        self.start_time = time.time()
        
        self.step_read_time = 0
        self.step_write_time = 0
예제 #9
0
class T4TFEnv(py_environment.PyEnvironment):

    def __init__(self, fake=False, metrics_key='001'):
        with open('running', 'w') as f:
            f.write(str(os.getpid()))
        
        self._episode_ended = False

        self.game = serpent.initialize_game('T4TF1')

        game_frame = self.game.screen_regions['GAME_REGION']
        self.width = 10
        self.height = 10

        self.state_shape = (int(self.height / 2), int(self.width / 2), 1)
        self._action_spec = array_spec.BoundedArraySpec(
            shape=(), dtype=np.int32, minimum=0, maximum=1, name='action')
        self._observation_spec = array_spec.BoundedArraySpec(
            shape=self.state_shape, dtype=np.float32, minimum=0.0, name='observation')


        self._state = np.zeros(self.state_shape).astype(np.float32)

        if fake:
            return
        self.interrupted = False

        self.game.launch()
        self.game.start_frame_grabber()
        self.input_controller = InputController(game=self.game)
        # self.input_proc = 

        self.frame_buffer = FrameGrabber.get_frames([0])
        self.frame_buffer = self.extract_game_area(self.frame_buffer)

        self.width = self.frame_buffer[0].shape[1]
        self.height = self.frame_buffer[0].shape[0]
        print('width: %d' % self.width)
        print('height: %d' % self.height)
        self.state_shape = (self.height, self.width, 3)
        self._action_spec = array_spec.BoundedArraySpec(
            shape=(), dtype=np.int32, minimum=0, maximum=1, name='action')
        self._observation_spec = array_spec.BoundedArraySpec(
            shape=self.state_shape, dtype=np.float32, minimum=0.0, name='observation')

        self._state = np.zeros(self.state_shape).astype(np.float32)

        # print('created input with pid: %s' % self.input_proc.pid)
        self.sell_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_S]
        self.buy_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_B]
        self.step_keys = [KeyboardKey.KEY_LEFT_SHIFT, KeyboardKey.KEY_LEFT_CTRL, KeyboardKey.KEY_F]


        self.visual_debugger = VisualDebugger()

        self.scraper = T4Scraper(game=self.game, visual_debugger=self.visual_debugger)
        frame = self.game.grab_latest_frame()
        self.scraper.current_frame = frame
        self.pl = 0
        self.working_trade = 0
        self.current_action = ''
        self.held = False
        self.fill_count = 0

        self.window_controller = WindowController()
        self.window_id = self.window_controller.locate_window(".*Mini-Dow .*")
        # self.window_id = self.window_controller.locate_window(".*S&P .*")

        self.keys = RedisKeys(metrics_key)
#         self.redis = redis.Redis(port=6001)
    
        self.number_of_trades = 0
        self.number_of_wins = 0
        self.buys = 0
        self.sells = 0
        self.holds = 0
        self.history = list()
        self.actions = 0
        self.last_action = ''

        self.previous_write = -1
        self.get_metadata()
        
        self.active_frame = None
        
        self.start_time = time.time()
        
        self.step_read_time = 0
        self.step_write_time = 0
        

    def get_state(self, zeros=False):
        if zeros:
            return np.zeros(self.state_shape).astype(np.float32)
            self.frame_history = [
                np.zeros((int(self.width / 4), int(self.height / 4))).astype(np.float32),
                np.zeros((int(self.width / 4), int(self.height / 4))).astype(np.float32),
                np.zeros((int(self.width / 4), int(self.height / 4))).astype(np.float32),
                np.zeros((int(self.width / 4), int(self.height / 4))).astype(np.float32)
            ]
            
        st = np.stack(
            self.frame_history,
            axis=2
        ).astype(np.float32)
        
        print(st.shape)
        return st

    
    def is_focused(self):
        return self.window_controller.is_window_focused(self.window_id)

    def display_frame(self):
        frame = self.game.grab_latest_frame()
        self.visual_debugger.store_image_data(
                frame.frame,
                frame.frame.shape,
                2
            )

    def action_spec(self):
        return self._action_spec

    def observation_spec(self):
        return self._observation_spec

    def _reset(self):
        print('RESTARTING')
        self._state = np.zeros(self.state_shape).astype(np.float32)
        self._episode_ended = False
        return ts.restart(self._state)


    def update_scraper_frame(self):
        self.scraper.current_frame = self.game.grab_latest_frame()
        self.visual_debugger.store_image_data(
            self.scraper.current_frame.frame,
            self.scraper.current_frame.frame.shape,
            str(2)
        )

    def stop(self):
        self.input_proc.kill()
        self.game.stop_frame_grabber()
        return ts.termination(self._state, 0)
    
    def write_order(self, order_type):
        write_start = time.time()
#         if order_type is self.previous_write: return
        with open('/home/dan/.wine/drive_c/input.txt', 'w') as f:
            f.write('%d' % (order_type))
        
        self.step_write_time += (time.time() - write_start)
        self.previous_write = order_type

    def step_forward(self):
        self.write_order(3)
        
    def add_to_history(self, frame, action, reward):
        history_start = time.time()
        im = Image.fromarray(frame)
        im.save('history/%d_%d_%f.jpg' % (int(datetime.now().timestamp() * 100), action, reward))
        print("history add time: %s seconds" % (time.time() - history_start))
#     def log(self, string):
#         if self.actions % 200 == 0:
#             print(string)
#      
    def _step(self, action):
        self.step_read_time = 0
        self.step_write_time = 0
        
        if self.interrupted:
            return self.stop()

        print('----')
        if self._episode_ended:
        # The last action ended the episode. Ignore the current action and start
        # a new episode.
            return self.reset()

        if action == 0:
            # perform buy
            self.current_action = 'buy'
            self.working_trade = True
            # self.input_controller.tap_keys(self.buy_keys, duration=0.001)
            self.write_order(action)

        elif action == 1:
            # perform sell
            self.current_action = 'sell'
            self.working_trade = True
            # self.input_controller.tap_keys(self.sell_keys, duration=0.001)
            self.write_order(action)
        elif action == 2:
            print('hold')
            self.current_action = 'hold'
            y = 0 
            while y < 3:
#                 self.write_order(action)
                self.step_forward()
                sleep(0.1)
                y = y + 1
                
        self.actions += 1

        if action < 2:
            self.number_of_trades += 1
        
            while not self.has_open_positions():
                sleep(0.01)

                if self.interrupted:
                    return self.stop()


            while self.has_open_positions():
                self.step_forward()
                sleep(0.01)

                if self.interrupted:
                    return self.stop()
        
        
        self.write_order(4)
        
        
        sleep(0.2)
        reward = self.reward_agent()

        if self.actions > 1:
            self.add_to_history(self.active_frame, action, reward)

        start_grab_frame = time.time()
        self.frame_buffer = FrameGrabber.get_frames([0])
        self.frame_buffer = self.extract_game_area(self.frame_buffer)
        print("frame grab time: %s seconds" % (time.time() - start_grab_frame))
        self.active_frame = self.frame_buffer[0]
#         for i, game_frame in enumerate(self.frame_buffer):
#             if i >= 3: break
#             self.visual_debugger.store_image_data(
#                 game_frame,
#                 game_frame.shape,
#                 str(i)
#             )
        print(self.frame_buffer[0].shape)    

#         self.frame_history.insert(0, self.frame_buffer[0])
        
#         self._states = self.get_state()
        states_shape = self.state_shape
        print(states_shape)
        self._states = np.reshape(self.frame_buffer[0], (states_shape[0], states_shape[1], states_shape[2])).astype(np.float32)
        print(self._states.shape)
        if self.number_of_trades > 0:
            self.push_metadata(action=self.current_action, reward=reward)
        
            print('Wins: %d%% - %d / %d' % ((self.number_of_wins / self.number_of_trades * 100), self.number_of_wins, self.number_of_trades))
            
        
        # print history
        
        if len(self.history) > 0:
            historical_wins = len(list(filter(lambda x: x[1] > 0, self.history)))
            print('Wins (last %d): %d%%' % (len(self.history), (historical_wins / len(self.history) * 100)))
        
        print('Buys: %d' % self.buys)
        print('Sells: %d' % self.sells)
        print('Holds: %d' % self.holds)
        
        print('Step read time: %s' % self.step_read_time)
        print('Step write time: %s' % self.step_write_time)
        # print(states.shape)
        return ts.transition(self._states, reward=reward, discount=1.0)

    def read_position_and_pl(self):
        read_start = time.time()
        result = ['','']
        while len(result[0]) < 1 or len(result[1]) < 1:
            with open('/home/dan/.wine/drive_c/output.txt', 'r') as f:
                result = [x.strip() for x in f.read().split(',')]
        
        self.step_read_time += (time.time() - read_start)
        return (int(result[0]), int(result[1]))

    def has_open_positions(self):
        result = self.read_position_and_pl()
        pos = result[0]
        pl = result[1]
        
        # if self.working_trade:
        #     if pos != 0:
        #         self.working_trade = False
        #     else:
        #         if pl != self.pl:
        #             self.working_trade = False
        #             return False
        #         else:
        #             return True
        
        if pos != 0:
            return True
        return False

    def reward_agent(self):
        # get pl for last trade

        newPL = self.read_position_and_pl()[1]
        print('old pl: %d' % self.pl)
        print('new pl: %d' % newPL)
        if newPL > self.pl:
            reward = 1.0
        else:
            reward = -1.0

        if self.current_action is 'hold':
            reward = -0.25
        else:
            if reward > 0:
                if self.last_action is 'hold':
                    reward = 1.25
        # if reward is 1.0:
        #     if self.current_action is 'buy' and self.buys > self.sells:
        #         reward = 0.8
        #     elif self.current_action is 'sell' and self.sells > self.buys:
        #         reward = 0.8
        # elif reward is -1.0:
        #     if self.current_action is 'sell' and self.buys > self.sells:
        #         reward = -0.8
        #     elif self.current_action is 'buy' and self.sells > self.buys:
        #         reward = -0.8
                
        
        self.last_action = self.current_action
        print('REWARD: %f' % reward)
        self.pl = newPL
        return reward
        
    def extract_game_area(self, frame_buffer):
        game_area_buffer = []
#         for game_frame in frame_buffer.frames:
#             game_area = cv.extract_region_from_image(
#                 game_frame.grayscale_frame,
#                 self.game.screen_regions["GAME_REGION"]
#             )

        frame = frame_buffer.frames[0].quarter_resolution_frame
#         frame = FrameTransformer.rescale(frame_buffer.frames[0].grayscale_frame, 0.5)
        game_area_buffer.append(frame)

        return game_area_buffer


    def get_metadata(self):
        return
        if self.redis.exists(self.keys.trades):
            self.number_of_trades = self.redis.llen(self.keys.trades)
            
            self.history = list()
            history_strings = self.redis.lrange(self.keys.trades, -100, 100)
            for s in history_strings:
                d = json.loads(s)
                self.history.append((d['action'], float(d['reward'])))
        
        if self.redis.exists(self.keys.wins):
            self.number_of_wins = int(self.redis.get(self.keys.wins))
            
        if self.redis.exists(self.keys.buys):
            self.buys = int(self.redis.get(self.keys.buys))
        
        if self.redis.exists(self.keys.sells):
            self.sells = int(self.redis.get(self.keys.sells))
        
        if self.redis.exists(self.keys.holds):
            self.holds = int(self.redis.get(self.keys.holds))

    def push_metadata(self, action, reward, reset=False):
        return
        if action is None:
            return
            
        # last 100
        if not action is 'hold':
            while len(self.history) >= 100:
                self.history.pop(0)    
    
            self.history.append((action, reward))

        
        obj = {
            'timestamp':str(datetime.now().timestamp()),
            'action': action,
            'reward': str(reward)
        }
        
        self.redis.rpush(self.keys.trades, json.dumps(obj))
        
        if action == 'buy':
            self.buys += 1
            self.redis.incr(self.keys.buys)
        elif action == 'sell':
            self.sells += 1
            self.redis.incr(self.keys.sells)
        elif action == 'hold':
            self.holds += 1
            self.redis.incr(self.keys.holds)
            
        if reward > 0:
            self.number_of_wins += 1
            self.redis.incr(self.keys.wins)
            
        if reset:
            self.redis.set(self.keys.buys, "0")
            self.redis.set(self.keys.sells, "0")
            self.redis.set(self.keys.wins, "0")
            self.redis.set(self.keys.trades, "0")
            self.redis.set(self.keys.holds, "0")