"""Локальные тесты лабораторной работы 1.

Положите этот файл рядом с ноутбуком и в первой ячейке:

    from lab01_tests import test_task0

Решение — функция без аргументов: читает данные через ``input()``
и печатает ответ через ``print()``, как в контесте.

    def task0():
        n = int(input())
        print(...)

    test_task0(task0)

Внутри файла лежат только пары stdin/stdout (сжатый pickle), без эталонных решений.
"""

from __future__ import annotations

import base64
import builtins
import io
import pickle
import sys
import traceback
import zlib

try:
    from tqdm.auto import tqdm
except ImportError:  # среда первой недели может быть без tqdm
    def tqdm(iterable, **kwargs):
        return iterable

_PAYLOAD = (
    "eNqlVltvG0UUbhLbcaalQlCkSkh0QAVVCKOZ2R3v7mOu5KUElSceEOrFwgklgToR8ICUtrRFYnko"
    "WoSEQGr5BVao1dAkbn/C7A/o7+gr3zmzjte5iAdie2fO/TtnzpnNZuXXP8UJ/vs+u5BWr17utDoZ"
    "bcdU9imWio4SkaUTOhLZ3QykiZnUBamwSceNp2IdsjAohNqQMPRUkBgWFmSsFAljT5mAKVuoeqo5"
    "MLRlBEGkmFREttIxzTjHCcfEh0usQyHTyifzH3sqLlOArEqqlZDJfXFVJyPyqlEHFIwy4Shj1GNV"
    "Nw9YJDaMSgo1g/zKFrUwjkdNaqY5GhZ5Gs6zFohQUD1qN5Y/b6+z9mQsUI3mKLNmhWLFk8tffrXW"
    "6Sxfud7yAiXoc1gwFSrhv1C6fHVj3bMntUXI5AiDSZxvk+MeikEoSTC5dmV9o1MwYxGLYNR5Hb1i"
    "BPfJiKoF9Oaoas3A+IiEUJpg2ALjvjHHzXA/ocnTKS1lKGUipfZ9NWEp0bMltpTGShlgDROvklDa"
    "8hgVKZtgx7rcVm//hy74atC4IaM+CQaY0pTnoaYRlFKoFOrplFUyIC1SKliwsvQdDpmwWgZGGu7Q"
    "Yn4EB/BxC1MEt6WSqUMlGw+GU83DVOx56gbBfF0Loqr9WBRzybQt3RSYChOV6Brw+CHwFwIgNRlS"
    "XYsI3aaGYITGwQd4qtJVY8sa9UjQhzn+7qkn0E/KFqe1oAYy7K3Ef5UKg3OmhX9lN6dD9DEZhaP8"
    "S+TMcj/SNGrxf2lfCVtUIuJKvBbGcloH0eIMBkTJ6SRJpqeH53UhVnIe9+9H06Kp5UVr7dKiaCq5"
    "aIxZuohchhZVbYs2EslhR2dgNKO1np0V0VFSDRQmmJkdcbnfmCSfiaJodu5ASKWGOKfxKoAD3hk9"
    "N887o/XCB8fgfMNaOQv2/DwlNwdnCwuj8e3+HMVcrfORaAQS54S5QbcLhX3DyEYgGk0Zi4Y2kpq9"
    "YqQ/wlcgsLJh+elN6OUifVecIUe4JsFt+E2D5bTfl7NMDzcsL7rNEAs2HkLJ81nLBhjSQiNgsNZb"
    "B0VOCed0yqJNYu5YfncaP2v1gG/w0uzW4SwRDR6wps8PNp5lSsyXUBMMKIt4WhM1gOvncTCVfqMG"
    "Z/gygWWqcYzGaRRSMyioxsObbIrKzNzBxLU20uoXy6vX+N+M9kQ6sby6nrXfSavftTqra1n7Ulr5"
    "Zu3Gtaz9bToJ0Wed1tdZO115d+zEifYDvzzzy3O/vFhpYFk5SQ9ibKS19eX1661BgMg9zG+7XXy6"
    "Mr/rtvMf8k2Z38o38/v5HffY7blufg/Pvvvb9SW22/lNt+O6BOp19wuTfffE9bHu5T+5fyQpukcE"
    "9Zz7y227p+zO9RCGJDt5CnfbMOlSFufcQ/d04EWCu+W67hH0u/ktsLaQHXTug7lHUdwWNJ/AHHG2"
    "sNkh7az9IH3TZWD04eneAMcOg+7CF7Jyu1n7WbroficIrNXLbyLEFmX1M1g9lKAHU476niQEEMJV"
    "fkdSddwTRN52u1St/HbWfp6ed79RdC5QV7qnMOlT9l24/3GY44v0LdShDyXgllRQ6BI4zqTPKLYz"
    "PqFUuz+GkbDzxeq7XuEe7MdA1UPUHkfoZRsb7/8L3laUFQ=="
)

_DATA = pickle.loads(zlib.decompress(base64.b64decode(_PAYLOAD)))
_CASES = _DATA["cases"]
_KINDS = _DATA["kinds"]
_TITLES = _DATA["titles"]


def _normalize(kind: str, text: str) -> str:
    text = text.replace("\r\n", "\n").strip()
    if kind == "yesno":
        return text.upper()
    if kind == "int":
        return str(int(text))
    if kind == "int_seq":
        return " ".join(text.split())
    if kind == "word":
        return text.split()[0] if text else ""
    return text


def _invoke(fn, stdin_text: str) -> str:
    # В Jupyter ``input()`` — это обёртка ядра, она не читает ``sys.stdin``.
    # Поэтому подменяем и потоки, и имена ``input``/``print`` (builtins + globals функции).
    buf_in = io.StringIO(stdin_text if stdin_text.endswith("\n") else stdin_text + "\n")
    buf_out = io.StringIO()

    real_print = builtins.print

    def fake_input(prompt=""):
        line = buf_in.readline()
        if line == "":
            raise EOFError("EOF when reading a line")
        return line[:-1] if line.endswith("\n") else line

    def fake_print(*args, **kwargs):
        kwargs.setdefault("file", buf_out)
        return real_print(*args, **kwargs)

    patches = [
        (sys, "stdin", buf_in),
        (sys, "stdout", buf_out),
        (builtins, "input", fake_input),
        (builtins, "print", fake_print),
    ]
    g = getattr(fn, "__globals__", None)
    if isinstance(g, dict):
        patches.append((g, "input", fake_input))
        patches.append((g, "print", fake_print))

    missing = object()
    old = [(ns, key, ns.get(key, missing) if isinstance(ns, dict) else getattr(ns, key, missing))
           for ns, key, _ in patches]
    returned = None
    try:
        for ns, key, value in patches:
            if isinstance(ns, dict):
                ns[key] = value
            else:
                setattr(ns, key, value)
        try:
            returned = fn()
        except SystemExit:
            # print(...) ; exit(0) — допустимый, хоть и грубый, способ выйти
            pass
    finally:
        for ns, key, value in old:
            if value is missing:
                if isinstance(ns, dict):
                    ns.pop(key, None)
                elif hasattr(ns, key):
                    delattr(ns, key)
            elif isinstance(ns, dict):
                ns[key] = value
            else:
                setattr(ns, key, value)
    out = buf_out.getvalue()
    if not out.strip() and returned is not None:
        out = str(returned)
    return out


def _preview(text: str, limit: int = 400) -> str:
    text = text if text.endswith("\n") else text + "\n"
    if len(text) <= limit:
        return text
    return text[:limit] + "\n...\n"


def _run(task_id: str, fn) -> bool:
    if not callable(fn):
        raise TypeError("ожидалась функция без аргументов, например def task(): ...")
    cases = _CASES[task_id]
    kind = _KINDS[task_id]
    title = _TITLES[task_id]
    ok = 0
    first_fail = None
    for i, (stdin, expected) in enumerate(tqdm(cases, desc=f"task{task_id}", leave=False), start=1):
        try:
            got = _invoke(fn, stdin)
            if _normalize(kind, got) == _normalize(kind, expected):
                ok += 1
            elif first_fail is None:
                first_fail = (
                    f"WA на тесте {i}/{len(cases)}\n"
                    f"вход:\n{_preview(stdin)}"
                    f"ожидалось: {_normalize(kind, expected)!r}\n"
                    f"получено:  {_normalize(kind, got)!r}"
                )
        except Exception:
            if first_fail is None:
                first_fail = (
                    f"RE на тесте {i}/{len(cases)}\n"
                    f"вход:\n{_preview(stdin)}"
                    f"{traceback.format_exc()}"
                )
    total = len(cases)
    name = f"task{task_id} «{title}»"
    if first_fail is None:
        print(f"{name}: {ok}/{total} OK")
        return True
    print(f"{name}: {ok}/{total} не OK")
    print(first_fail)
    return False


def test_task0(fn):
    """Сумма цифр трёхзначного числа."""
    return _run('0', fn)


def test_task1(fn):
    """Високосный год."""
    return _run('1', fn)


def test_task2(fn):
    """Тип треугольника."""
    return _run('2', fn)


def test_task3(fn):
    """Список квадратов."""
    return _run('3', fn)


def test_task4(fn):
    """Банковский вклад."""
    return _run('4', fn)


def test_task5(fn):
    """Двоичный логарифм."""
    return _run('5', fn)


def test_task6(fn):
    """Количество элементов, равных максимуму."""
    return _run('6', fn)


def test_task7(fn):
    """Задача про гаишника."""
    return _run('7', fn)


def test_task8(fn):
    """Точки на плоскости."""
    return _run('8', fn)


def test_task9(fn):
    """Максимальное произведение."""
    return _run('9', fn)

test_sum_of_digits = test_task0
test_leap_year = test_task1
test_triangle_type = test_task2
test_list_of_x_square = test_task3
test_deposit = test_task4
test_rather_ln2 = test_task5
test_how_many_max = test_task6
test_policeman = test_task7
test_count_the_points = test_task8
test_max_product = test_task9

__all__ = ["test_task0", "test_task1", "test_task2", "test_task3", "test_task4", "test_task5", "test_task6", "test_task7", "test_task8", "test_task9"]
