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
def extract_side_features(sides, labels, character_model): index = 0 features = {"indicators": [], "parallel_port": False, "batteries": 0} for side in sides: for img in side: cv2_img = convert_to_cv2(img) mod_name = module_classifier.LABELS[labels[index]] try: if labels[index] == 1: # Single battery (large or small). features["batteries"] += 1 elif labels[index] == 2: # Double batteries. features["batteries"] += 2 elif labels[index] == 3: # Serial number. serial_num = get_serial_number(cv2_img, character_model) if serial_num is None: log(f"Serial number could not be determined.", config.LOG_WARNING) index += 1 continue log(f"Serial number: {serial_num}", verbose=config.LOG_DEBUG) features["serial_number"] = serial_num serial_features = extract_serial_number_features( serial_num) features.update(serial_features) elif labels[index] == 5: # Parallel port. features["parallel_port"] = True elif labels[index] == 6: # Indicator of some kind. lit, text = get_indicator_features(cv2_img, character_model) desc = "lit_" + text if lit else "unlit_" + text features["indicators"].append(desc) except KeyboardInterrupt: handle_module_exception(mod_name, cv2_img) raise KeyboardInterrupt except Exception: handle_module_exception(mod_name, cv2_img) index += 1 return features
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.