commit 2898a6bd386b029b3aa486a15db91bc10995c31d Author: GASSER Thibaud (PRESTA EXT) Date: Tue Jan 23 14:32:21 2024 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a945fb4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ceb21ef --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Codewars solutions in python + +## Quickstart + +```console +$ pip install git+https://github.com/codewars/python-test-framework.git#egg=codewars_test +``` diff --git a/function_overloading/overload.py b/function_overloading/overload.py new file mode 100644 index 0000000..17e4470 --- /dev/null +++ b/function_overloading/overload.py @@ -0,0 +1,68 @@ +# https://www.codewars.com/kata/5f24315eff32c4002efcfc6a + +import inspect + +# https://docs.python.org/3.8/reference/datamodel.html#customizing-class-creation +# https://snarky.ca/unravelling-pythons-classes/ +# https://gist.github.com/tmr232/c7214d62607ba1fc0e0a2e82d7e041cd +class DispatchProxy: + def __init__(self, name): + self.registry = {} + self.name = name + + def register(self, f): + print(f"register {inspect.signature(f)}") + argcount = f.__code__.co_argcount + self.registry[argcount] = f + """ + def decorator(func): + argcount = f.__code__.co_argcount + self.registry[argcount] = f + return func + return decorator + """ + + def __call__(self, *args): + argcount = len(args) + 1 # add 1 because the first argument of a method is "self" + if argcount in self.registry: + resolved = self.registry[argcount] + print(f"resolved: {resolved.__name__}{inspect.signature(resolved)}") + return resolved(self, *args) + else: + raise AttributeError(f"No matching function for args: {args}") + + +class MyNamespace(dict): + def __getitem__(self, key): + #(f"get {key}") + return super().__getitem__(key) + + def __setitem__(self, key, value): + #sign = inspect.signature(value) if callable(value) else value + #print(f"set {key} {value}") + + # already exists => overload + is_method = callable(value) and not value.__name__.startswith("__") + + if is_method and key in self: + m = self[key] + if not isinstance(m, DispatchProxy): + m = DispatchProxy(self) + m.register(self[key]) + m.register(value) + super().__setitem__(key, m) + else: + super().__setitem__(key, value) + + +class Meta(type): + @classmethod + def __prepare__(cls, name, bases): + return MyNamespace() + + def __new__(cls, name, bases, dct): + x = super().__new__(cls, name, bases, dct) + return x + + def __init__(self, name, bases, attrs): + super(Meta, self).__init__(name, bases, attrs) \ No newline at end of file diff --git a/function_overloading/tests.py b/function_overloading/tests.py new file mode 100644 index 0000000..fad80a1 --- /dev/null +++ b/function_overloading/tests.py @@ -0,0 +1,160 @@ +import codewars_test as test +from overload import Meta + +cng_msg = 'Dont change the properties of class.' +sld_work = 'Function overloading should work.' + + +@test.describe('Python Recipes #1 : Function Overloading') +def _(): + + # implement meta class ----- + + def build(): # returning class to regenerate accordingly. + + class Overload(metaclass=Meta): + + CLS_VAR = 42 + + def __init__(self): + self.a = 1 + self.no = 'This is "No parameter" function.' + self.single = 'This is "Single parameter" function' + self.two = 'This is "Two parameter" function' + self.three = 'This is "Three parameter" function' + + def foo(self): + return self.no + + def foo(self, x): + return self.single + ':' + str(x) + + def foo(self, x, y): + return self.two + ':' + str(x) + ',' + str(y) + + def foo(self, x, y, z): + return self.three + ':' + str(x) + ',' + str(y) + ',' + str(z) + + def extra(self): + return 'This is extra method.' + + return Overload + + @test.describe('Sample tests') + def _(): + + overload = build() + obj = overload() + + + @test.it('Verifying access') + def _(): + test.assert_equals(obj.a, 1, cng_msg) + test.assert_equals(obj.no, 'This is "No parameter" function.', cng_msg) + test.assert_equals(obj.single, 'This is "Single parameter" function', cng_msg) + test.assert_equals(obj.two, 'This is "Two parameter" function', cng_msg) + test.assert_equals(obj.three, 'This is "Three parameter" function', cng_msg) + test.assert_equals(obj.extra(), 'This is extra method.', cng_msg) + test.assert_equals(obj.CLS_VAR, 42, cng_msg) + + @test.it('Verifying overloading feature') + def _(): + test.assert_equals(obj.foo(), 'This is "No parameter" function.', sld_work) + test.assert_equals(obj.foo(1), 'This is "Single parameter" function:1', sld_work) + test.assert_equals(obj.foo(1,2), 'This is "Two parameter" function:1,2', sld_work) + test.assert_equals(obj.foo(1,2,3), 'This is "Three parameter" function:1,2,3', sld_work) + + @test.it('Verifying overloading feature after adding new methods :1') + def _(): + + def foo(self, a, b, c, d): + return self.a + a + b + c + d + + def foo1(self, a, b): + return 'Overwritten' + + overload.foo = foo + + + test.assert_equals(obj.foo(), 'This is "No parameter" function.', sld_work) + test.assert_equals(obj.foo(1), 'This is "Single parameter" function:1', sld_work) + test.assert_equals(obj.foo(1,2), 'This is "Two parameter" function:1,2', sld_work) + test.assert_equals(obj.foo(1,2,3), 'This is "Three parameter" function:1,2,3', sld_work) + + test.assert_equals(obj.foo(1,2,3,4), 11, sld_work) + + overload.foo = foo1 + test.assert_equals(obj.foo(1,2), 'Overwritten', sld_work) + + + @test.it('Verifying overloading feature after adding new methods :2') + def _(): + + def boo1(self): + return self.a + + def boo2(self, a): + return self.a + a + + def unique(self, a, b): + return a + b + + overload.boo = boo1 + overload.boo = boo2 + obj.nothing = '123' + overload.unique = unique + + test.assert_equals(obj.boo(), 1, sld_work) + test.assert_equals(obj.boo(1), 2, sld_work) + test.assert_equals(obj.unique(1, 2), 3, sld_work) + test.assert_equals(obj.nothing, '123', sld_work) + + + + @test.describe('Verify the absence of unwanted sharing of methods between different classes') + def _(): + class Unshare(metaclass=Meta): + def foo(self,a,b): return 'unshared!' + + unsh=Unshare() + @test.it('The new foo function in Unshare class should be used') + def _(): + test.assert_equals(unsh.foo(1,2), 'unshared!') + + @test.it('Previous implementations of "foo" in other classes shouldn\'t be visible from a freshly built class') + def _(): + test.expect_error("Your function didn't raise any exception", lambda: unsh.foo(1), Exception) + test.expect_error("Your function should raise AttributeError", lambda: unsh.foo(1), AttributeError) + + @test.it('Previous method with the same signature in other classes shouldn\'t be affected') + def _(): + test.assert_equals(obj.foo(1,2), 'Overwritten') + + + @test.it('Class level variables are still working as expected') + def _(): + def over(): obj.CLS_VAR=-42 + def write(): obj.HAHA=msg + + test.expect_no_error("Class level variables can be overriden", over) + test.assert_equals(obj.CLS_VAR, -42, "Class variable Overload.CLS_VAR hasn't been overriden") + + msg = 'This is another class variable' + test.expect_no_error("New class level variables can be defined", write) + test.assert_equals(obj.HAHA, msg, "New class level variables can be defined and accessed") + + + @test.it('Undefined methods or variables should raise AttributeError') + def _(): + test.expect_error('Undefined attributes/mehtods should raise AttributeError', + lambda: overload.NEW_CLS_VAR, AttributeError) + test.expect_error('Undefined attributes/mehtods should raise AttributeError', + lambda: obj.ABCD, AttributeError) + test.expect_error('Undefined attributes/mehtods should raise AttributeError', + lambda: obj.randomFuncName(), AttributeError) + + + @test.it('undefined overloaded methods (wrong number of arguments should raise AttributeError)') + def _(): + test.expect_error('Undefined attributes/mehtods should raise AttributeError', + lambda: overload.foo(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1), AttributeError) diff --git a/prime_streaming/Scripts/python.exe b/prime_streaming/Scripts/python.exe new file mode 100644 index 0000000..71092d0 Binary files /dev/null and b/prime_streaming/Scripts/python.exe differ diff --git a/prime_streaming/Scripts/pythonw.exe b/prime_streaming/Scripts/pythonw.exe new file mode 100644 index 0000000..4710dd5 Binary files /dev/null and b/prime_streaming/Scripts/pythonw.exe differ diff --git a/prime_streaming/helper.py b/prime_streaming/helper.py new file mode 100644 index 0000000..9bedc93 --- /dev/null +++ b/prime_streaming/helper.py @@ -0,0 +1,41 @@ +from threading import Thread +import functools + +def timeout(timeout): + def deco(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, timeout))] + def newFunc(): + try: + res[0] = func(*args, **kwargs) + except Exception as e: + res[0] = e + t = Thread(target=newFunc) + t.daemon = True + try: + t.start() + t.join(timeout) + except Exception as je: + print ('error starting thread') + raise je + ret = res[0] + if isinstance(ret, BaseException): + raise ret + return ret + return wrapper + return deco + + +if __name__ == "__main__": + @timeout(timeout=5) + def long_running_function(): + import time + time.sleep(10) + return "Function completed successfully" + + try: + result = long_running_function() + print(result) + except TimeoutError as e: + print(e) \ No newline at end of file diff --git a/prime_streaming/pyvenv.cfg b/prime_streaming/pyvenv.cfg new file mode 100644 index 0000000..479bfb0 --- /dev/null +++ b/prime_streaming/pyvenv.cfg @@ -0,0 +1,5 @@ +home = C:\Python312 +include-system-site-packages = false +version = 3.12.0 +executable = C:\Python312\python.exe +command = C:\Python312\python.exe -m venv C:\Users\GASSERTH\source\bidouilles\codewars\prime_streaming diff --git a/prime_streaming/stream.py b/prime_streaming/stream.py new file mode 100644 index 0000000..ca17af4 --- /dev/null +++ b/prime_streaming/stream.py @@ -0,0 +1,58 @@ +import numpy as np + +def sieve_np(limit): + if limit < 2: + return [] + + # Create a boolean array "is_prime" and initialize all entries as True + is_prime = np.ones(limit + 1, dtype=bool) + is_prime[0:2] = False # 0 and 1 are not prime numbers + + for p in range(2, int(limit**0.5) + 1): + if is_prime[p]: + # Use array slicing to mark all multiples of p as not prime + is_prime[p**2 : limit + 1 : p] = False + + # Create a list of prime numbers using NumPy's where function + primes = np.where(is_prime)[0] + return primes.tolist() + +def sieve(max_n): + s = [True] * (max_n + 1) + p = 2 + while p**2 <= max_n: + if s[p]: + for i in range(p**2, max_n + 1, p): + s[i] = False + p += 1 + + primes = [p for p in range(2, max_n + 1) if s[p]] + return primes + + +def sieve_of_eratosthenes(limit): + if limit < 2: + return [] + + # Create a boolean array "prime[0..limit]" and initialize all entries as True + prime = [True] * (limit + 1) + prime[0] = prime[1] = False # 0 and 1 are not prime numbers + + p = 2 + while p**2 <= limit: + if prime[p]: + # Update all multiples of p starting from p^2 + prime[p**2 : limit + 1 : p] = [False] * len(prime[p**2 : limit + 1 : p]) + p += 1 + + # Create a list of prime numbers + primes = [p for p in range(2, limit + 1) if prime[p]] + return primes + + +class Primes: + primes = sieve(25_000_000) + + @staticmethod + def stream(): + yield from Primes.primes diff --git a/recover_secret/recover_secret.py b/recover_secret/recover_secret.py new file mode 100644 index 0000000..4ee58f5 --- /dev/null +++ b/recover_secret/recover_secret.py @@ -0,0 +1,34 @@ +# https://www.codewars.com/kata/53f40dff5f9d31b813000774/train/python +# Recover a secret string from random triplets +def recoverSecret(triplets): + transposed = list(zip(*triplets)) + sets = [set(x) for x in transposed] + return sets + return (sets[0], + sets[1] - sets[0], + sets[2] - sets[1] - sets[0]) + +test_data = [[['t','u','p'], ['w','h','i'], ['t','s','u'], ['a','t','s'], ['h','a','p'], ['t','i','s'], ['w','h','s']], + [['t', 's', 'f'], ['a', 's', 'u'], ['m', 'a', 'f'], ['a', 'i', 'n'], ['s', 'u', 'n'], ['m', 'f', 'u'], ['a', 't', 'h'], ['t', 'h', 'i'], ['h', 'i', 'f'], ['m', 'h', 'f'], ['a', 'u', 'n'], ['m', 'a', 't'], ['f', 'u', 'n'], ['h', 's', 'n'], ['a', 'i', 's'], ['m', 's', 'n'], ['m', 's', 'u']], + [['t', 's', 'f'], ['a', 's', 'u'], ['m', 'a', 'f'], ['a', 'i', 'n'], ['s', 'u', 'n'], ['m', 'f', 'u'], ['a', 't', 'h'], ['t', 'h', 'i'], ['h', 'i', 'f'], ['m', 'h', 'f'], ['a', 'u', 'n'], ['m', 'a', 't'], ['f', 'u', 'n'], ['h', 's', 'n'], ['a', 'i', 's'], ['m', 's', 'n'], ['m', 's', 'u']], + [['g', 'a', 's'], ['o', 'g', 's'], ['c', 'n', 't'], ['c', 'o', 'n'], ['a', 't', 's'], ['g', 'r', 't'], ['r', 't', 's'], ['c', 'r', 'a'], ['g', 'a', 't'], ['n', 'g', 's'], ['o', 'a', 's']]] + +def main(): + # tests + triplets = [['t','u','p'], ['w','h','i'], ['t','s','u'], ['a','t','s'], ['h','a','p'], ['t','i','s'], ['w','h','s']] + res = recoverSecret(triplets) + #assert res == "whatisup" + + triplets = [['t', 's', 'f'], ['a', 's', 'u'], ['m', 'a', 'f'], ['a', 'i', 'n'], ['s', 'u', 'n'], ['m', 'f', 'u'], ['a', 't', 'h'], ['t', 'h', 'i'], ['h', 'i', 'f'], ['m', 'h', 'f'], ['a', 'u', 'n'], ['m', 'a', 't'], ['f', 'u', 'n'], ['h', 's', 'n'], ['a', 'i', 's'], ['m', 's', 'n'], ['m', 's', 'u']] + res = recoverSecret(triplets) + #assert res == "mathisfun" + + triplets = [['g', 'a', 's'], ['o', 'g', 's'], ['c', 'n', 't'], ['c', 'o', 'n'], ['a', 't', 's'], ['g', 'r', 't'], ['r', 't', 's'], ['c', 'r', 'a'], ['g', 'a', 't'], ['n', 'g', 's'], ['o', 'a', 's']] + res = recoverSecret(triplets) + #assert res == "congrats" + + + +if __name__ == "__main__": + main() + diff --git a/sum_strings/solution.py b/sum_strings/solution.py new file mode 100644 index 0000000..96ad1f3 --- /dev/null +++ b/sum_strings/solution.py @@ -0,0 +1,11 @@ +# https://www.codewars.com/kata/5324945e2ece5e1f32000370/ + +def sum_strings(s1, s2): + res = "" + carry = 0 + s1, s2 = s1.zfill(len(s2)), s2.zfill(len(s1)) + for d1, d2 in zip(s1[::-1], s2[::-1]): + carry, total = divmod(int(d1) + int(d2) + carry, 10) + res += str(total) + + return (str(carry) + res[::-1]).lstrip('0') or '0' diff --git a/sum_strings/tests.py b/sum_strings/tests.py new file mode 100644 index 0000000..bbb9875 --- /dev/null +++ b/sum_strings/tests.py @@ -0,0 +1,93 @@ +import random +import codewars_test as test +from string import digits +from solution import sum_strings + + +def rand_str_num(): + return ''.join( + random.choice(digits) + for _ in range(random.randint(0, 1000)) + ) + +def __this_is_the_sol(x, y): + out, ret = '', 0 + + for c_x, c_y in zip(x.zfill(len(y))[::-1], y.zfill(len(x))[::-1]): + ret, d = divmod(int(c_x) + int(c_y) + ret, 10) + out += str(d) + + out = f"{out}{'1' * ret}"[::-1] or '0' + return out if len(out) < 2 else out.lstrip('0') + + +@test.describe('Basic tests') +def test_examples(): + + @test.it('Example tests') + def basic_tests(): + test.assert_equals(sum_strings("1", "1"), "2") + test.assert_equals(sum_strings("123", "456"), "579") + + @test.it('Fixed tests') + def basic_test(): + test.assert_equals(sum_strings("10", "20"), "30") + test.assert_equals(sum_strings("200", "100"), "300") + + test.assert_equals(sum_strings("99", "1"), "100") + test.assert_equals(sum_strings("42", "69"), "111") + + test.assert_equals(sum_strings("2999", "302"), "3301") + test.assert_equals(sum_strings("800", "9567"), "10367") + + test.assert_equals(sum_strings("00103", "08567"), "8670") + test.assert_equals(sum_strings("0", "0"), "0") + + test.assert_equals(sum_strings("0", "5"), "5") + test.assert_equals(sum_strings("5", "0"), "5") + + test.assert_equals(sum_strings("0", ""), "0") + test.assert_equals(sum_strings("", ""), "0") + + test.assert_equals(sum_strings("9999", ""), "9999") + test.assert_equals(sum_strings("", "9999"), "9999") + + test.assert_equals(sum_strings("9999999999999999", "1"), "10000000000000000") + test.assert_equals(sum_strings("1", "9999999999999999"), "10000000000000000") + + test.assert_equals( + sum_strings( + "712569312664357328695151392", + "8100824045303269669937" + ), + "712577413488402631964821329", + ) + + test.assert_equals( + sum_strings( + "50095301248058391139327916261", + "81055900096023504197206408605" + ), + "131151201344081895336534324866" + ) + + @test.it('Random tests') + def basic_test(): + x = rand_str_num() + y = rand_str_num() + + for _ in range(100): + test.assert_equals( + sum_strings(x, y), + __this_is_the_sol(x, y) + ) + + @test.it('Is it fast enough?') + def basic_test(): + x = str(random.randint(10, 99)) * random.randint(1_000_000, 1_100_000) + y = str(random.randint(10, 99)) * random.randint(1_000_000, 1_100_000) + + test.expect( + sum_strings(x, y) == __this_is_the_sol(x, y), + "big test failed" + ) \ No newline at end of file