Example #1
0
 def do_stage(self) -> bool:
     "Set up the next stage, and return False if all stages are done."
     self.current_stage += 1
     stages_not_done = (self.current_stage <= self.total_stages)
     if self.total_stages > 1 and stages_not_done:
         talk(f"- STAGE {self.current_stage}")
     return stages_not_done
Example #2
0
 def _get_start_time_mins(self, start_time_mins: Optional[int]) -> None:
     if start_time_mins is not None and start_time_mins > 0:
         self.start_time_mins = start_time_mins
     elif EdgeFlag.START_TIME_MINS in self._required_edgework_flag:
         talk("What is the starting time on the bomb, in minutes?")
         talk(
             "(In Zen mode, this is the time the bomb was generated with.)")
         self.start_time_mins = ask.positive_int()
 def stage(self) -> None:
     if self.current_stage == 1:
         talk("What color is flashing?")
     else:
         talk("What color is now flashing at the end of the sequence?")
     talk(
         'Type one of "red", "blue", "green", or "yellow", without quotes.')
     new_color = ask.str_from_set(self.valid_colors)
     self.color_sequence.append(new_color)
     if self.bomb.serial_vowel:
         if self.bomb.strikes == 0:
             simon_key = {
                 "red": "Blue",
                 "blue": "Red",
                 "green": "Yellow",
                 "yellow": "Green",
             }
         elif self.bomb.strikes == 1:
             simon_key = {
                 "red": "Yellow",
                 "blue": "Green",
                 "green": "Blue",
                 "yellow": "Red",
             }
         else:
             simon_key = {
                 "red": "Green",
                 "blue": "Red",
                 "green": "Yellow",
                 "yellow": "Blue",
             }
     else:
         if self.bomb.strikes == 0:
             simon_key = {
                 "red": "Blue",
                 "blue": "Yellow",
                 "green": "Green",
                 "yellow": "Red",
             }
         elif self.bomb.strikes == 1:
             simon_key = {
                 "red": "Red",
                 "blue": "Blue",
                 "green": "Yellow",
                 "yellow": "Green",
             }
         else:
             simon_key = {
                 "red": "Yellow",
                 "blue": "Green",
                 "green": "Blue",
                 "yellow": "Red",
             }
     talk("Press the following colors in order:")
     for color in self.color_sequence:
         talk(simon_key[color])
 def stage(self) -> None:
     talk("What Morse Code sequence is flashing?")
     word = morse.ask_word()
     while word not in self.word_to_freq:
         talk("That word isn't in my table.")
         talk("What Morse Code sequence is flashing?")
         word = morse.ask_word()
     talk(f"Respond at frequency 3.{self.word_to_freq[word]} MHz.")
Example #5
0
 def stage(self) -> None:
     talk("What is on the display? Type it exactly as written.")
     talk("Include any typos. Type arrows as angle brackets.")
     phrase = ask.str_from_set(self.table.keys())
     talk("Flip the switch down when the bomb "
          f"timer has a {self.table[phrase][0]} in the seconds column.")
     talk("Then, flip the switch up when the bomb "
          f"timer has a {self.table[phrase][1]} in the seconds column.")
Example #6
0
 def stage(self) -> None:
     talk("What is displayed on the module?")
     scramble = ask.str_from_regex(r"[a-z]{6}")
     while set(scramble) not in [set(w) for w in self.words]:
         talk("Those letters don't correspond to a known word.")
         talk("What is displayed on the module?")
         scramble = ask.str_from_regex(r"[a-z]{6}")
     answer = [w for w in self.words if set(w) == set(scramble)][0]
     talk(f'Type in the word "{answer}".')
Example #7
0
 def _get_ports(self, port_plates: Optional[PortPlateList]) -> None:
     if port_plates is not None:
         self.port_plates = port_plates
     elif EdgeFlag.PORTS in self._required_edgework_flag:
         if ask.yes_no("Are there any port plates?"):
             plate_list: List[PortPlate] = []
             talk("How many port plates are there?")
             plate_count = ask.positive_int()
             for i in range(plate_count):
                 talk(f"What ports, if any, are on plate {i+1}?")
                 plate = ask.list_from_set(
                     self._port_names,
                     print_options=True,
                 )
                 plate_list.append(
                     tuple(self._port_name_to_enum[port] for port in plate))
             self.port_plates = tuple(plate_list)
Example #8
0
 def solve(self,
           *,
           start_time_mins: Optional[int] = None,
           max_strikes: Optional[int] = None) -> None:
     "Get edgework information, call each solver in turn, and do associated handling."
     self.initialize_edgework(start_time_mins=start_time_mins,
                              max_strikes=max_strikes)
     while self.queue:
         if self.edgework.defused:
             raise RuntimeError("Bomb defused with items on the queue.")
         self.resort_queue()
         solver = self.queue.pop()
         solver.solve()
         if not solver.all_solved:
             self.queue.append(solver)
     if self.edgework.defused:
         talk("Bomb defused!")
     else:
         raise RuntimeError("Queue empty but bomb not defused.")
 def stage(self) -> None:
     while True:
         possible_words: List[str] = list(self.valid_words)
         for column_index in range(5):
             talk(f"What letters are in column {column_index + 1}?")
             letters = ask.str_from_regex(r"[a-z]{6}")
             while len(set(letters)) != 6:  #all letters should be unique
                 talk("There should be 6 unique letters in the column.")
                 talk(f"What letters are in column {column_index + 1}?")
                 letters = ask.str_from_regex(r"[a-z]{6}")
             possible_words = [
                 word for word in possible_words
                 if word[column_index] in letters
             ]  #filter
             if len(possible_words) == 1:
                 answer = possible_words[0].upper()
                 talk(f'Enter the password "{answer}".')
                 return
             if len(possible_words) == 0:
                 break
         #no valid word or multiple valid words
         talk("Something went wrong. Let's start over.")
 def stage(self) -> None:
     talk("What number is on the display?")
     display = int(ask.str_from_regex(r'[1-4]'))
     talk("What numbers are on the buttons, in reading order?")
     buttons = ask.str_from_regex(r'[1-4]{4}')
     while any(c not in buttons for c in '1234'):
         talk("There should be one of each number on the buttons.")
         talk("What numbers are on the buttons, in reading order?")
         buttons = ask.str_from_regex(r'[1-4]{4}')
     item: _MemoryItem
     if self.current_stage == 1:
         item = self._stage_1(display, buttons)
     elif self.current_stage == 2:
         item = self._stage_2(display, buttons)
     elif self.current_stage == 3:
         item = self._stage_3(display, buttons)
     elif self.current_stage == 4:
         item = self._stage_4(display, buttons)
     else:  #self.current_stage == 5
         item = self._stage_5(display, buttons)
     talk(f"Press the button labeled {item.label}.")
     self.presses.append(item)
Example #11
0
def from_pool(*modules: Type[ModuleSolver],
              count: int = 1,
              print_options: bool = True) -> List[ModuleSolver]:
    """Ask the user which of the modules in the pool is present on the bomb,
    and return the associated solvers."""
    module_names = {str(module.name) for module in modules}
    assert len(module_names) == len(modules)
    if print_options:
        talk("Which of the following modules are present on the bomb?")
    else:
        talk("Which modules in the pool are present on the bomb?")
    modules_present = ask.list_from_set(module_names,
                                        print_options=print_options,
                                        expected_len=count)
    final_modules = []
    for module_name in set(modules_present):
        for module in modules:
            if str(module.name).lower(
            ) == module_name:  #module.name will be lowercase
                final_modules.append(module(
                    modules_present.count(module_name)))
                break
    return final_modules
 def ask_wires(self) -> Tuple[_SequenceWire, ...]:
     "Get a set of wires from the user."
     talk("What wires are on the panel, in order by their left plug?")
     talk("Input their color followed by the letter")
     talk('they\'re plugged into, like "red C".')
     wirelist = ask.list_from_func(self._check_wire_text)
     converted_wirelist = tuple(
         _SequenceWire._make(wire.split()) for wire in wirelist)
     return converted_wirelist
Example #13
0
def ask_coord(*, alpha: bool = True) -> Coord:
    """Get a coordinate point from the user. If alpha is set (the default), the
    expected form is like "A5", otherwise, row and column are asked separately."""
    col: int
    row: int
    if alpha:
        talk('(Submit a coordinate like "B4", where the letter is the column')
        talk("and the number is the row.)")
        alpha_coord = ask.str_from_regex(r"[a-z][1-9][0-9]*")
        col = ascii_lowercase.index(alpha_coord[0]) + 1
        row = int(alpha_coord[1:])
    else:
        talk("Row number:")
        row = ask.positive_int()
        talk("Column number:")
        col = ask.positive_int()
    return Coord(row - 1, col - 1)
Example #14
0
 def stage(self) -> None:
     if not self.right_keys_turned:
         talk("This module and others like it have a number"
              " displaying each module's priority."
              )  #first time this bomb only
         talk("Turn each right key on modules of this type,"
              " in descending order of priority.")
     talk(
         "Turn the lowest priority left key that hasn't already been turned."
     )
Example #15
0
 def _get_indicators(self, indicators: Optional[IndicatorList]) -> None:
     if indicators is not None:
         self.indicators = indicators
     elif EdgeFlag.INDICATORS in self._required_edgework_flag:
         if ask.yes_no("Are there any indicators?"):
             talk("Input each indicator, one per line.")
             talk('Lowercase means unlit and uppercase means lit,')
             talk('so "CAR" is a lit CAR, and "frk" is an unlit FRK.')
             indicator_list_raw = ask.list_from_regex(r'[a-z]{3}|[A-Z]{3}',
                                                      case_sensitive=True)
             self.indicators = tuple(
                 (ind.lower(), ind.isupper()) for ind in indicator_list_raw)
 def stage(self) -> None:
     talk('What text is on the display? '
          '(If there is no text, type "Empty".)')
     display = ask.str_from_set(self.valid_displays)
     talk("What are the button labels, in reading order?")
     labels = ask.list_from_set(self.valid_labels, expected_len=6)
     label_index = self.display_to_index[display]
     key_label = labels[label_index]
     answer_label = key_label
     for button in self.label_to_buttons[key_label]:
         if button in labels:
             answer_label = button
             break
     talk(f"Press the button labeled {answer_label.upper()}.")
 def _hold(self) -> None:
     talk("Hold down the button. What color is the strip on the right?")
     talk(
         'Type one of "red", "yellow", "blue", or "white", without quotes.')
     strip = ask.str_from_set(self.valid_colors)
     digit: int
     if strip == "blue":
         digit = 4
     elif strip == "yellow":
         digit = 5
     else:
         digit = 1
     talk(f"Release the button when the countdown timer has a {digit} "
          "in any position.")
 def stage(self) -> None:
     #canonize last_stage_counts before starting new stage
     self.wire_counts.update(self.last_stage_counts)
     self.last_stage_counts.clear()
     wires = self.ask_wires()
     for wire in wires:
         self.last_stage_counts[wire.color] += 1
         wire_count = self.wire_counts[wire.color] + self.last_stage_counts[
             wire.color]
         if wire.label in self.cut_table[wire.color][wire_count - 1]:
             talk(f"Cut the {wire.color} wire "
                  f"connected to label {wire.label.upper()}.")
         else:
             talk(f"Do not cut the {wire.color} wire "
                  f"connected to label {wire.label.upper()}.")
     talk("Press the down arrow to finish this panel.")
 def stage(self) -> None:  #pylint: disable=too-many-branches #can't help it
     talk("What color wires are on the module, from top to bottom?")
     talk(
         "Type R for red, Y for yellow, B for blue, W for white, and K for black."
     )
     wirelist = ask.str_from_regex(r"[rybwk]{3,6}").lower()
     wire: str
     if len(wirelist) == 3:
         if 'r' not in wirelist:
             wire = "second"
         elif wirelist[-1] == 'w':
             wire = "last"
         elif wirelist.count('b') > 1:
             wire = "last blue"
         else:
             wire = "last"
     elif len(wirelist) == 4:
         if wirelist.count('r') > 1 and self.bomb.serial_odd:
             wire = "last red"
         elif wirelist[-1] == 'y' and 'r' not in wirelist:
             wire = "first"
         elif wirelist.count('b') == 1:
             wire = "first"
         elif wirelist.count('y') > 1:
             wire = "last"
         else:
             wire = "second"
     elif len(wirelist) == 5:
         if wirelist[-1] == 'k' and self.bomb.serial_odd:
             wire = "fourth"
         elif wirelist.count('r') == 1 and wirelist.count('y') > 1:
             wire = "first"
         elif 'k' not in wirelist:
             wire = "second"
         else:
             wire = "first"
     elif len(wirelist) == 6:
         if 'y' not in wirelist and self.bomb.serial_odd:
             wire = "third"
         elif wirelist.count('y') == 1 and wirelist.count('w') > 1:
             wire = "fourth"
         elif 'r' not in wirelist:
             wire = "last"
         else:
             wire = "fourth"
     talk(f"Cut the {wire} wire.")
Example #20
0
 def stage(self) -> None:
     talk("What plugs are the wires connected to, in numeric order?")
     wire_plugs = ask.list_from_set(
         {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'})
     talk(F"Starting from plug {wire_plugs[0]}, "
          "what colors are the wires in clockwise order?")
     wire_colors = ask.list_from_set(self.valid_colors,
                                     expected_len=len(wire_plugs))
     start_index: int
     if self.bomb.has_port(Port.RJ45) and ('4' in wire_plugs
                                           and '5' in wire_plugs):
         start_index = wire_plugs.index('4')
     elif str(self.bomb.batteries) in wire_plugs:
         start_index = wire_plugs.index(str(self.bomb.batteries))
     elif self.bomb.serial_first_digit in wire_plugs:
         start_index = wire_plugs.index(self.bomb.serial_first_digit)
     elif not self.bomb.has_indicator('CLR', True):
         start_index = 0
     else:
         talk("Cut all of the wires in reverse order.")
         return
     self.wire_loop(wire_plugs, wire_colors, start_index)
Example #21
0
 def stage(self) -> None:
     talk("What word is on the display?")
     word = ask.str_from_set(self.words)
     anagrams = [w for w in self.words if set(w) == set(word) and w != word]
     talk(f'Type in the word "{anagrams[0]}"')
 def stage(self) -> None:
     talk("What color is the button?")
     talk(
         'Type one of "red", "yellow", "blue", or "white", without quotes.')
     color = ask.str_from_set(self.valid_colors)
     talk("What is the text on the label?")
     talk(
         'Type one of "abort", "detonate", "hold", or "press", without quotes.'
     )
     label = ask.str_from_set(self.valid_labels)
     if color == "blue" and label == "abort":
         self._hold()
     elif self.bomb.batteries > 1 and label == "detonate":
         talk("Press and immediately release the button.")
     elif color == "white" and ('car', True) in self.bomb.indicators:
         self._hold()
     elif self.bomb.batteries > 2 and ('frk', True) in self.bomb.indicators:
         talk("Press and immediately release the button.")
     elif color == "yellow":
         self._hold()
     elif color == "red" and label == "hold":
         talk("Press and immediately release the button.")
     else:
         self._hold()
 def stage(self) -> None:
     while True:
         talk("What coordinate contains the white light?")
         start = maze.Node._make(grid.ask_coord())
         talk("What coordinate contains the red triangle?")
         goal = maze.Node._make(grid.ask_coord())
         talk("What coordinate contains a circular marking?")
         talk("(You may use either one.)")
         marking = grid.ask_coord()
         while marking not in self.mark_to_maze:
             talk("That doesn't fit any of the mazes.")
             talk("What coordinate contains a circular marking?")
             talk("(You may use either one.)")
             marking = grid.ask_coord()
         walls = self.mark_to_maze[marking]
         path = maze.solve_maze(grid.Dimensions(6, 6), start, goal, walls)
         if not path:
             talk("Something went wrong and I couldn't find a path.")
             continue
         talk("Press the following directions in order:")
         for direction in path:
             talk(direction)
         return
 def stage(self) -> None:
     talk("What symbols are on the keypad?")
     symbols = ask.list_from_set(self.valid_symbols,
                                 print_options=True,
                                 expected_len=4)
     while all(
             any(sym not in col for sym in symbols)
             for col in self.columns):
         talk("I couldn't find a solution for those symbols.")
         talk("Please ensure you typed them correctly.")
         talk("What symbols are on the keypad?")
         symbols = ask.list_from_set(self.valid_symbols,
                                     print_options=True,
                                     expected_len=4)
     for col in self.columns:
         if all(sym in col for sym in symbols):
             talk("Press the keys in the following order:")
             for symbol in [sym for sym in col if sym in symbols]:
                 talk(symbol.upper())
 def stage(self) -> None:
     talk("What wires are on the module?")
     talk(
         "For each wire, include its colors, any of (R)ed, (B)lue, or (W)hite,"
     )
     talk(
         "whether the LED above it is (L)it, and whether a (S)tar is present."
     )
     talk("Input each wire as a string of the parenthesized letters above.")
     wirelist = ask.list_from_regex(r"[rbwls]+")
     for wire in wirelist:
         if self.cut(wire):
             talk(f"Cut wire {wire.upper()}.")
         else:
             talk(f"Do not cut wire {wire.upper()}.")
Example #26
0
 def _get_serial(self, serial: Optional[str]) -> None:
     if serial is not None and self._serial_valid(serial):
         self.serial = serial
     elif EdgeFlag.SERIAL in self._required_edgework_flag:
         talk("What is the serial number?")
         self.serial = ask.str_from_func(self._serial_valid).lower()
Example #27
0
 def announce(self) -> None:
     """Print the Now Solving message for this module.
     To be used only at the start of each new module."""
     module_number = self.solved_count + 1
     talk(f"--- NOW SOLVING: {self.name} #{module_number}",
          warning_bypass=True)
Example #28
0
 def stage(self) -> None: #pylint: disable=too-many-branches #can't help it
     talk("What color is the last word in the sequence?")
     last_color = ask.str_from_set(self.valid_colors)
     if last_color == "red":
         if ask.yes_no("Does the word Green appear at least three times?"):
             talk("Press Yes on the third word whose color or text is green.")
         elif ask.yes_no("Is there exactly one blue-colored word?"):
             talk("Press No on the word Magenta.")
         else:
             talk("Press Yes on the last word whose color or text is white.")
     elif last_color == "yellow":
         if ask.yes_no("Does the word Blue appear colored green?"):
             talk("Press Yes on the first word colored green.")
         elif ask.yes_no("Does the word White appear colored white or red?"):
             talk("Press Yes on the second word whose color doesn't match its text.")
         else:
             talk("Count the number of words whose color or text is magenta.")
             talk("Press No that many words into the sequence.")
     elif last_color == "green":
         if ask.yes_no("Does a word appear twice in a row with different colors?"):
             talk("Press No on the fifth word in the sequence.")
         elif ask.yes_no("Does the word Magenta appear at least three times?"):
             talk("Press No on the first word whose color or text is yellow.")
         else:
             talk("Press Yes on any word whose text matches its color.")
     elif last_color == "blue":
         if ask.yes_no("Are there at least three words whose"
                       " color doesn't match their text?"):
             talk("Press Yes on the first such word.")
         elif (ask.yes_no("Does the word Red appear colored yellow?")
               or ask.yes_no("Does the word Yellow appear colored white?")):
             talk("Press No on the word White that is colored red.")
         else:
             talk("Press Yes on the last word whose color or text is green.")
     elif last_color == "magenta":
         if ask.yes_no("Do two words in a row share a color?"):
             talk("Press Yes on the third word.")
         elif ask.yes_no("Are there more words reading Yellow"
                         " than words colored blue?"):
             talk("Press No on the last word whose text is Yellow.")
         else:
             talk("Note the text of the seventh word.")
             talk("Press No on the first word with that color.")
     else: #white
         if ask.yes_no("Does the third word's color match"
                       " the fourth or fifth words' text?"):
             talk("Press No on the first word whose color or text is blue.")
         elif ask.yes_no("Does the word Yellow appear colored red?"):
             talk("Press Yes on the last word colored blue.")
         else:
             talk("Press No at any time.")
Example #29
0
 def add_strike(self) -> None:
     "Add a strike, and quit if we hit the strike limit."
     self.strikes += 1
     if self.hit_strike_limit:
         talk("Bomb exploded! Hopefully it wasn't my fault.")
         raise SystemExit
Example #30
0
    def wire_loop(
            self,
            wire_plugs: List[str],  #pylint: disable=too-many-branches
            wire_colors: List[str],
            start_index: int) -> None:
        "Given a starting index, determine which wires in the loop to cut."
        rules_reverse_order = wire_colors[start_index] in ('red', 'green',
                                                           'white')
        current_index = start_index
        prev_cut = True
        talk(f"Cut the wire starting at plug {wire_plugs[current_index]}.")

        prev_index = current_index
        current_index = (current_index + 1) % len(wire_plugs)
        current_rule: int
        if self.bomb.serial_first_letter:
            current_rule = "abcdefghijklmnopqrstuvwxyz".index(
                self.bomb.serial_first_letter) % 13
        else:
            current_rule = 0
        while current_index != start_index:
            if (current_rule == 0 and wire_colors[prev_index]
                    not in {"yellow", "blue", "green"}):
                prev_cut = True
            elif current_rule == 1 and int(wire_plugs[current_index]) % 2 == 0:
                prev_cut = True
            elif current_rule == 2 and prev_cut:
                prev_cut = True
            elif (current_rule == 3
                  and wire_colors[prev_index] in {"red", "blue", "black"}):
                prev_cut = True
            elif (current_rule == 4 and len({
                    wire_colors[i]
                    for i in range(prev_index, prev_index - 3, -1)
            }) < 3):
                prev_cut = True
            elif (
                    current_rule == 5  #!= is equivalent to xor in this context
                    and
                ((wire_colors[prev_index] == wire_colors[current_index]) !=
                 (wire_colors[prev_index - 1] == wire_colors[current_index]))):
                prev_cut = True
            elif (current_rule == 6
                  and wire_colors[prev_index] in {"yellow", "white", "green"}):
                prev_cut = True
            elif current_rule == 7 and not prev_cut:
                prev_cut = True
            elif (current_rule == 8 and int(wire_plugs[prev_index]) + 1 != int(
                    wire_plugs[current_index])):
                prev_cut = True
            elif (current_rule == 9 and wire_colors[prev_index]
                  not in {"white", "black", "red"}):
                prev_cut = True
            elif (current_rule == 10
                  and wire_colors[prev_index] != wire_colors[prev_index - 1]):
                prev_cut = True
            elif current_rule == 11 and int(wire_plugs[current_index]) > 6:
                prev_cut = True
            elif (current_rule == 12 and
                  (wire_colors[prev_index] not in {"white", "black"}
                   or wire_colors[prev_index - 1] not in {"white", "black"})):
                prev_cut = True
            else:
                prev_cut = False

            if prev_cut:
                talk(
                    f"Cut the wire starting at plug {wire_plugs[current_index]}."
                )
            prev_index = current_index
            current_index = (current_index + 1) % len(wire_plugs)
            current_rule = (current_rule +
                            (-1 if rules_reverse_order else 1)) % 13