Пример #1
0
def run_level(module_model, char_model, symbol_model, minutes, seconds, num_modules):
    LIGHT_MONITOR.start()

    time_started = time() # Time started is used for solving the button module.

    log("Inspecting bomb...")

    images = inspect_bomb.inspect_bomb(num_modules) # Capture images of all sides of the bomb.
    side_partitions = inspect_bomb.partition_sides(images) # Split images into modules/side of bomb.
    # Identify features from the side of the bomb (indicators, batteries, serial number, etc.).
    predictions = identify_side_features(side_partitions, module_model)

    modules = 12 if num_modules > 5 else 6

    sw, sh = win_util.get_screen_size()
    #add_overlay_properties("module_positions", [get_module_coords(x) for x in range(6)])
    add_overlay_properties("module_names", [module_classifier.LABELS[x]
                                            for x in predictions[:modules]])

    # Extract aforementioned features (read serial number, count num. of batteries, etc.).
    side_features = extract_side_features(side_partitions[1:], predictions[modules:], char_model)

    log(f"Side features: {side_features}", verbose=config.LOG_DEBUG)
    log(f"Modules: {[module_classifier.LABELS[x] for x in predictions[:modules]]}", config.LOG_DEBUG)

    try:
        # Solve all modules. Back of the bomb first, from left to right, top to bottom.
        solve_modules(predictions[:modules], side_features, char_model,
                      symbol_model, (time_started, minutes, seconds))
    except KeyboardInterrupt: # Catch SIGINT from LightMonitor (meaning the bomb exploded).
        log("Exiting...")
        exit(0)

    LIGHT_MONITOR.shut_down()
Пример #2
0
def continue_button():
    sw, sh = win_util.get_screen_size()
    x = sw // 2
    y = int(sh * 0.65)
    win_util.click(x, y)
    sleep(1)
    win_util.click(x, y)
Пример #3
0
 def monitor(self):
     _, SH = get_screen_size()
     lo = (30, 30, 30)
     hi = (255, 255, 255)
     self.change_event.set()
     while self.is_active:
         sc = screenshot(0, SH - 200, 200, 200)
         img = features_util.convert_to_cv2(sc)
         rgb = features_util.split_channels(img)
         if self.lights_on:
             if not features_util.color_in_range(self.pixel, rgb, lo, hi):
                 if self.bomb_exploded(rgb):  # We died :(
                     self.is_active = False
                     self.exit_after_explosion()
                 else:
                     log("Lights in the room are turned off. Pausing execution temporarily..."
                         )
                     self.lights_on = False
                     self.change_event.clear()
                     sleep(1)
         else:
             if features_util.color_in_range(self.pixel, rgb, lo, hi):
                 log("Lights in the room are turned back on. Resuming...")
                 self.change_event.set()
                 self.lights_on = True
                 sleep(1)
         sleep(0.25)
Пример #4
0
 def create_bg_image():
     sw, sh = win_util.get_screen_size()
     padding = 20
     if "debug_bg_img" in GUIOverlay.properties:
         GUIOverlay.bg_img = np.copy(GUIOverlay.properties["debug_bg_img"])
     else:
         GUIOverlay.bg_img = np.zeros((sh - padding, sw - padding, 3),
                                      dtype="uint8")
Пример #5
0
def get_module_coords(module):
    SW, SH = win_util.get_screen_size()
    start_x = SW * 0.35
    start_y = SH * 0.35
    offset_x = 300
    offset_y = 300
    x = int(start_x + ((module % 3) * offset_x))
    y = int(start_y + ((module // 3) * offset_y))
    return x, y
Пример #6
0
def log_info(img, info):
    sw, sh = win_util.get_screen_size()
    width = 350
    x = sw - width
    y_step = 20
    start_y = 100
    draw_rect(img, (x - 10, start_y), (sw, sh), (0, 0, 0), -1)
    max_lines = int(sh // 23)  # 47 for 1080.
    for i, s in enumerate(info[-max_lines:]):
        draw_text(img, s, (x, start_y + 10 + (y_step * i)), 1.2,
                  (255, 255, 255), 1)
Пример #7
0
def get_module_characters():
    SW, SH = win_util.get_screen_size()
    sc = screenshot(int(SW * 0.524), int(SH * 0.547), 36, 25)
    img = cv2.cvtColor(np.array(sc), cv2.COLOR_RGB2BGR)
    thresh = get_threshold(img)
    masks = get_masked_images(thresh)
    if len(masks) == 1 and masks[0].shape[1] > 20:
        mask1 = masks[0][:, :masks[0].shape[1]//2]
        mask2 = masks[0][:, masks[0].shape[1]//2:]
        masks = [mask1, mask2]
    return masks
Пример #8
0
def restart_level(level):
    SW, SH = win_util.get_screen_size()
    win_util.click(int(SW * 0.9), int(SH * 0.8), btn="right")
    sleep(1)
    win_util.click(int(SW * 0.73), int(SH * 0.65))
    sleep(1)
    win_util.click(int(SW * 0.73), int(SH * 0.45))
    sleep(2)
    win_util.click(int(SW * 0.52), int(SH * 0.53))
    sleep(0.8)
    inspect_bomb.select_level(level)
    sleep(0.5)
Пример #9
0
def get_module_coords(module_index):
    """
    Get screen coordinates of a module based on module index.
    """
    SW, SH = win_util.get_screen_size()
    start_x = SW * 0.35
    start_y = SH * 0.35
    offset_x = 300
    offset_y = 300
    x = int(start_x + ((module_index % 3) * offset_x))
    y = int(start_y + ((module_index // 3) * offset_y))
    return x, y
Пример #10
0
def inspect(labels, labels_to_inspect):
    SW, SH = win_util.get_screen_size()

    filtered_labels = []
    images = []
    for module in range(12):
        mod_index = module if module < 6 else module - 6
        if labels[module] in labels_to_inspect:
            main.select_module(mod_index)
            sleep(1)
            SC, _, _ = main.screenshot_module()
            images.append(SC)
            filtered_labels.append(labels[module])
            main.deselect_module()
            sleep(0.5)
        if module == 5:  # We have gone through 6 modules, flip the bomb over and proceeed.
            SW, SH = win_util.get_screen_size()
            flip_bomb(SW, SH)
            sleep(0.75)
            win_util.mouse_up(SW // 2, SH // 2, btn="right")
            sleep(0.5)
    return images, filtered_labels
Пример #11
0
    def create_window(conn):
        sw, sh = win_util.get_screen_size()

        path = "../resources/misc/recorded_runs/"
        num_files = len(glob(path + "*"))
        record_path = f"{path}{num_files+1}/"
        mkdir(record_path)

        mon_bbox = {"top": 0, "left": 0, "width": sw, "height": sh}
        sct = mss()

        queue = Queue(5)
        io_thread = Thread(target=save_video_frame, args=(record_path, queue))
        io_thread.start()

        Thread(target=listen, args=(conn, )).start()

        target_fps = 30
        secs_per_frame = 1 / target_fps

        try:
            while not GUIOverlay.is_active:
                sleep(0.1)  # Wait for start.

            time_started = GUIOverlay.properties.get("speedrun_time", None)
            timestamp = int(time())
            while GUIOverlay.is_active:
                frame_time = time()
                img = np.array(sct.grab(mon_bbox))
                img = GUIOverlay.pad_bg_img(img, 300, 100)
                if time_started is not None:
                    new_time = int(time())
                    if new_time > timestamp:
                        timestamp = new_time
                        GUIOverlay.add_property("speedrun_time",
                                                timestamp - time_started)
                elif "speedrun_time" in GUIOverlay.properties:
                    time_started = GUIOverlay.properties["speedrun_time"]

                frame_time = time() - frame_time
                if frame_time < secs_per_frame:
                    sleep(secs_per_frame - frame_time)

                if time_started is not None:
                    data = (img, GUIOverlay.properties, time() - time_started)
                    queue.put(data, True)
        except KeyboardInterrupt:
            return
        finally:
            queue.put(None)
Пример #12
0
def solve_needy_modules(modules, needy_indices, curr_module, duration):
    SW, SH = win_util.get_screen_size()
    prev_index = curr_module
    timestamp = None
    for index in needy_indices:
        if (index > 5) ^ (prev_index > 5):  # Flip the bomb, if needed.
            inspect_bomb.flip_bomb(SW, SH)
            sleep(0.75)
            win_util.mouse_up(SW // 2, SH // 2, btn="right")
            sleep(0.5)
        mod_index = index if index < 6 else index - 6
        label = modules[index]
        select_module(mod_index)
        add_overlay_properties("module_info", (label))
        SC, x, y = screenshot_module()
        mod_pos = (x, y)
        cv2_img = convert_to_cv2(SC)
        mod_name = module_classifier.LABELS[label]
        log(f"Solving {mod_name}...")
        try:
            if label == 20:  # Needy Vent Gas.
                solve_needy_vent(cv2_img, mod_pos)
            elif label == 21:  # Needy Discharge Capacitor.
                solve_needy_discharge(cv2_img, mod_pos)
            elif label == 22:  # Solve Knob.
                solve_needy_knob(cv2_img, mod_pos)
        except KeyboardInterrupt:
            handle_module_exception(mod_name, cv2_img)
            raise KeyboardInterrupt
        except Exception:
            handle_module_exception(mod_name, cv2_img)
        if timestamp is None:
            cooldown_time = 5
            timestamp = time() + cooldown_time
        sleep(0.5)
        deselect_module()
        prev_index = index
    # Flip the bomb back to it's original state, if needed.
    if (curr_module > 5) ^ (prev_index > 5):
        inspect_bomb.flip_bomb(SW, SH)
        sleep(0.75)
        win_util.mouse_up(SW // 2, SH // 2, btn="right")
        sleep(0.5)
    return timestamp
Пример #13
0
def inspect_bomb(num_modules=None):
    sw, sh = win_util.get_screen_size()
    mid_x = sw // 2
    mid_y = sh // 2
    win_util.click(mid_x, mid_y + (mid_y // 8))
    sleep(0.5)
    # Inspect front of bomb.
    front_img = screenshot(460, 220, 1000, 640)
    sleep(0.2)
    # Rotate bomb.
    win_util.mouse_down(mid_x, mid_y, btn="right")
    sleep(0.2)
    # Inspect right side.
    right_img = inspect_side(sw - int(sw / 2.74), mid_y + int(mid_y / 8), 755,
                             60, 480, 900)
    # Inspect left side.
    left_img = inspect_side(int(sw / 2.76), mid_y + int(mid_y / 8), 755, 60,
                            480, 900)
    # Inspect top side.
    top_img = inspect_side(int(sw / 2.75), sh, 720, 0, 480, sh)
    # Inspect bottom side.
    bottom_img = inspect_side(int(sw / 2.75), 0, 720, 0, 480, sh)
    # Inspect back of bomb.
    win_util.mouse_up(mid_x, mid_y, btn="right")
    sleep(0.5)
    return_tupl = (front_img, left_img, right_img, top_img, bottom_img)
    if num_modules is None or num_modules > 5:
        flip_bomb(sw, sh)
        back_img = screenshot(460, 220, 1000, 640)
        sleep(0.4)
        win_util.mouse_up(mid_x, mid_y, btn="right")
        return_tupl = (back_img, ) + return_tupl
    else:
        win_util.click(200, 200, btn="right")
        sleep(0.4)
        win_util.click(mid_x, mid_y + (mid_y // 8))
        sleep(0.5)
    return return_tupl
Пример #14
0
def draw_speedrun_splits(img, splits):
    sw, _ = win_util.get_screen_size()
    bar_height = 100
    cv2.rectangle(img, (0, 0), (sw, bar_height), (0, 0, 0), -1)
    start_x = 5
    step_x = 125
    for i, (level, split) in enumerate(splits):
        segment = split if i < 1 else split - splits[i - 1][1]
        total_time_str = format_time(split)
        segment_time_str = format_time(segment)
        level_strs = format_level(level)
        x = start_x + (step_x * i)
        cv2.rectangle(img, (step_x * i, 0), (step_x * (i + 1), bar_height),
                      (80, 80, 80), -1)
        cv2.rectangle(img, (step_x * i, 0), (step_x * (i + 1), bar_height),
                      (0, 0, 0), 1)
        for lvl_s, lvl_y in level_strs:
            cv2.putText(img, lvl_s, (x, lvl_y), cv2.FONT_HERSHEY_PLAIN, 1.2,
                        (255, 255, 255), 1)
        cv2.putText(img, total_time_str, (x, 60), cv2.FONT_HERSHEY_PLAIN, 1.6,
                    (60, 230, 30), 2)
        cv2.putText(img, "(" + segment_time_str + ")", (x, 90),
                    cv2.FONT_HERSHEY_PLAIN, 1.6, (40, 160, 40), 2)
Пример #15
0
def get_duration_characters():
    SW, SH = win_util.get_screen_size()
    sc = screenshot(int(SW * 0.47), int(SH * 0.54), 80, 38)
    img = cv2.cvtColor(np.array(sc), cv2.COLOR_RGB2BGR)
    thresh = get_threshold(img)
    return get_masked_images(thresh)
Пример #16
0
def solve_modules(modules, side_features, character_model, symbol_model,
                  duration):
    # Get list of indexes of needy modules (all modules an index over 19).
    needy_indices = list(
        filter(lambda i: modules[i] > 19, [x for x in range(len(modules))]))
    needy_timestamp = duration[0]
    module_durations = [2, 5, 2, 12, 10, 2, 14, 8, 8, 8, 20]
    log(f"Needy modules: {len(needy_indices)}", config.LOG_DEBUG)

    solved_modules = 0
    num_modules = len(list(filter(lambda x: 8 < x < 20, modules)))
    module = 0
    while module < len(modules):
        label = modules[module]
        LIGHT_MONITOR.wait_for_light()  # If the room is dark, wait for light.
        mod_index = module if module < 6 else module - 6
        bomb_solved = solved_modules == num_modules
        mod_duration = 2 if label > 19 else module_durations[label - 9]
        critical = needy_modules_critical(len(needy_indices), needy_timestamp,
                                          mod_duration)
        if not bomb_solved and critical:
            # Needy modules need attention! Solve them, and continue where we left off.
            needy_timestamp = solve_needy_modules(modules, needy_indices,
                                                  module, needy_timestamp)

        if 8 < label < 20:
            select_module(mod_index)
            SC, x, y = screenshot_module()
            #add_overlay_properties("module_selected", (x, y, mod_index))
            mod_pos = (x, y)
            cv2_img = convert_to_cv2(SC)
            mod_name = module_classifier.LABELS[label]
            log(f"Solving {mod_name}...")
            try:
                if label == 9:  # Wires.
                    solve_wires(cv2_img, mod_pos, side_features)
                elif label == 10:  # Button.
                    solve_button(cv2_img, mod_pos, side_features,
                                 character_model, duration)
                elif label == 11:  # Symbols.
                    solve_symbols(cv2_img, mod_pos, symbol_model)
                elif label == 12:  # Simon Says.
                    solve_simon(cv2_img, mod_pos, side_features)
                elif label == 13:  # Wire Sequence.
                    solve_wire_sequence(cv2_img, mod_pos)
                elif label == 14:  # Complicated Wires.
                    solve_complicated_wires(cv2_img, mod_pos, side_features)
                elif label == 15:  # Memory Game.
                    solve_memory(cv2_img, character_model, mod_pos)
                elif label == 16:  # Who's on First?
                    solve_whos_on_first(cv2_img, character_model, mod_pos)
                elif label == 17:  # Maze.
                    solve_maze(cv2_img, mod_pos)
                elif label == 18:  # Password.
                    solve_password(cv2_img, character_model, mod_pos)
                elif label == 19:  # Morse.
                    solve_morse(cv2_img, mod_pos)
                solved_modules += 1
            except KeyboardInterrupt:  # Bomb 'sploded.
                handle_module_exception(mod_name, cv2_img)
                raise KeyboardInterrupt
            except Exception:
                # If an exception happened while lights were off, we try again.
                if not LIGHT_MONITOR.lights_on:
                    log("Exception while light was off. We try again in a bit!"
                        )
                    deselect_module()
                    continue
                handle_module_exception(mod_name, cv2_img)

            sleep(0.1)
            deselect_module()

        if module == 5 and solved_modules != num_modules:
            # We have gone through all modules on one side of the bomb, flip it over and continue.
            SW, SH = win_util.get_screen_size()
            inspect_bomb.flip_bomb(SW, SH)
            sleep(0.75)
            win_util.mouse_up(SW // 2, SH // 2, btn="right")
            sleep(0.5)

        module += 1
    if solved_modules == num_modules:
        log("We did it! We live to defuse another bomb!")
    else:
        log("Some modules could not be disarmed, it seems we are doomed...")
        raise KeyboardInterrupt  # We failed.
Пример #17
0
def start_level():
    """
    Click the 'Start Level' button, after a level has been selected.
    """
    SW, SH = win_util.get_screen_size()
    win_util.click(int(SW - SW / 2.6), int(SH - SH / 3.3))
Пример #18
0
def screenshot_module():
    SW, SH = win_util.get_screen_size()
    x = int(SW * 0.43)
    y = int(SH * 0.36)
    return screenshot(x, y, 300, 300), x, y
Пример #19
0
def draw_speedrun_time(img, s_time):
    sw, _ = win_util.get_screen_size()
    time_str = format_time(s_time, 0)
    draw_text(img, time_str, (sw - 180, 50), 2.8, (255, 255, 255), 2)
Пример #20
0
def select_bombs_menu():
    sw, sh = win_util.get_screen_size()
    x = sw // 2
    y = int(sh * 0.56)
    win_util.click(x, y)
Пример #21
0
from time import sleep
import util.windows_util as win_util
from model.grab_img import screenshot

SW, SH = win_util.get_screen_size()
LEVEL_COORDS = {
    "first_bomb": int(SH * 0.35),
    "old-new": int(SH * 0.47),
    "double_your_money": int(SH * 0.53),
    "step_up": int(SH * 0.58),
    "pick_up_pace_1": int(SH * 0.62),
    "hidden_message": int(SH * 0.26),
    "somethings_different": int(SH * 0.30),
    "one_giant_leap": int(SH * 0.35),
    "fair_game": int(SH * 0.39),
    "pick_up_pace_2": int(SH * 0.44),
    "no_room_for_error": int(SH * 0.48),
    "eight_modules": int(SH * 0.53),
    "small_wrinkle": int(SH * 0.64),
    "multi-tasker": int(SH * 0.35),
    "the_knob": int(SH * 0.305),
    "hardcore": int(SH * 0.55)
}


def next_level_page():
    sw, sh = win_util.get_screen_size()
    win_util.click(int(sw * 0.65), int(sh * 0.70))


def select_level(level):
Пример #22
0
def next_level_page():
    sw, sh = win_util.get_screen_size()
    win_util.click(int(sw * 0.65), int(sh * 0.70))