diff --git a/src/constants.py b/src/constants.py new file mode 100644 index 0000000..7b75d11 --- /dev/null +++ b/src/constants.py @@ -0,0 +1,43 @@ +from modules.wires import WiresModule +from modules.button import ButtonModule +from modules.password import PasswordModule + +modules = { + 'wires': WiresModule, + 'button': ButtonModule, + 'keypad': None, + 'simon': None, + 'first': None, + 'memory': None, + 'morse': None, + 'compwires': ComplicatedWiresModule, + 'seqwires': None, + 'maze': None, + 'password': PasswordModule, + 'vent': None, + 'discharge': None, + 'knob': None, +} + +indicators = [ + 'SND', + 'CLR', + 'CAR', + 'IND', + 'FRQ', + 'SIG', + 'NSA', + 'MSA', + 'TRN', + 'BOB', + 'FRK', +] + +ports = [ + 'DVI', + 'Para', + 'PS2', + 'RJ45', + 'Serial', + 'RCA', +] diff --git a/src/modules/__init__.py b/src/modules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/button.py b/src/modules/button.py new file mode 100644 index 0000000..1223786 --- /dev/null +++ b/src/modules/button.py @@ -0,0 +1,69 @@ +from enum import Enum, auto +from prompt_toolkit import prompt +from prompt_toolkit.completion import WordCompleter + +class ButtonAction(Enum): + RELEASE = auto(), + HOLD = auto() + +class ButtonModule: + def __init__(self, color, text, state): + self.color = color + self.text = text.lower() + self.state = state + + def solve(self): + if self.color == "blue" and self.text == "abort": + return ButtonAction.HOLD + + elif self.state.batteries > 1 and self.text == "detonate": + return ButtonAction.RELEASE + + try: + if self.color == "white" and self.indicators["CAR"] == True: + return ButtonAction.HOLD + except KeyError: pass + + try: + if self.state.batteries > 2 and self.indicators["FRK"] == True: + return ButtonAction.RELEASE + except KeyError: pass + + if self.color == "yellow": + return ButtonAction.HOLD + + elif self.color == "red" and self.text == "hold": + return ButtonAction.RELEASE + + return ButtonAction.HOLD + + def hold(self, color): + if color == "blue": + return 4 + elif color == "white": + return 1 + elif color == "yellow": + return 5 + + return 1 + + @classmethod + def interactive(cls, state, cmdline): + print("Please enter button color") + color = prompt('button> ') + print("Please enter button text") + text = prompt('button> ') + + button = cls(color, text, state) + result = button.solve() + + if result == ButtonAction.HOLD: + print("What is the held button color") + heldcolor = prompt('button> ') + + print("Release until the timer has a {} in any position".format( + str(button.hold(heldcolor)) + )) + else: + print("Release") + diff --git a/comp_wires.py b/src/modules/comp_wires.py similarity index 66% rename from comp_wires.py rename to src/modules/comp_wires.py index 9c81828..d58fbf6 100644 --- a/comp_wires.py +++ b/src/modules/comp_wires.py @@ -1,4 +1,6 @@ from enum import Enum, auto +from prompt_toolkit import prompt +from prompt_toolkit.completion import WordCompleter class MappedAction(Enum): CUT_UNCONDITIONALLY = auto(), @@ -11,18 +13,7 @@ class FinalAction(Enum): CUT = auto(), NO_CUT = auto() -class GlobalState: - def __init__(self, serial, parallel, batteries): - self.serial = serial - self.parallel = parallel - self.batteries = batteries - - if int(self.serial[-1]) % 2 == 0: - self.serial_even = True - else: - self.serial_even = False - -class ComplicatedWire: +class ComplicatedWiresModule: def __init__(self, red, blue, star, led, state): self.red = red self.blue = blue @@ -63,7 +54,6 @@ class ComplicatedWire: def resolveAction(self): action = self.getAction() - print(action) if action == MappedAction.CUT_UNCONDITIONALLY: return FinalAction.CUT @@ -72,12 +62,12 @@ class ComplicatedWire: return FinalAction.NO_CUT elif action == MappedAction.CUT_IF_DIGIT_EVEN: - if self.state.serial_even: + if self.state.serial.is_even: return FinalAction.CUT return FinalAction.NO_CUT elif action == MappedAction.CUT_IF_PARALLEL: - if self.state.parallel: + if 'Para' in self.state.ports: return FinalAction.CUT return FinalAction.NO_CUT @@ -87,22 +77,23 @@ class ComplicatedWire: return FinalAction.NO_CUT @classmethod - def human_helper(cls): - serial = input("serial (string)? ") - parallel = cls.custom_bool(input("parallel (bool)? ")) - batteries = int(input("number of batteries (int)? ")) + def interactive(cls, state, cmdline): + completer = WordCompleter(['red', 'blue', 'star', 'led', 'quit', 'exit']) - red = cls.custom_bool(input("is red (bool)? ")) - blue = cls.custom_bool(input("is blue (bool)? ")) - star = cls.custom_bool(input("is star (bool)? ")) - led = cls.custom_bool(input("is led (bool)? ")) + # there are 6 wires in the complicated wires module + while True: + text = prompt('compwires> ', completer=completer, complete_while_typing=True) - print(red, blue, star, led) + if text == "quit": + return - state = GlobalState(serial, parallel, batteries) - wire = cls(red, blue, star, led, state) + elif text == "exit": + return - print(wire.resolveAction()) + attr = [i in text for i in ['red', 'blue', 'star', 'led']] -if __name__ == "__main__": - ComplicatedWire.human_helper() + try: + print("CUT" if cls(*attr, state).resolveAction() == FinalAction.CUT else "NO CUT") + + except AttributeError: + print("the state hasn't been completed. maybe fill out the serial?") diff --git a/passwords.py b/src/modules/password.py similarity index 100% rename from passwords.py rename to src/modules/password.py diff --git a/src/modules/wires.py b/src/modules/wires.py new file mode 100644 index 0000000..58bb68d --- /dev/null +++ b/src/modules/wires.py @@ -0,0 +1,78 @@ +from prompt_toolkit import prompt +from prompt_toolkit.completion import WordCompleter + +class WiresModule: + def __init__(self, wires, state): + self.state = state + self.wires = wires.split(' ') + self.len = len(self.wires) + + def solve(self): + # prints the solved solution + + if self.len == 3: + if not 'red' in self.wires: + return "second wire" + + elif self.wires[-1] == "white": + return "last wire" + + elif self.wires.count('blue') > 1: + return "last blue wire" + + else: + return "last wire" + + elif self.len == 4: + if self.wires.count('red') > 1 and self.state.serial.is_odd: + return "last red wire" + + elif self.wires[-1] == 'yellow' and not 'red' in self.wires: + return "first wire" + + elif self.wires.count('blue') == 1: + return "first wire" + + elif self.wires.count('yellow') > 1: + return "last wire" + + else: + return "second wire" + + elif self.len == 5: + if self.wires[-1] == 'black' and self.state.serial.is_odd: + return "fourth wire" + + elif self.wires.count('red') == 1 and self.wires.count('yellow') > 1: + return "first wire" + + elif not 'black' in self.wires: + return "second wire" + + else: + return "first wire" + + elif self.len == 6: + if not 'yellow' in self.wires and self.state.serial.is_odd: + return "third wire" + + elif self.wires.count('yellow') == 1 and self.wires.count('white') > 1: + return "fourth wire" + + elif not 'red' in self.wires: + return "last wire" + + else: + return "fourth wire" + + @classmethod + def interactive(cls, state, cmdline): + completer = WordCompleter(['red', 'blue', 'yellow', 'white', 'black']) + + print("Please enter wire colors from top to bottom.") + text = prompt('wires> ', completer=completer, complete_while_typing=True) + + wires = WiresModule(text, state) + print("cut the {}".format(wires.solve())) + + return diff --git a/src/shell.py b/src/shell.py new file mode 100644 index 0000000..f017e19 --- /dev/null +++ b/src/shell.py @@ -0,0 +1,131 @@ +from constants import modules, indicators, ports + +from prompt_toolkit import PromptSession +from prompt_toolkit.completion import NestedCompleter + +maincompleter = NestedCompleter.from_nested_dict({ + 'help': None, + 'mark': None, + 'serial': None, + 'strike': None, + 'batteries': None, + 'eval': None, + 'indicator': {*[indicator for indicator in indicators]}, + 'ports': {*[port for port in ports]}, + 'mod': {*["mod {}".format(module) for module in modules.keys()]}, +}) + +class Serial: + def __init__(self, serial): + self.serial = serial.lower() + + @property + def is_even(self): + if int(self.serial[-1]) % 2 == 0: + return True + + return False + + @property + def is_odd(self): + return not self.is_even + + @property + def vowel(self): + for vowel in ['a', 'e', 'i', 'o', 'u']: + if vowel in self.serial: + return True + + return False + + @property + def no_vowel(self): + return not self.vowel + + @property + def text(self): + return self.serial + +class GlobalBombState: + def __init__(self): + self.indicators = {} + self.ports = [] + self._serial = None + self.batteries = 0 + self.modulecount = 0 + self.strikes = 0 + + @property + def serial(self): + return self._serial + + @serial.setter + def serial(self, serial): + self._serial = Serial(serial) + + def update_toolbar(self): + return "help for help, ports: {}, ind: {}, batt: {}, serial: {}, strikes {}".format( + self.ports, self.indicators, str(self.batteries), self.serial.text if self.serial else "?", str(self.strikes) + ) + +session = PromptSession(completer=maincompleter) +state = GlobalBombState() + +while True: + userinput = session.prompt("ktane> ", bottom_toolbar=state.update_toolbar(), complete_while_typing=True) + splitted = userinput.split(' ') + tokens = len(splitted) + command = splitted[0] + + if command == "mod": + if tokens == 1: + print(modules.keys()) + elif tokens > 1: + if splitted[1].isnumeric(): + state.modulecount = int(splitted[1]) + print("module count set to {}".format(str(state.modulecount))) + else: + try: + selectedmodule = modules[splitted[1]] + if selectedmodule: + selectedmodule.interactive(state, splitted[2:]) + else: + print("this module doesn't exist!") + except IndexError: + print("you didn't specify a module") + + elif command == "serial": # set the serial number + try: + state.serial = splitted[1] + print("serial number set to {}".format(state.serial.text)) + except IndexError: + print("specify a serial number, perhaps?") + + elif command == "batteries": + try: + state.batteries = int(splitted[1]) + print("battery count set to {}".format(str(state.batteries))) + except IndexError: + print("specify a number of batteries, perhaps?") + + elif command == "strike": + state.strikes += 1 + print("strike given") + + elif command == "ports": + try: + state.ports.append(splitted[1]) + print("appeneded port {}".format(splitted[1])) + except IndexError: + print("specify a port type") + + elif command == "indicator": + try: + state.indicators[splitted[1]] = True if splitted[2] == 't' else False + print("added indicator {} with state {}".format( + splitted[1], state.indicators[splitted[1]] + )) + except IndexError: print("specify an indicator and a state") + + elif command == "eval": + eval(' '.join(splitted[1:]))