diff --git a/leetcode/.python-version b/leetcode/.python-version new file mode 100644 index 0000000..92536a9 --- /dev/null +++ b/leetcode/.python-version @@ -0,0 +1 @@ +3.12.0 diff --git a/leetcode/pyproject.toml b/leetcode/pyproject.toml new file mode 100644 index 0000000..93aadae --- /dev/null +++ b/leetcode/pyproject.toml @@ -0,0 +1,156 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "leetcode" +description = 'What A Mess' +readme = "README.md" +version = "0.1.0" +requires-python = ">=3.7" +license = "MIT" +keywords = [] +authors = [ + { name = "Dan Buch", email = "dan@meatballhat.com" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = [ + "ipython" +] + +[project.urls] +Documentation = "https://github.com/unknown/leetcode#readme" +Issues = "https://github.com/unknown/leetcode/issues" +Source = "https://github.com/unknown/leetcode" + +[tool.hatch.envs.default] +dependencies = [ + "coverage[toml]>=6.5", + "pytest", +] +[tool.hatch.envs.default.scripts] +test = "pytest {args:tests}" +test-cov = "coverage run -m pytest {args:tests}" +cov-report = [ + "- coverage combine", + "coverage report", +] +cov = [ + "test-cov", + "cov-report", +] + +[[tool.hatch.envs.all.matrix]] +python = ["3.7", "3.8", "3.9", "3.10", "3.11"] + +[tool.hatch.envs.lint] +detached = true +dependencies = [ + "black>=23.1.0", + "mypy>=1.0.0", + "ruff>=0.0.243", +] +[tool.hatch.envs.lint.scripts] +typing = "mypy --install-types --non-interactive {args:src/leetcode tests}" +style = [ + "ruff {args:.}", + "black --check --diff {args:.}", +] +fmt = [ + "black {args:.}", + "ruff --fix {args:.}", + "style", +] +all = [ + "style", + "typing", +] + +[tool.black] +target-version = ["py37"] +line-length = 120 +skip-string-normalization = true + +[tool.ruff] +target-version = "py37" +line-length = 120 +select = [ + "A", + "ARG", + "B", + "C", + "DTZ", + "E", + "EM", + "F", + "FBT", + "I", + "ICN", + "ISC", + "N", + "PLC", + "PLE", + "PLR", + "PLW", + "Q", + "RUF", + "S", + "T", + "TID", + "UP", + "W", + "YTT", +] +ignore = [ + # Allow non-abstract empty methods in abstract base classes + "B027", + # Allow boolean positional values in function calls, like `dict.get(... True)` + "FBT003", + # Ignore checks for possible passwords + "S105", "S106", "S107", + # Ignore complexity + "C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915", +] +unfixable = [ + # Don't touch unused imports + "F401", +] + +[tool.ruff.isort] +known-first-party = ["leetcode"] + +[tool.ruff.flake8-tidy-imports] +ban-relative-imports = "all" + +[tool.ruff.per-file-ignores] +# Tests can use magic values, assertions, and relative imports +"tests/**/*" = ["PLR2004", "S101", "TID252"] + +[tool.coverage.run] +source_pkgs = ["leetcode", "tests"] +branch = true +parallel = true +omit = [ + "src/leetcode/__about__.py", +] + +[tool.coverage.paths] +leetcode = ["src/leetcode", "*/leetcode/src/leetcode"] +tests = ["tests", "*/leetcode/tests"] + +[tool.coverage.report] +exclude_lines = [ + "no cov", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] diff --git a/leetcode/stuff.py b/leetcode/stuff.py new file mode 100644 index 0000000..90dc403 --- /dev/null +++ b/leetcode/stuff.py @@ -0,0 +1,50 @@ +import typing + + +def yep(s: str) -> bool: + return s.strip().lower().startswith("y") + + +def guess_bisect_repl(lower: int, upper: int) -> int: + mid = lower + ((upper - lower) // 2) + + if yep(input(f"is it {mid}? ")): + return mid + + if yep(input(f"higher than {mid}? ")): + return guess_bisect_repl(mid, upper) + + return guess_bisect_repl(lower, mid) + + +def find_sqrt_ish(n: int) -> int: + return int(find_bisect(0, n, gen_sqrt_check(n))) + + +def gen_sqrt_check(n: int) -> typing.Callable[[float], int]: + def check(mid: float) -> int: + mid_sq: float = mid * mid + + if mid_sq == n: + return 0 + + if mid_sq < n: + return 1 + + return -1 + + return check + + +def find_bisect(lower: float, upper: float, check: typing.Callable[[float], int]) -> float: + mid: float = lower + ((upper - lower) / 2) + + print(f"lower={lower} mid={mid} upper={upper}") + + if mid == lower or mid == upper or check(mid) == 0: + return mid + + if check(mid) == 1: + return find_bisect(mid, upper, check) + + return find_bisect(lower, mid, check) diff --git a/leetcode/test_stuff.py b/leetcode/test_stuff.py new file mode 100644 index 0000000..1820bac --- /dev/null +++ b/leetcode/test_stuff.py @@ -0,0 +1,18 @@ +import pytest + +import stuff + + +@pytest.mark.parametrize( + ("n", "expected"), + [ + (0, 0), + (1, 1), + (5, 2), + (4, 2), + (8, 2), + (9, 3), + ], +) +def test_find_sqrt_ish(n: int, expected: int): + assert stuff.find_sqrt_ish(n) == expected