last week's exercises / katas
This commit is contained in:
parent
eb6a242257
commit
aea0c0173d
@ -2,7 +2,6 @@ import typing
|
||||
|
||||
|
||||
class Router(object):
|
||||
|
||||
def __init__(self):
|
||||
self.routes = {}
|
||||
|
||||
|
||||
303
src/codewars/chemist.py
Normal file
303
src/codewars/chemist.py
Normal file
@ -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)
|
||||
32
src/codewars/cipher_helper.py
Normal file
32
src/codewars/cipher_helper.py
Normal file
@ -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
|
||||
@ -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))
|
||||
|
||||
39
src/exercises/fetcher_protocol.py
Normal file
39
src/exercises/fetcher_protocol.py
Normal file
@ -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"))
|
||||
@ -208,7 +208,6 @@ def main() -> None:
|
||||
]
|
||||
|
||||
for filename in files:
|
||||
|
||||
BASE_DIR = Path(__file__).parent
|
||||
file_path = BASE_DIR / "data" / filename
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -27,7 +27,6 @@ def filter_dataframe(df, col, func):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
df = pd.DataFrame(
|
||||
{
|
||||
"A": list(range(0, 10)),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user