def test_tilemap_position_list():
    pyboy = PyBoy(supermarioland_rom, window_type="headless")
    for _ in range(100):
        pyboy.tick()

    # Start the game
    pyboy.send_input(WindowEvent.PRESS_BUTTON_START)
    pyboy.tick()
    pyboy.send_input(WindowEvent.RELEASE_BUTTON_START)

    # Move right for 100 frame
    pyboy.send_input(WindowEvent.PRESS_ARROW_RIGHT)
    for _ in range(100):
        pyboy.tick()

    # Get screen positions, and verify the values
    positions = pyboy.botsupport_manager().screen().tilemap_position_list()
    for y in range(1, 16):
        assert positions[y][0] == 0  # HUD
    for y in range(16, 144):
        assert positions[y][0] == 49  # Actual screen position

    # Progress another 10 frames to see and increase in SCX
    for _ in range(10):
        pyboy.tick()

    # Get screen positions, and verify the values
    positions = pyboy.botsupport_manager().screen().tilemap_position_list()
    for y in range(1, 16):
        assert positions[y][0] == 0  # HUD
    for y in range(16, 144):
        assert positions[y][0] == 59  # Actual screen position

    pyboy.stop(save=False)
Exemple #2
0
def test_dmg_acid():
    # Has to be in here. Otherwise all test workers will import the file, and cause an error.
    dmg_acid_file = "dmg_acid2.gb"
    if not os.path.isfile(dmg_acid_file):
        print(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/LICENSE.dmg-acid2.txt").read())
        dmg_acid_data = urllib.request.urlopen(
            "https://pyboy.dk/mirror/dmg-acid2.gb").read()
        with open(dmg_acid_file, "wb") as rom_file:
            rom_file.write(dmg_acid_data)

    pyboy = PyBoy(dmg_acid_file, window_type="headless")
    pyboy.set_emulation_speed(0)
    for _ in range(59):
        pyboy.tick()

    for _ in range(25):
        pyboy.tick()

    png_path = Path(f"test_results/{dmg_acid_file}.png")
    image = pyboy.botsupport_manager().screen().screen_image()
    if OVERWRITE_PNGS:
        png_path.parents[0].mkdir(parents=True, exist_ok=True)
        image.save(png_path)
    else:
        old_image = PIL.Image.open(png_path)
        diff = PIL.ImageChops.difference(image, old_image)
        if diff.getbbox() and not os.environ.get("TEST_CI"):
            image.show()
            old_image.show()
            diff.show()
        assert not diff.getbbox(), f"Images are different! {dmg_acid_file}"

    pyboy.stop(save=False)
Exemple #3
0
def test_mooneye(clean, rom):
    global saved_state
    # Has to be in here. Otherwise all test workers will import this file, and cause an error.
    mooneye_dir = "mooneye"
    if not os.path.isdir(mooneye_dir):
        print(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/LICENSE.mooneye.txt").read())
        mooneye_data = io.BytesIO(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/mooneye.zip").read())
        with ZipFile(mooneye_data) as _zip:
            _zip.extractall(mooneye_dir)

    if saved_state is None:
        # HACK: We load any rom and load it until the last frame in the boot rom.
        # Then we save it, so we won't need to redo it.
        pyboy = PyBoy(default_rom, window_type="dummy")
        pyboy.set_emulation_speed(0)
        saved_state = io.BytesIO()
        for _ in range(59):
            pyboy.tick()
        pyboy.save_state(saved_state)
        pyboy.stop(save=False)

    pyboy = PyBoy(rom, window_type="headless")
    pyboy.set_emulation_speed(0)
    saved_state.seek(0)
    if clean:
        for _ in range(59):
            pyboy.tick()
    else:
        pyboy.load_state(saved_state)

    for _ in range(180 if "div_write" in rom else 40):
        pyboy.tick()

    png_path = Path(f"test_results/{rom}.png")
    image = pyboy.botsupport_manager().screen().screen_image()
    if OVERWRITE_PNGS:
        png_path.parents[0].mkdir(parents=True, exist_ok=True)
        image.save(png_path)
    else:
        old_image = PIL.Image.open(png_path)
        if "acceptance" in rom:
            # The registers are too volatile to depend on. We crop the top out, and only match the assertions.
            diff = PIL.ImageChops.difference(image.crop((0, 72, 160, 144)),
                                             old_image.crop((0, 72, 160, 144)))
        else:
            diff = PIL.ImageChops.difference(image, old_image)

        if diff.getbbox() and not os.environ.get("TEST_CI"):
            image.show()
            old_image.show()
            diff.show()
        assert not diff.getbbox(), f"Images are different! {rom}"

    pyboy.stop(save=False)
Exemple #4
0
def test_screen_buffer_and_image():
    cformat = "RGBA"
    boot_logo_hash_predigested = b"=\xff\xf9z 6\xf0\xe9\xcb\x05J`PM5\xd4rX+\x1b~z\xef1\xe0\x82\xc4t\x06\x82\x12C"
    boot_logo_hash_predigested = \
        b"s\xd1R\x88\xe0a\x14\xd0\xd2\xecOk\xe8b\xae.\x0e\x1e\xb6R\xc2\xe9:\xa2\x0f\xae\xa2\x89M\xbf\xd8|"

    pyboy = PyBoy(any_rom, window_type="headless", bootrom_file=boot_rom)
    pyboy.set_emulation_speed(0)
    for n in range(275): # Iterate to boot logo
        pyboy.tick()

    assert pyboy.botsupport_manager().screen().raw_screen_buffer_dims() == (160, 144)
    assert pyboy.botsupport_manager().screen().raw_screen_buffer_format() == cformat

    boot_logo_hash = hashlib.sha256()
    boot_logo_hash.update(pyboy.botsupport_manager().screen().raw_screen_buffer())
    assert boot_logo_hash.digest() == boot_logo_hash_predigested
    assert isinstance(pyboy.botsupport_manager().screen().raw_screen_buffer(), bytes)

    # The output of `screen_image` is supposed to be homogeneous, which means a shared hash between versions.
    boot_logo_png_hash_predigested = (
        b"\x1b\xab\x90r^\xfb\x0e\xef\xf1\xdb\xf8\xba\xb6:^\x01"
        b"\xa4\x0eR&\xda9\xfcg\xf7\x0f|\xba}\x08\xb6$"
    )
    boot_logo_png_hash = hashlib.sha256()
    image = pyboy.botsupport_manager().screen().screen_image()
    assert isinstance(image, PIL.Image.Image)
    image_data = io.BytesIO()
    image.save(image_data, format="BMP")
    boot_logo_png_hash.update(image_data.getvalue())
    assert boot_logo_png_hash.digest() == boot_logo_png_hash_predigested

    # Screenshot shortcut
    image1 = pyboy.botsupport_manager().screen().screen_image()
    image2 = pyboy.screen_image()
    diff = ImageChops.difference(image1, image2)
    assert not diff.getbbox()

    # screen_ndarray
    numpy_hash = hashlib.sha256()
    numpy_array = np.ascontiguousarray(pyboy.botsupport_manager().screen().screen_ndarray())
    assert isinstance(pyboy.botsupport_manager().screen().screen_ndarray(), np.ndarray)
    assert numpy_array.shape == (144, 160, 3)
    numpy_hash.update(numpy_array.tobytes())
    assert numpy_hash.digest(
    ) == (b"\r\t\x87\x131\xe8\x06\x82\xcaO=\n\x1e\xa2K$"
          b"\xd6\x8e\x91R( H7\xd8a*B+\xc7\x1f\x19")

    pyboy.stop(save=False)
Exemple #5
0
def test_shonumi(rom):
    # Has to be in here. Otherwise all test workers will import this file, and cause an error.
    shonumi_dir = "GB Tests"
    if not os.path.isdir(shonumi_dir):
        print(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/SOURCE.GBTests.txt").read())
        shonumi_data = io.BytesIO(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/GB%20Tests.zip").read())
        with ZipFile(shonumi_data) as _zip:
            _zip.extractall(shonumi_dir)

    pyboy = PyBoy(rom,
                  window_type="headless",
                  color_palette=(0xFFFFFF, 0x999999, 0x606060, 0x000000))
    pyboy.set_emulation_speed(0)

    # sprite_suite.gb
    # 60 PyBoy Boot
    # 23 Loading
    # 50 Progress to screenshot
    for _ in range(60 + 23 + 50):
        pyboy.tick()

    png_path = Path(f"test_results/{rom}.png")
    png_path.parents[0].mkdir(parents=True, exist_ok=True)
    image = pyboy.botsupport_manager().screen().screen_image()

    old_image = PIL.Image.open(png_path)
    old_image = old_image.resize(image.size, resample=PIL.Image.NEAREST)
    diff = PIL.ImageChops.difference(image, old_image)

    if diff.getbbox() and not os.environ.get("TEST_CI"):
        image.show()
        old_image.show()
        diff.show()
    assert not diff.getbbox(), f"Images are different! {rom}"

    pyboy.stop(save=False)
Exemple #6
0
def test_tiles():
    pyboy = PyBoy(default_rom, window_type="headless")
    pyboy.set_emulation_speed(0)
    for _ in range(BOOTROM_FRAMES_UNTIL_LOGO):
        pyboy.tick()

    tile = pyboy.botsupport_manager().tilemap_window().tile(0, 0)
    assert isinstance(tile, Tile)

    tile = pyboy.botsupport_manager().tile(1)
    image = tile.image()
    assert isinstance(image, PIL.Image.Image)
    ndarray = tile.image_ndarray()
    assert isinstance(ndarray, np.ndarray)
    assert ndarray.shape == (8, 8, 4)
    assert ndarray.dtype == np.uint8
    data = tile.image_data()
    assert data.shape == (8, 8)

    assert [[x for x in y] for y in data
           ] == [[0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff],
                 [0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff],
                 [0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff],
                 [0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff],
                 [0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff],
                 [0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff],
                 [0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff],
                 [0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff]]

    for identifier in range(384):
        t = pyboy.botsupport_manager().tile(identifier)
        assert t.tile_identifier == identifier
    with pytest.raises(Exception):
        pyboy.botsupport_manager().tile(-1)
    with pytest.raises(Exception):
        pyboy.botsupport_manager().tile(385)

    pyboy.stop(save=False)
Exemple #7
0
def test_mooneye():
    # Has to be in here. Otherwise all test workers will import the file, and cause an error.
    mooneye_dir = "mooneye"
    if not os.path.isdir(mooneye_dir):
        print(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/LICENSE.mooneye.txt").read())
        mooneye_data = io.BytesIO(
            urllib.request.urlopen(
                "https://pyboy.dk/mirror/mooneye.zip").read())
        with ZipFile(mooneye_data) as _zip:
            _zip.extractall(mooneye_dir)

    test_roms = [
        (False, "mooneye/misc/boot_hwio-C.gb"),
        (False, "mooneye/misc/boot_regs-A.gb"),
        (False, "mooneye/misc/bits/unused_hwio-C.gb"),
        (False, "mooneye/misc/boot_div-A.gb"),
        (False, "mooneye/misc/boot_regs-cgb.gb"),
        (False, "mooneye/misc/boot_div-cgbABCDE.gb"),
        (False, "mooneye/misc/ppu/vblank_stat_intr-C.gb"),
        (False, "mooneye/misc/boot_div-cgb0.gb"),
        (False, "mooneye/manual-only/sprite_priority.gb"),
        # (False, "mooneye/utils/bootrom_dumper.gb"),
        (False, "mooneye/utils/dump_boot_hwio.gb"),
        (False, "mooneye/acceptance/rapid_di_ei.gb"),
        (False, "mooneye/acceptance/oam_dma_start.gb"),
        (False, "mooneye/acceptance/boot_regs-dmgABC.gb"),
        (False, "mooneye/acceptance/reti_timing.gb"),
        (False, "mooneye/acceptance/call_timing.gb"),
        (False, "mooneye/acceptance/reti_intr_timing.gb"),
        (False, "mooneye/acceptance/boot_regs-mgb.gb"),
        (False, "mooneye/acceptance/ei_sequence.gb"),
        (False, "mooneye/acceptance/jp_timing.gb"),
        (False, "mooneye/acceptance/ei_timing.gb"),
        (False, "mooneye/acceptance/oam_dma_timing.gb"),
        (False, "mooneye/acceptance/call_cc_timing2.gb"),
        (False, "mooneye/acceptance/boot_div2-S.gb"),
        (False, "mooneye/acceptance/halt_ime1_timing.gb"),
        (False, "mooneye/acceptance/halt_ime1_timing2-GS.gb"),
        (False, "mooneye/acceptance/timer/tima_reload.gb"),
        (False, "mooneye/acceptance/timer/tma_write_reloading.gb"),
        (False, "mooneye/acceptance/timer/tim10.gb"),
        (False, "mooneye/acceptance/timer/tim00.gb"),
        (False, "mooneye/acceptance/timer/tim11.gb"),
        (False, "mooneye/acceptance/timer/tim01.gb"),
        (False, "mooneye/acceptance/timer/tima_write_reloading.gb"),
        (False, "mooneye/acceptance/timer/tim11_div_trigger.gb"),
        (False, "mooneye/acceptance/timer/div_write.gb"),
        (False, "mooneye/acceptance/timer/tim10_div_trigger.gb"),
        (False, "mooneye/acceptance/timer/tim00_div_trigger.gb"),
        (False, "mooneye/acceptance/timer/rapid_toggle.gb"),
        (False, "mooneye/acceptance/timer/tim01_div_trigger.gb"),
        (False, "mooneye/acceptance/boot_regs-sgb.gb"),
        (False, "mooneye/acceptance/jp_cc_timing.gb"),
        (False, "mooneye/acceptance/call_timing2.gb"),
        (False, "mooneye/acceptance/ld_hl_sp_e_timing.gb"),
        (False, "mooneye/acceptance/push_timing.gb"),
        (False, "mooneye/acceptance/boot_hwio-dmg0.gb"),
        (False, "mooneye/acceptance/rst_timing.gb"),
        (False, "mooneye/acceptance/boot_hwio-S.gb"),
        (False, "mooneye/acceptance/boot_div-dmgABCmgb.gb"),
        (False, "mooneye/acceptance/bits/mem_oam.gb"),
        (False, "mooneye/acceptance/bits/reg_f.gb"),
        (False, "mooneye/acceptance/bits/unused_hwio-GS.gb"),
        (False, "mooneye/acceptance/div_timing.gb"),
        (False, "mooneye/acceptance/ret_cc_timing.gb"),
        (False, "mooneye/acceptance/boot_regs-dmg0.gb"),
        (False, "mooneye/acceptance/interrupts/ie_push.gb"),
        (False, "mooneye/acceptance/boot_hwio-dmgABCmgb.gb"),
        (False, "mooneye/acceptance/pop_timing.gb"),
        (False, "mooneye/acceptance/ret_timing.gb"),
        (False, "mooneye/acceptance/oam_dma_restart.gb"),
        (False, "mooneye/acceptance/add_sp_e_timing.gb"),
        (False, "mooneye/acceptance/oam_dma/sources-GS.gb"),
        (False, "mooneye/acceptance/oam_dma/basic.gb"),
        (False, "mooneye/acceptance/oam_dma/reg_read.gb"),
        (False, "mooneye/acceptance/halt_ime0_nointr_timing.gb"),
        (False, "mooneye/acceptance/ppu/vblank_stat_intr-GS.gb"),
        (False, "mooneye/acceptance/ppu/intr_2_mode0_timing_sprites.gb"),
        (False, "mooneye/acceptance/ppu/stat_irq_blocking.gb"),
        (False, "mooneye/acceptance/ppu/intr_1_2_timing-GS.gb"),
        (False, "mooneye/acceptance/ppu/intr_2_mode0_timing.gb"),
        (False, "mooneye/acceptance/ppu/lcdon_write_timing-GS.gb"),
        (False, "mooneye/acceptance/ppu/hblank_ly_scx_timing-GS.gb"),
        (False, "mooneye/acceptance/ppu/intr_2_0_timing.gb"),
        (False, "mooneye/acceptance/ppu/stat_lyc_onoff.gb"),
        (False, "mooneye/acceptance/ppu/intr_2_mode3_timing.gb"),
        (False, "mooneye/acceptance/ppu/lcdon_timing-GS.gb"),
        (False, "mooneye/acceptance/ppu/intr_2_oam_ok_timing.gb"),
        (False, "mooneye/acceptance/call_cc_timing.gb"),
        (False, "mooneye/acceptance/halt_ime0_ei.gb"),
        (False, "mooneye/acceptance/intr_timing.gb"),
        (False, "mooneye/acceptance/instr/daa.gb"),
        (False, "mooneye/acceptance/if_ie_registers.gb"),
        (False, "mooneye/acceptance/di_timing-GS.gb"),
        (False, "mooneye/acceptance/serial/boot_sclk_align-dmgABCmgb.gb"),
        (False, "mooneye/acceptance/boot_regs-sgb2.gb"),
        (False, "mooneye/acceptance/boot_div-S.gb"),
        (False, "mooneye/acceptance/boot_div-dmg0.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_64Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_1Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_512kb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_32Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_2Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_4Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_8Mb.gb"),
        (True, "mooneye/emulator-only/mbc5/rom_16Mb.gb"),
        # (True, "mooneye/emulator-only/mbc2/rom_1Mb.gb"),
        # (True, "mooneye/emulator-only/mbc2/ram.gb"),
        # (True, "mooneye/emulator-only/mbc2/bits_unused.gb"),
        # (True, "mooneye/emulator-only/mbc2/bits_ramg.gb"),
        # (True, "mooneye/emulator-only/mbc2/rom_512kb.gb"),
        # (True, "mooneye/emulator-only/mbc2/bits_romb.gb"),
        # (True, "mooneye/emulator-only/mbc2/rom_2Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_1Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/bits_bank2.gb"),
        (True, "mooneye/emulator-only/mbc1/bits_ramg.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_512kb.gb"),
        (True, "mooneye/emulator-only/mbc1/bits_mode.gb"),
        (True, "mooneye/emulator-only/mbc1/ram_64kb.gb"),
        (True, "mooneye/emulator-only/mbc1/bits_bank1.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_2Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/ram_256kb.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_4Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/multicart_rom_8Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_8Mb.gb"),
        (True, "mooneye/emulator-only/mbc1/rom_16Mb.gb"),
    ]

    # HACK: We load any rom and load it until the last frame in the boot rom.
    # Then we save it, so we won't need to redo it.
    pyboy = PyBoy(default_rom, window_type="dummy")
    pyboy.set_emulation_speed(0)
    saved_state = io.BytesIO()
    for _ in range(59):
        pyboy.tick()
    pyboy.save_state(saved_state)
    pyboy.stop(save=False)

    for clean, rom in test_roms:
        pyboy = PyBoy(rom, window_type="headless")
        pyboy.set_emulation_speed(0)
        saved_state.seek(0)
        if clean:
            for _ in range(59):
                pyboy.tick()
        else:
            pyboy.load_state(saved_state)

        for _ in range(20):
            pyboy.tick()

        png_path = Path(f"test_results/{rom}.png")
        image = pyboy.botsupport_manager().screen().screen_image()
        if OVERWRITE_PNGS:
            png_path.parents[0].mkdir(parents=True, exist_ok=True)
            image.save(png_path)
        else:
            old_image = PIL.Image.open(png_path)
            diff = PIL.ImageChops.difference(image, old_image)
            if diff.getbbox() and not os.environ.get("TEST_CI"):
                image.show()
                old_image.show()
                diff.show()
            assert not diff.getbbox(), f"Images are different! {rom}"

        pyboy.stop(save=False)
Exemple #8
0
def test_tetris():
    NEXT_TETROMINO = 0xC213

    pyboy = PyBoy(tetris_rom,
                  bootrom_file="pyboy_fast",
                  window_type="headless",
                  game_wrapper=True)
    pyboy.set_emulation_speed(0)
    tetris = pyboy.game_wrapper()
    tetris.set_tetromino("T")

    first_brick = False
    tile_map = pyboy.botsupport_manager().tilemap_window()
    state_data = io.BytesIO()
    for frame in range(
            5282
    ):  # Enough frames to get a "Game Over". Otherwise do: `while not pyboy.tick():`
        pyboy.tick()

        assert pyboy.botsupport_manager().screen().tilemap_position() == ((0,
                                                                           0),
                                                                          (-7,
                                                                           0))

        # Start game. Just press Start and A when the game allows us.
        # The frames are not 100% accurate.
        if frame == 144:
            pyboy.send_input(WindowEvent.PRESS_BUTTON_START)
        elif frame == 145:
            pyboy.send_input(WindowEvent.RELEASE_BUTTON_START)
        elif frame == 152:
            pyboy.send_input(WindowEvent.PRESS_BUTTON_A)
        elif frame == 153:
            pyboy.send_input(WindowEvent.RELEASE_BUTTON_A)
        elif frame == 156:
            pyboy.send_input(WindowEvent.PRESS_BUTTON_A)
        elif frame == 157:
            pyboy.send_input(WindowEvent.RELEASE_BUTTON_A)
        elif frame == 162:
            pyboy.send_input(WindowEvent.PRESS_BUTTON_A)
        elif frame == 163:
            pyboy.send_input(WindowEvent.RELEASE_BUTTON_A)

        # Play game. When we are passed the 168th frame, the game has begone.
        # The "technique" is just to move the Tetromino to the right.
        elif frame > 168:
            if frame % 2 == 0:
                pyboy.send_input(WindowEvent.PRESS_ARROW_RIGHT)
            elif frame % 2 == 1:
                pyboy.send_input(WindowEvent.RELEASE_ARROW_RIGHT)

            # Show how we can read the tile data for the screen. We can use
            # this to see when one of the Tetrominos touch the bottom. This
            # could be used to extract a matrix of the occupied squares by
            # iterating from the top to the bottom of the screen.
            # Sidenote: The currently moving Tetromino is a sprite, so it
            # won't show up in the tile data. The tile data shows only the
            # placed Tetrominos.
            # We could also read out the score from the screen instead of
            # finding the corresponding value in RAM.

            if not first_brick:
                # 17 for the bottom tile when zero-indexed
                # 2 because we skip the border on the left side. Then we take a slice of 10 more tiles
                # 303 is the white background tile index
                if any(filter(lambda x: x != 303, tile_map[2:12, 17])):
                    first_brick = True
                    print(frame)
                    print("First brick touched the bottom!")

                    game_board_matrix = list(tile_map[2:12, :18])
                    assert game_board_matrix == ([
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 133, 133, 133],
                        [303, 303, 303, 303, 303, 303, 303, 303, 133, 303]
                    ])

                    tile_map.use_tile_objects(True)

                    t1 = tile_map[0, 0]
                    t2 = tile_map.tile(0, 0)
                    t3 = tile_map.tile(1, 0)
                    assert t1 == t2, "Testing __eq__ method of Tile object"
                    assert t1 != t3, "Testing not __eq__ method of Tile object"

                    game_board_matrix = [[x.tile_identifier for x in row]
                                         for row in tile_map[2:12, :18]]
                    tile_map.use_tile_objects(False)
                    assert game_board_matrix == ([
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                        [303, 303, 303, 303, 303, 303, 303, 133, 133, 133],
                        [303, 303, 303, 303, 303, 303, 303, 303, 133, 303]
                    ])

            if frame == 1012:
                assert not first_brick

            if frame == 1013:
                assert first_brick

                s1 = pyboy.botsupport_manager().sprite(0)
                s2 = pyboy.botsupport_manager().sprite(1)
                assert s1 == s1
                assert s1 != s2
                assert s1.tiles[0] == s2.tiles[
                    0], "Testing equal tiles of two different sprites"

                # Test that both ways of getting identifiers work and provides the same result.
                all_sprites = [
                    (s.x, s.y, s.tiles[0].tile_identifier, s.on_screen)
                    for s in
                    [pyboy.botsupport_manager().sprite(n) for n in range(40)]
                ]
                all_sprites2 = [
                    (s.x, s.y, s.tile_identifier, s.on_screen) for s in
                    [pyboy.botsupport_manager().sprite(n) for n in range(40)]
                ]
                assert all_sprites == all_sprites2

                # Verify data with known reference
                # pyboy.botsupport_manager().screen().screen_image().show()
                assert all_sprites == ([
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (72, 128, 133, True),
                    (80, 128, 133, True),
                    (88, 128, 133, True),
                    (80, 136, 133, True),
                    (120, 112, 133, True),
                    (128, 112, 133, True),
                    (136, 112, 133, True),
                    (128, 120, 133, True),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                    (-8, -16, 0, False),
                ])

                assert pyboy.get_memory_value(NEXT_TETROMINO) == 24
                assert tetris.next_tetromino() == "T"

                with open("tmp.state", "wb") as f:
                    pyboy.save_state(f)
                pyboy.save_state(state_data)
                break

    pre_load_game_board_matrix = None
    for frame in range(1015, 1865):
        pyboy.tick()

        if frame == 1864:
            game_board_matrix = list(tile_map[2:12, :18])
            assert game_board_matrix == ([
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 303, 303, 303, 303, 303, 303, 303],
                [303, 303, 303, 133, 133, 133, 303, 133, 133, 133],
                [303, 303, 303, 303, 133, 303, 303, 303, 133, 303]
            ])
            pre_load_game_board_matrix = game_board_matrix

    state_data.seek(
        0
    )  # Reset to the start of the buffer. Otherwise, we call `load_state` at end of file
    with open("tmp.state", "rb") as f:
        for _f in [f, state_data
                   ]:  # Tests both file-written state and in-memory state
            pyboy.load_state(
                _f)  # Reverts memory state to before we changed the Tetromino
            pyboy.tick()
            for frame in range(1015, 1865):
                pyboy.tick()

                if frame == 1864:
                    game_board_matrix = list(tile_map[2:12, :18])
                    assert game_board_matrix == pre_load_game_board_matrix
                    break
    os.remove("tmp.state")
    pyboy.stop(save=False)
Exemple #9
0
    target=target)  # numpy array for all channels - set initial target
actions = []

#Initialize PyBoy
# load rom through PyBoy
# if there is a state file, load it
dir_path = os.path.dirname(os.path.realpath(__file__))
rom_dir = os.path.join(dir_path, 'roms')
pyboy = PyBoy(os.path.join(rom_dir, 'Pokemon.gb'))
if os.path.exists(os.path.join(rom_dir,
                               'simulated_game.state')) and load_state:
    l_state = open("roms/simulated_game.state", "rb")
    pyboy.load_state(l_state)

# set up PyBoy screen support
bot_sup = pyboy.botsupport_manager()
scrn = bot_sup.screen()

# init image
screen_colors = scrn.screen_ndarray()
img = Image.fromarray(screen_colors)
img.save('game.jpg')

# minimize PyBoy window
pyboy_handle = ctypes.windll.user32.FindWindowW(None, "PyBoy")
ctypes.windll.user32.ShowWindow(pyboy_handle, 6)

# init controller
controller = pyboy_controller(pyboy)

# init command handler
Exemple #10
0
class PyBoyEnv(Env):
    """ Operators :
        - increase
        - decrease
        - equal <val>
        - smaller <val>
        - bigger <val>
        - in <val_1>,<val_2>,...,<val_n> (no spaces between values plz)
    """
    def __init__(self,
                 game,
                 window='SDL2',
                 visible=False,
                 colors=(0xfff6d3, 0xf9a875, 0xeb6b6f, 0x7c3f58),
                 buttons_press_mode='toggle'):
        # Build game
        super().__init__()
        self._pyboy = PyBoy(game,
                            window_type=window,
                            color_palette=colors,
                            disable_renderer=not visible)
        self._pyboy.set_emulation_speed(0)

        self._manager = self._pyboy.botsupport_manager()
        self._screen = self._manager.screen()

        self.actions = {
            0: WindowEvent.PRESS_ARROW_UP,
            1: WindowEvent.PRESS_ARROW_DOWN,
            2: WindowEvent.PRESS_ARROW_LEFT,
            3: WindowEvent.PRESS_ARROW_RIGHT,
            4: WindowEvent.PRESS_BUTTON_A,
            5: WindowEvent.PRESS_BUTTON_B,
            6: WindowEvent.PRESS_BUTTON_SELECT,
            7: WindowEvent.PRESS_BUTTON_START,
            8: WindowEvent.RELEASE_ARROW_UP,
            9: WindowEvent.RELEASE_ARROW_DOWN,
            10: WindowEvent.RELEASE_ARROW_LEFT,
            11: WindowEvent.RELEASE_ARROW_RIGHT,
            12: WindowEvent.RELEASE_BUTTON_A,
            13: WindowEvent.RELEASE_BUTTON_B,
            14: WindowEvent.RELEASE_BUTTON_SELECT,
            15: WindowEvent.RELEASE_BUTTON_START,
            16: WindowEvent.PASS
        }
        self.action_space = Discrete(len(self.actions))
        self.observation_space = Box(low=0,
                                     high=255,
                                     shape=(160, 144, 3),
                                     dtype=np.uint8)
        # Format :
        # {'addr':<address>, 'op':<operator>, 'reward':<reward>, 'val':<latest value>, 'lab':<label>}
        self._reward_rules = list()
        self._done_rules = list()
        self._refresh_values()

    def _refresh_values(self):
        """ Refresh values for each rule
        """
        for x in self._reward_rules + self._done_rules:
            x['val'] = self._pyboy.get_memory_value(x['addr'])

    def _get_observation(self):
        """ Returns screen
        """
        return np.asarray(self._screen.screen_ndarray(), dtype=np.uint8)

    def _handle_rule(self, rule):
        if rule['rule_type'] == 'reward':
            done = False
            reward = rule['reward']  # Set reward and label
            label = [rule['lab'], rule['reward']]
        elif rule['rule_type'] == 'done':
            done = True
            reward = 0
            label = [rule['lab'], "Done"]
        return reward, done, label

    def _scan_memory(self):
        """ Scan memory in order to apply rules
        """
        reward = 0
        done = False
        label = list()
        for x in self._reward_rules + self._done_rules:
            r, d, lab = 0, False, None
            if 'increase' in x['op']:  # INCREASE
                if x['val'] < self._pyboy.get_memory_value(x['addr']):
                    r, d, lab = self._handle_rule(x)
            elif 'decrease' in x['op']:  # DECREASE
                if x['val'] > self._pyboy.get_memory_value(x['addr']):
                    r, d, lab = self._handle_rule(x)
            elif 'equal' in x['op']:  # EQUAL
                if self._pyboy.get_memory_value(x['addr']) == int(
                        x['op'].split()[1]):
                    r, d, lab = self._handle_rule(x)
            elif 'bigger' in x['op'] or 'greater' in x['op']:  # BIGGER
                if self._pyboy.get_memory_value(x['addr']) > int(
                        x['op'].split()[1]):
                    r, d, lab = self._handle_rule(x)
            elif 'smaller' in x['op'] or 'less' in x['op']:  # SMALLER
                if self._pyboy.get_memory_value(x['addr']) < int(
                        x['op'].split()[1]):
                    r, d, lab = self._handle_rule(x)
            elif 'in' in x['op']:  # IN
                if self._pyboy.get_memory_value(
                        x['addr']) in x['op'].split(' ')[1].split(','):
                    r, d, lab = self._handle_rule(x)
            else:
                raise ValueError(f"Invalid custom reward operator: {x['op']}")
            reward += r
            done = done or d
            label.append(lab) if lab is not None else None
        self._refresh_values()
        return reward, done, label

    def set_reward_rule(self, address, operator, reward, label):
        # More user friendly ?
        self._reward_rules.append({
            'rule_type': 'reward',
            'addr': address,
            'op': operator,
            'reward': reward,
            'val': 0,
            'lab': label
        })

    # No reward here but some action to pass screen etc if needed ?
    def set_done_rule(self, address, operator, label):
        self._done_rules.append({
            'rule_type': 'done',
            'addr': address,
            'op': operator,
            'val': 0,
            'lab': label
        })

    def step(self, action_id):  # same thing as gymboy (no toggle)
        action = self.actions[action_id]
        self._pyboy.send_input(action)
        done_tick = self._pyboy.tick()
        reward, done, info = self._scan_memory()
        obs = self._get_observation()
        return obs, reward, done or done_tick, info

    def reset(self):  # ?? Done rules ??
        return self._get_observation()

    def render(self):  # there's a way to toggle visible screen??
        pass
Exemple #11
0
def test_tilemaps():
    pyboy = PyBoy(kirby_rom, window_type="dummy")
    pyboy.set_emulation_speed(0)
    for _ in range(120):
        pyboy.tick()

    bck_tilemap = pyboy.botsupport_manager().tilemap_background()
    wdw_tilemap = pyboy.botsupport_manager().tilemap_window()

    assert bck_tilemap[0, 0] == 256
    assert bck_tilemap[:5, 0] == [256, 256, 256, 256, 170]
    assert bck_tilemap[:20, :10] == [
        [
            256, 256, 256, 256, 170, 176, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 171, 173, 177, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 172, 174, 178, 256, 256, 256, 256, 256, 256, 256,
            256, 347, 363, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 288, 175, 179, 336, 352, 368, 268, 284, 300, 316,
            332, 348, 364, 380, 256, 256, 256
        ],
        [
            256, 257, 273, 289, 305, 321, 337, 353, 369, 269, 285, 301, 317,
            333, 349, 365, 381, 256, 256, 256
        ],
        [
            256, 258, 274, 290, 306, 322, 338, 354, 370, 270, 286, 302, 318,
            334, 350, 366, 382, 256, 256, 256
        ],
        [
            256, 259, 275, 291, 307, 323, 339, 355, 371, 271, 287, 303, 319,
            335, 351, 367, 383, 256, 256, 256
        ],
        [
            256, 256, 276, 292, 308, 324, 340, 356, 372, 272, 320, 260, 261,
            262, 361, 182, 346, 256, 256, 256
        ],
        [
            256, 256, 277, 293, 309, 325, 341, 357, 373, 128, 181, 362, 378,
            299, 315, 331, 256, 256, 256, 256
        ],
        [
            256, 256, 278, 294, 310, 326, 342, 358, 374, 129, 164, 132, 136,
            140, 143, 146, 150, 167, 157, 168
        ]
    ]
    assert isinstance(bck_tilemap.tile(0, 0), Tile)
    assert bck_tilemap.tile_identifier(0, 0) == 256
    bck_tilemap.use_tile_objects(True)
    assert isinstance(bck_tilemap.tile(0, 0), Tile)
    assert bck_tilemap.tile_identifier(0, 0) == 256
    assert isinstance(bck_tilemap[0, 0], Tile)

    assert wdw_tilemap[0, 0] == 256
    assert wdw_tilemap[:5, 0] == [256, 256, 256, 256, 256]
    assert wdw_tilemap[:20, :10] == [
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 230, 224, 236, 228, 256, 241, 242,
            224, 240, 242, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 241, 238, 243, 237, 227, 256, 242,
            228, 241, 242, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ],
        [
            256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
            256, 256, 256, 256, 256, 256, 256
        ]
    ]
    assert isinstance(wdw_tilemap.tile(0, 0), Tile)
    assert wdw_tilemap.tile_identifier(0, 0) == 256
    wdw_tilemap.use_tile_objects(True)
    assert isinstance(wdw_tilemap.tile(0, 0), Tile)
    assert wdw_tilemap.tile_identifier(0, 0) == 256
    assert isinstance(wdw_tilemap[0, 0], Tile)

    pyboy.stop(save=False)
Exemple #12
0
height = 160
perf_times = []
frame_count = 0
while True:
    start_time = time.perf_counter()

    pb.tick()

    frame_count += 1

    if frame_count % (1//skip_rate):
        continue

    # observation: 画面のRGB値(144, 160, 3)
    observation = np.asarray(pb.botsupport_manager(
    ).screen().screen_ndarray(), dtype=np.uint8)

    # グレースケールに変換 (144, 160)
    observation = cv2.cvtColor(observation, cv2.COLOR_BGR2GRAY)

    screen = ""
    for row in observation:
        tmp = ""
        for c in row:
            if c == 255:
                tmp += white
            elif c == 153:
                tmp += light_gray
            elif c == 85:
                tmp += dark_gray
            elif c == 0:
Exemple #13
0
class simple_window(arcade.Window):

    # screen and image size vars
    screen_width = None
    screen_height = None
    game_width = None
    game_height = None
    checkerboard_size = CHECKERBOARD_SIZE
    padding = PADDING

    # textures and frequencies vars
    texture_list = []
    flicker_frequency = []
    tick = 0
    last_state = []
    checkerboard_pos_list = []
    draw_scale = None

    # PyBoy vars
    pyboy = None
    bot_sup = None
    scrn = None

    # data collection vars
    generator = None
    cortex = None

    # controller vars
    command_handler = None
    controller = None

    def __init__(self, width, height, title):
        # scale the game width to make the game screen bigger
        self.game_width = GAME_WIDTH * GAME_SCALE
        self.game_height = GAME_HEIGHT * GAME_SCALE

        # set total screen size since we also need space to draw checkerboards
        self.screen_width = self.game_width + CHECKERBOARD_SIZE * 2 + PADDING
        self.screen_height = self.game_height + CHECKERBOARD_SIZE * 2 + PADDING

        self.draw_scale = self.screen_height / BASE_HEIGHT

        # let Arcade Window run it's setup
        super().__init__(self.screen_width, self.screen_height, title, resizable=True)

        # set frame rate as (1 / desired_frame_rate)
        self.set_update_rate(1/FREQUENCY)

    def print_stage(self, stage):
        print('-'*20)
        print('{} BEGINNING'.format(stage))
        print('-'*20)

    def setup(self):
        self.print_stage("VISUALS SETUP")
        self.setup_checkerboards()
        self.print_stage("PYBOY SETUP")
        self.setup_pyboy()
        self.print_stage("CONTROLLER SETUP")
        self.setup_controller()
        self.print_stage("COMMAND HANDLER SETUP")
        # self.setup_command_handler()
        self.print_stage("CORTEX SETUP")
        # self.setup_cortex()

    def setup_controller(self):
        self.controller = pyboy_controller(self.pyboy)

    def setup_command_handler(self):
        self.command_handler = command_handler(self.controller)

    def setup_cortex(self):
        self.cortex = Cortex(None)
        self.cortex.do_prepare_steps()
        self.generator = self.cortex.sub_request(['eeg'])

    def setup_checkerboards(self):
        # load textures
        self.load_checkerboards()

        self.resize_drawing_vars()

        self.set_checkerboard_positions()

        # set all checkerboards to normal state (as opposed to inverted checkerboard)
        self.last_state = [0] * len(self.checkerboard_pos_list)

        # set flicker frequencies for each quadrant
        with open('flicker_patterns.txt') as f:
            for sequence in f:
                self.flicker_frequency.append(eval(sequence))

    def set_checkerboard_positions(self):
        # set some useful vars
        half_width = self.screen_width / 2
        half_height = self.screen_height / 2
        half_checkerboard = self.checkerboard_size / 2
        width_offset = (self.game_width / 2) + half_checkerboard + self.padding
        height_offset = (self.game_height / 2) + half_checkerboard + self.padding

        # empty checkerboard pos list
        self.checkerboard_pos_list = []

        # prep x,y pairs for where to print checkerboards
        # ordering is:
        #   y [top, middle, bottom]
        #       x [left, middle, right]
        for y in [half_height + height_offset, half_height, half_height - height_offset]:
            for x in [half_width - width_offset, half_width, half_width + width_offset]:
                # skip drawing in the middle of board
                if x == half_width and y == half_height:
                    continue
                self.checkerboard_pos_list.append([x, y])

        # only select the non corner positions for simple window
        self.checkerboard_pos_list = [self.checkerboard_pos_list[i] for i in [1, 3, 4, 6]]

    def load_checkerboards(self):
        # Set up dir paths
        dir_path = os.path.dirname(os.path.realpath(__file__))
        image_dir = os.path.join(dir_path, 'images')
        checkerboard_dir = os.path.join(image_dir, 'simple')
        icon_list = os.listdir(checkerboard_dir)

        # empty texture list, load new textures
        self.texture_list = []
        for icon in icon_list:
            if "png" not in icon.lower():
                continue
            self.texture_list.append(arcade.load_texture(os.path.join(checkerboard_dir, icon)))

    def setup_pyboy(self):
        # load rom through PyBoy
        dir_path = os.path.dirname(os.path.realpath(__file__))
        rom_dir = os.path.join(dir_path, 'roms')
        self.pyboy = PyBoy(os.path.join(rom_dir, 'Pokemon.gb'))

        # set up PyBoy screen support
        self.bot_sup = self.pyboy.botsupport_manager()
        self.scrn = self.bot_sup.screen()

        # minimize PyBoy window
        pyboy_handle = ctypes.windll.user32.FindWindowW(None, "PyBoy")
        ctypes.windll.user32.ShowWindow(pyboy_handle, 6)

    def on_update(self, delta_time):
        self.pyboy.tick()
        self.on_draw()
        # self.exhaust()
        self.tick += 1
        self.tick %= FREQUENCY
        # if self.tick % COMMAND_SEND_FREQUENCY == 0:
        #     "Starting guess"
        #     start = time.time()
        #     self.command_handler.predict(self.get_eeg_data())
        #     print("Guess done in: {}s".format(time.time() - start))

    def exhaust(self):
        next(self.generator)

    def get_eeg_data(self):
        # return np.ones((128, 5))
        return np.asarray(list(next(self.generator).queue))

    def resize_drawing_vars(self):
        if self.screen_height <= self.screen_width:
            self.draw_scale = self.screen_height / BASE_HEIGHT
        else:
            self.draw_scale = self.screen_width / BASE_WIDTH
        self.checkerboard_size = CHECKERBOARD_SIZE * self.draw_scale
        self.game_width = GAME_WIDTH * GAME_SCALE * self.draw_scale
        self.game_height = GAME_HEIGHT * GAME_SCALE * self.draw_scale
        self.padding = PADDING * self.draw_scale

    def on_resize(self, width, height):
        # Call the parent. Failing to do this will mess up the coordinates, and default to 0,0 at the center and the
        # edges being -1 to 1.
        super().on_resize(width, height)

        self.screen_width = width
        self.screen_height = height

        self.resize_drawing_vars()

        self.set_checkerboard_positions()

    def on_draw(self):
        # Start the render process
        arcade.start_render()

        # Draw game
        self.draw_game()

        # Draw checkerboards
        self.draw_checkerboards()

        # Finish the render
        arcade.finish_render()

    def draw_game(self):
        screen_colors = self.scrn.screen_ndarray()
        img = Image.fromarray(screen_colors)
        texture = arcade.Texture("img", img)
        arcade.draw_scaled_texture_rectangle(self.width / 2, self.height / 2, texture, GAME_SCALE * self.draw_scale)

    def draw_checkerboards(self):
        # Load and draw all checkerboards
        for ind, last_state in enumerate(self.last_state):
            freq = self.flicker_frequency[ind]
            pos = self.checkerboard_pos_list[ind]
            texture = self.texture_list[last_state]

            # if this is a switch state, change checkerboard state:
            if freq[self.tick % len(freq)]:
                self.last_state[ind] = not last_state

            arcade.draw_scaled_texture_rectangle(pos[0], pos[1], texture, self.draw_scale, 0)

    def on_key_press(self, key, key_modifiers):
        actions = []
        print("KEY PRESSED: {}".format(key))

        # switch statement to create WindowEvents (button commands for PyBoy)
        if (key == arcade.key.UP):
            actions = [WindowEvent.PRESS_ARROW_UP, WindowEvent.RELEASE_ARROW_UP]
        elif (key == arcade.key.DOWN):
            actions = [WindowEvent.PRESS_ARROW_DOWN, WindowEvent.RELEASE_ARROW_DOWN]
        elif (key == arcade.key.LEFT):
            actions = [WindowEvent.PRESS_ARROW_LEFT, WindowEvent.RELEASE_ARROW_LEFT]
        elif (key == arcade.key.RIGHT):
            actions = [WindowEvent.PRESS_ARROW_RIGHT, WindowEvent.RELEASE_ARROW_RIGHT]
        elif (key == arcade.key.Z):
            actions = [WindowEvent.PRESS_BUTTON_B, WindowEvent.RELEASE_BUTTON_B]
        elif (key == arcade.key.X):
            actions = [WindowEvent.PRESS_BUTTON_A, WindowEvent.RELEASE_BUTTON_A]
        elif (key == arcade.key.ENTER):
            actions = [WindowEvent.PRESS_BUTTON_SELECT, WindowEvent.RELEASE_BUTTON_SELECT]
        elif (key == arcade.key.RSHIFT):
            actions = [WindowEvent.PRESS_BUTTON_START, WindowEvent.RELEASE_BUTTON_START]

        # if actions list isn't empty, send commands to pyboy and tick the pyboy window to process each command
        if actions:
            for action in actions:
                self.pyboy.send_input(WindowEvent(action))
                self.pyboy.tick()

    def main():
        game = simple_window(0, 0, "Simple Window")
        game.setup()
        arcade.run()