diff --git a/src/codewars/SimpleWebFramework.py b/src/codewars/SimpleWebFramework.py index dd111de..50ceb7a 100644 --- a/src/codewars/SimpleWebFramework.py +++ b/src/codewars/SimpleWebFramework.py @@ -2,7 +2,6 @@ import typing class Router(object): - def __init__(self): self.routes = {} diff --git a/src/codewars/chemist.py b/src/codewars/chemist.py new file mode 100644 index 0000000..28383b7 --- /dev/null +++ b/src/codewars/chemist.py @@ -0,0 +1,303 @@ +PERIODIC_TABLE: dict[str, tuple[int, float | int]] = { + "H": (1, 1.0), + "B": (3, 10.8), + "C": (4, 12.0), + "N": (3, 14.0), + "O": (2, 16.0), + "F": (1, 19.0), + "Mg": (2, 24.3), + "P": (3, 31.0), + "S": (2, 32.1), + "Cl": (1, 35.5), + "Br": (1, 80.0), +} + + +class LockedMolecule(Exception): + pass + + +class UnlockedMolecule(Exception): + pass + + +class InvalidBond(Exception): + pass + + +class EmptyMolecule(Exception): + pass + + +class Atom(object): + def __init__(self, elt: str, id_: int): + self.element = elt + self.id = id_ + self.bounds = [] + self.max_bounds = PERIODIC_TABLE[self.element][0] + self.weight = PERIODIC_TABLE[self.element][1] + + def __hash__(self): + return self.id + + def __eq__(self, other): + return self.id == other.id + + def __str__(self): + bounds = [] + + bounds.extend( + list(sorted(Molecule.filter_element(self.bounds, "C"), key=lambda b: b.id)) + ) + bounds.extend( + list(sorted(Molecule.filter_element(self.bounds, "O"), key=lambda b: b.id)) + ) + + for bound in list( + sorted(sorted(self.bounds, key=lambda b: b.id), key=lambda b: b.element) + ): + if bound.element not in ["C", "H", "O"]: + bounds.append(bound) + + bounds.extend( + list(sorted(Molecule.filter_element(self.bounds, "H"), key=lambda b: b.id)) + ) + + return ( + f"Atom({self.element}.{self.id}" + f"{': ' if bounds else ''}" + f"{','.join(bound.element + (str(bound.id) if bound.element != 'H' else '') for bound in bounds)})" + ) + + def add_bound(self, atom): + if self == atom: + raise InvalidBond + if len(self.bounds) >= self.max_bounds: + raise InvalidBond + + self.bounds.append(atom) + + @staticmethod + def remove_bounds(atom1, atom2): + if not (atom1 or atom2): + return + + if atom1 in atom2.bounds: + atom2.bounds.remove(atom1) + + if atom2 in atom1.bounds: + atom1.bounds.remove(atom2) + + def mutate(self, element: str): + if len(self.bounds) > PERIODIC_TABLE[element][0]: + raise InvalidBond + + self.element = element + self.max_bounds = PERIODIC_TABLE[self.element][0] + self.weight = PERIODIC_TABLE[self.element][1] + + def unlock(self): + self.bounds = list(filter(lambda atom: atom.element != "H", self.bounds)) + + +class Molecule(object): + name: str + _formula: str + _molecular_weight: float + atoms: list[Atom] + branches: dict[int, list[Atom]] + locked: bool = False + exception_thrown = False + + def __init__(self, name=""): + self.name = name + self.atoms = [] + self.branches = {} + + @staticmethod + def filter_element(atoms: list[Atom], element: str) -> list[Atom]: + return list(filter(lambda atom: element == atom.element, atoms)) + + def brancher(self, *branches: int): + if self.locked: + raise LockedMolecule + + for carbons in branches: + branch_id = len(self.branches) + 1 + self.branches[branch_id] = [] + for i in range(1, carbons + 1): + atom = Atom(elt="C", id_=len(self.atoms) + i) + self.branches[branch_id].append(atom) + + if i > 1: + last_atom = self.branches[branch_id][i - 2] + + try: + atom.add_bound(last_atom) + last_atom.add_bound(atom) + except InvalidBond as e: + Atom.remove_bounds(atom, last_atom) + raise e + + self.atoms.extend(self.branches[branch_id]) + return self + + def bounder(self, *bounds: tuple[int, int, int, int]): + if self.locked: + raise LockedMolecule + + for c1, b1, c2, b2 in bounds: + atom1 = self.branches[b1][c1 - 1] + atom2 = self.branches[b2][c2 - 1] + + atom1_bounds = atom1.bounds[:] + atom2_bounds = atom2.bounds[:] + + try: + atom1.add_bound(atom2) + atom2.add_bound(atom1) + except InvalidBond as e: + atom1.bounds = atom1_bounds + atom2.bounds = atom2_bounds + raise e + + return self + + def mutate(self, *mutations: tuple[int, int, str]): + if self.locked: + raise LockedMolecule + + for nc, nb, element in mutations: + atom = self.branches[nb][nc - 1] + try: + atom.mutate(element) + except InvalidBond as e: + raise e + + return self + + def add(self, *additions: tuple[int, int, str]): + if self.locked: + raise LockedMolecule + + for nc, nb, element in additions: + atom = Atom(elt=element, id_=len(self.atoms) + 1) + carbon = self.branches[nb][nc - 1] + + try: + carbon.add_bound(atom) + atom.add_bound(carbon) + except InvalidBond as e: + Atom.remove_bounds(carbon, atom) + raise e + + self.atoms.append(atom) + + return self + + def add_chaining(self, nc: int, nb: int, *elements: str): + if self.locked: + raise LockedMolecule + + carbon = self.branches[nb][nc - 1] + + chain = [] + + try: + last_atom = Atom(elt=elements[0], id_=len(self.atoms) + len(chain) + 1) + chain.append(last_atom) + + for element in elements[1:]: + atom = Atom(elt=element, id_=len(self.atoms) + len(chain) + 1) + chain.append(atom) + last_atom.add_bound(atom) + atom.add_bound(last_atom) + last_atom = atom + except InvalidBond as e: + Atom.remove_bounds(atom, last_atom) + raise e + + try: + carbon.add_bound(chain[0]) + chain[0].add_bound(carbon) + except InvalidBond as e: + Atom.remove_bounds(carbon, chain[0]) + raise e + + self.atoms.extend(chain) + + return self + + def closer(self): + if self.locked: + raise LockedMolecule + + try: + for atom in self.atoms: + while len(atom.bounds) < atom.max_bounds: + hydrogen = Atom(elt="H", id_=len(self.atoms) + 1) + atom.add_bound(hydrogen) + hydrogen.add_bound(atom) + self.atoms.append(hydrogen) + except InvalidBond as e: + Atom.remove_bounds(atom, hydrogen) + raise e + + self.locked = True + + return self + + def unlock(self): + self.locked = False + self.atoms = list(filter(lambda atom: atom.element != "H", self.atoms)) + + for new_id, atom in enumerate(self.atoms, start=1): + atom.unlock() + atom.id = new_id + + new_branches = {} + new_id = 1 + for atoms in self.branches.values(): + filtered = list(filter(lambda atom: atom.element != "H", atoms)) + if len(filtered) > 0: + new_branches[new_id] = filtered + new_id += 1 + + self.branches = new_branches + + if not self.branches: + raise EmptyMolecule + + return self + + @property + def formula(self) -> str: + if not self.locked: + raise UnlockedMolecule + + elements = set(atom.element for atom in self.atoms) + formula = "" + + if "C" in elements: + c_len = len(Molecule.filter_element(self.atoms, "C")) + formula += f"C{c_len if c_len > 1 else ''}" + if "H" in elements: + h_len = len(Molecule.filter_element(self.atoms, "H")) + formula += f"H{h_len if h_len > 1 else ''}" + if "O" in elements: + o_len = len(Molecule.filter_element(self.atoms, "O")) + formula += f"O{o_len if o_len > 1 else ''}" + + for element in list(sorted(elements)): + if element not in ["C", "H", "O"]: + num = len(Molecule.filter_element(self.atoms, element)) + formula += f"{element}{num if num > 1 else ''}" + + return formula + + @property + def molecular_weight(self) -> float: + if not self.locked: + raise UnlockedMolecule + + return sum(atom.weight for atom in self.atoms) diff --git a/src/codewars/cipher_helper.py b/src/codewars/cipher_helper.py new file mode 100644 index 0000000..acad08a --- /dev/null +++ b/src/codewars/cipher_helper.py @@ -0,0 +1,32 @@ +class VigenereCipher(object): + def __init__(self, key: str, alphabet: str): + self.key = key + self.alphabet = alphabet + + def encode(self, text): + encoded_text = "" + + for idx, c in enumerate(text): + alph_position = self.alphabet.find(c) + if alph_position == -1: + encoded_text += c + continue + shift = self.alphabet.find(self.key[idx % len(self.key)]) + + encoded_text += self.alphabet[(alph_position + shift) % len(self.alphabet)] + + return encoded_text + + def decode(self, text): + encoded_text = "" + + for idx, c in enumerate(text): + alph_position = self.alphabet.find(c) + if alph_position == -1: + encoded_text += c + continue + shift = self.alphabet.find(self.key[idx % len(self.key)]) + + encoded_text += self.alphabet[(alph_position - shift) % len(self.alphabet)] + + return encoded_text diff --git a/src/exercises/dog.py b/src/exercises/dog.py index d9bdf4a..5a115ee 100644 --- a/src/exercises/dog.py +++ b/src/exercises/dog.py @@ -72,3 +72,5 @@ print(dog2.bark(3)) print(dog2.is_puppy()) print(Dog.amount_of_dogs) print(dog2 == dog1) + +print("is a dog", isinstance(dog1, Dog)) diff --git a/src/exercises/fetcher_protocol.py b/src/exercises/fetcher_protocol.py new file mode 100644 index 0000000..d4589ee --- /dev/null +++ b/src/exercises/fetcher_protocol.py @@ -0,0 +1,39 @@ +from dataclasses import dataclass +from typing import Protocol + + +@dataclass +class CodeWarsUser: + username: str + + +class UserFetcher(Protocol): + @staticmethod + def get_user(username: str) -> CodeWarsUser: + return CodeWarsUser(username) + + +class CodewarsAdapter: + @staticmethod + def get_user(username: str) -> CodeWarsUser: + return CodeWarsUser(username) + + +class FakeAdapter: + @staticmethod + def get_user(username: str) -> CodeWarsUser: + return CodeWarsUser(username) + + +class WrongAdapter: + pass + + +fetchers: list = [] + +fetchers.append(CodewarsAdapter()) +fetchers.append(FakeAdapter()) +fetchers.append(WrongAdapter()) + +for fetcher in fetchers: + print(fetcher.get_user("user name")) diff --git a/src/order5_initial/main.py b/src/order5_initial/main.py index 5ea6cd2..a512c0b 100644 --- a/src/order5_initial/main.py +++ b/src/order5_initial/main.py @@ -208,7 +208,6 @@ def main() -> None: ] for filename in files: - BASE_DIR = Path(__file__).parent file_path = BASE_DIR / "data" / filename diff --git a/src/testing/catching_exeptions.py b/src/testing/catching_exeptions.py index b040155..cebeb6e 100644 --- a/src/testing/catching_exeptions.py +++ b/src/testing/catching_exeptions.py @@ -23,7 +23,6 @@ def double_integers(data: list[int]) -> list[int]: if __name__ == "__main__": - data = [1, 2, 3] result = double_integers(data) print(result) diff --git a/src/testing/pandas_filter_rows.py b/src/testing/pandas_filter_rows.py index c929df1..f694aba 100644 --- a/src/testing/pandas_filter_rows.py +++ b/src/testing/pandas_filter_rows.py @@ -27,7 +27,6 @@ def filter_dataframe(df, col, func): if __name__ == "__main__": - df = pd.DataFrame( { "A": list(range(0, 10)),