<file_sep>"""
Tests for somebody algo (pytest)
"""
import pytest
import algo


@pytest.mark.parametrize(
    "input_number, expected_number",
    [
        (1, 1),
        (+100, 100),
        (2048, 2048),
        ("8", 8),
        ("101", 101),
        ("1024", 1024),
        (" 56", 56),
        ("   +78     ", 78),
        ("+13   ", 13),
    ],
)
def test_task_with_one_int_validation_parameter_validate_data_right(input_number, expected_number):
    """
    Testing base class with validation method for correct number answer
    """
    assert algo.TaskWithOneIntValidationParameter.validate_data(input_number) == expected_number


@pytest.mark.parametrize(
    "input_number, expected_exception",
    [
        ("five", TypeError),
        (13.8, TypeError),
        (2 + 3j, TypeError),
        ("2+3j", TypeError),
        ("", TypeError),
        (None, TypeError),
        (-60, ValueError),
        ("  -12  ", ValueError),
        ("-1001", ValueError),
    ],
)
def test_task_with_one_int_validation_parameter_validate_data_exception(input_number, expected_exception):
    """
    Testing base class with validation method for exceptions
    """
    with pytest.raises(expected_exception):
        algo.TaskWithOneIntValidationParameter.validate_data(input_number)


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, "NO"),
        (6, "YES"),
        (19, "YES"),
        (4, "NO"),
        (15, "NO"),
        (73, "YES"),
    ],
)
def test_task88a_main_logic(number, expected_value):
    """
    Testing task 88a class main logic ( input number n, we should check, if 3 is in n^2 number)
    """
    assert algo.Task88a.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (4, 4),
        (123, 321),
        (45678, 87654),
        (100, 1),
        (2130000, 312),
    ],
)
def test_task88b_main_logic(number, expected_value):
    """
    Testing task 88b class main logic ( input number n, we should revert it)
    """
    assert algo.Task88b.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, 1),
        (4, 4),
        (234, 432),
        (1646, 6641),
        (333, 333),
        (3093, 3093),
        (264537, 764532),
        (12, 21),
        (1435, 5431),
    ],
)
def test_task88c(input_value, expected_value):
    """
    Testing task 88c class main logic (Swap the first and last digits of n)
    """
    assert algo.Task88c.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, 111),
        (4, 141),
        (234, 12341),
        (1646, 116461),
        (333, 13331),
        (3093, 130931),
        (264537, 12645371),
        (12, 1121),
        (1435, 114351),
    ],
)
def test_task88d(input_value, expected_value):
    """
    Testing task 88d class main logic (Add the number 1 to the beginning and end of n)
    """
    assert algo.Task88d.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, [1, 0, 0, 0]),
        (4, [2, 0, 0, 0]),
        (234, [15, 3, 0, 0]),
        (1646, [40, 6, 3, 1]),
        (2141, [46, 5, 0, 0]),
        (2137, [46, 4, 2, 1]),
        (2149, [46, 5, 2, 2]),
        (12412, [111, 9, 3, 1]),
        (90475, [300, 21, 5, 3]),
    ],
)
def test_task332(input_value, expected_value):
    """
    Testing task 332 class main logic (Find non-negative x1, x2, x3, x4 such that x1^2 + x2^2 + x3^2 + x4^2 = n)
    """
    assert algo.Task332.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "number, quantity, expected_value",
    [
        ("49850", 2, 5),
        ("14", 2, 5),
        ("548736", 4, 24),
        ("5870", 1, 0),
        ("247845225", 1, 5),
        ("558062862", 5, 24),
    ],
)
def test_task87_main_logic(number, quantity, expected_value):
    """
    Testing task 87 class main logic
    """
    assert algo.Task87.main_logic(number, quantity) == expected_value


@pytest.mark.parametrize(
    "number1, number2, expected_value",
    [
        (10, 3, []),
        (6, 15, [30, 60]),
        (250, 110, [2750, 5500, 8250, 11000, 13750, 16500, 19250, 22000, 24750]),
    ],
)
def test_task226_main_logic(number1, number2, expected_value):
    """
    Testing task 226 class main logic
    """
    assert algo.Task226.main_logic(number1, number2) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (126, [3, 7, 31]),
        (128, [3, 7, 31, 127]),
        (1, []),
        (8, [3, 7]),
        (8000, [3, 7, 31, 127]),
        (13172, [3, 7, 31, 127, 8191]),
    ],
)
def test_task559_main_logic(number, expected_value):
    """
    Testing task 559 class main logic
    """
    assert algo.Task559.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, 0),
        (3, 0),
        (4, 0),
        (16, 1),
        (17, 2),
        (45, 2),
        (64, 2),
        (65, 3),
        (100, 3),
        (256, 3),
        (257, 4),
    ],
)
def test_task107_main_logic(input_value, expected_value):
    """
    Testing task 107 class main logic (must return  the largest integer k, at which 4 ^k < m)
    """
    assert algo.Task107.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (24, ()),
        (104, (10, 2)),
        (328, (18, 2)),
        (611, ()),
        (1920, ()),
        (2311, ()),
        (9945, (99, 12)),
        (41410, (197, 51)),
    ],
)
def test_task243a_main_logic(number, expected_value):
    """
    Testing task 243a class main logic (must return True if there are two numbers (x, y) that x ^2 + y ^2 = n)
    """
    assert algo.Task243a.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (24, []),
        (104, [(10, 2)]),
        (328, [(18, 2)]),
        (611, []),
        (2000, [(44, 8), (40, 20)]),
        (2311, []),
        (9945, [(99, 12), (96, 27), (93, 36), (72, 69)]),
        (41410, [(197, 51), (183, 89), (181, 93), (159, 127)]),
    ],
)
def test_task243b_main_logic(number, expected_value):
    """
    Testing task 243a class main logic (must return True if there are two numbers (x, y) that x ^2 + y ^2 = n)
    """
    assert algo.Task243b.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (5, 8),
        (16, 32),
        (1, 2),
        (65, 128),
        (8, 16),
        (55, 64),
        (256, 512),
        (1000, 1024),
        (13, 16),
        (2, 4),
    ],
)
def test_task108(input_value, expected_value):
    """
    Testing task 108 class main logic
    (must return the least number, that is bigger than n and is degree of number 2)
    """
    assert algo.Task108.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (20, []),
        (3, ["1^2 + 1^2 + 1^2"]),
        (26, ["1^2 + 3^2 + 4^2"]),
        (1, []),
        (42, ["1^2 + 4^2 + 5^2"]),
        (4, []),
        (7, []),
        (9, ["1^2 + 2^2 + 2^2"]),
        (6, ["1^2 + 1^2 + 2^2"]),
        (5, []),
    ],
)
def test_task331a(input_value, expected_value):
    """
    Testing task 331a class main logic
    (must return number as a sum of 3 squared numbers)
    """
    assert algo.Task331a.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (
            50,
            [
                "3^2 + 4^2 + 5^2",
                "3^2 + 5^2 + 4^2",
                "4^2 + 3^2 + 5^2",
                "4^2 + 5^2 + 3^2",
                "5^2 + 3^2 + 4^2",
                "5^2 + 4^2 + 3^2",
            ],
        ),
        (
            45,
            [
                "2^2 + 4^2 + 5^2",
                "2^2 + 5^2 + 4^2",
                "4^2 + 2^2 + 5^2",
                "4^2 + 5^2 + 2^2",
                "5^2 + 2^2 + 4^2",
                "5^2 + 4^2 + 2^2",
            ],
        ),
        (9, ["1^2 + 2^2 + 2^2", "2^2 + 1^2 + 2^2", "2^2 + 2^2 + 1^2"]),
        (5, []),
        (1, []),
    ],
)
def test_task331b(input_value, expected_value):
    """
    Testing task 331b class main logic
    (must return number as all of combinations of sums of 3 squared numbers)
    """
    assert algo.Task331b.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([9, 12, 3], 0),
        ([18, 3, 17], 1),
        ([18, 3, 17, 78], 2),
        ([18, 3, 17, 0], 1),
        ([17, 17, 17, 17], 0),
    ],
)
def test_task178d(input_value, expected_value):
    """
    Testing task 178d class main logic
    (find amount of elements, which satisfy the condition\nAk < (Ak-1 + Ak+1) / 2.)
    """
    assert algo.Task178d.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([12, 45, 3, 19], 1),
        ([2, 4, 6, 8, 21, 34], 0),
        ([1, 45], 0),
        ([2, 2, 2], 0),
    ],
)
def test_task178e(input_value, expected_value):
    """
    Testing task 178e class main logic (find amount of elements, which satisfy the condition\n2**k < Ak < k!)
    """
    assert algo.Task178e.main_logic(input_value) == expected_value


@pytest.mark.parametrize("input_value, expected_value",
                         [
                             (1, [1, '\n']),
                             (2, [1, '\n', 1, 1, '\n', ]),
                             (4, [1, '\n', 1, 1, '\n', 1, 2,
                                  1, '\n', 1, 3, 3, 1, '\n', ]),
                             (6, [1, '\n', 1, 1, '\n', 1, 2, 1, '\n', 1, 3, 3, 1,
                                  '\n', 1, 4, 6, 4, 1, '\n', 1, 5, 10, 10, 5, 1, '\n', ]),
                         ])
def test_task555(input_value, expected_value):
    """
    Testing task 555 class main logic (build first n rows of Pascal's triangle)
    """
    assert list(algo.Task555.main_logic(input_value)) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([3, 6, 9, 12], 4),
        ([9, 15, 21, 33], 3),
        ([1, 45], 0),
        ([15, 2, 4], 0),
    ],
)
def test_task178b(input_value, expected_value):
    """
    Testing task 178b class main logic (Find numbers which are multiples of 3 and not multiples of 5)
    """
    assert algo.Task178b.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([4, 4, 4, 4], 4),
        ([16, 36], 2),
        ([1, 3], 0),
        ([16, 13, 4], 2),
    ],
)
def test_task178c(input_value, expected_value):
    """
    Testing task 178c class main logic (Find numbers which are squares of even numbers)
    """
    assert algo.Task178c.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (
            10,
            [
                [3, 4, 5],
                [6, 8, 10],
            ],
        ),
        (6, [[3, 4, 5]]),
        (11, [[3, 4, 5], [6, 8, 10]]),
        (2, []),
    ],
)
def test_task554(input_value, expected_value):
    """
    Testing task 554 class main logic (return list of pythagorean triplets)
    """
    assert algo.Task554.main_logic(input_value + 1) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [(15, 2), (441, 3), (9, 1), (123456798, 9), (15263, 5), (10526374859632104512, 20)],
)
def test_task86a_main_logic(number, expected_value):
    """
    Testing task 86a class main logic (must return  amount of digits in number)
    """
    assert algo.Task86a.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (15, 6),
        (441, 9),
        (9, 9),
        (123456798, 45),
        (15263, 17),
        (0, 0),
        (10000, 1),
        (11111, 5),
        (1991, 20),
    ],
)
def test_task86b_main_logic(number, expected_value):
    """
    Testing task 86b class main logic (must return sum of digits in number)
    """
    assert algo.Task86b.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (15, {1, 3, 5}),
        (441, {1, 3, 7, 9, 49, 147, 21, 63}),
        (9, {1, 3}),
        (1, {1}),
        (127, {1}),
        (254, {1, 2, 127}),
        (1000, {1, 2, 4, 5, 100, 200, 8, 10, 40, 50, 500, 20, 25, 250, 125}),
    ],
)
def test_task330_get_dividers(number, expected_value):
    """
    Testing task 330 class  dividers func (must return set of all dividers of the number expect number itself)
    """
    assert algo.Task330.get_dividers(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (15, [6]),
        (441, [6, 28]),
        (9, [6]),
        (123456, [6, 28, 496, 8128]),
        (15263, [6, 28, 496, 8128]),
        (1000, [6, 28, 496]),
    ],
)
def test_task330_main_logic(number, expected_value):
    """
    Testing task 330 main logic (must return number that's sum of dividers is equal to the number)
    """
    assert list(algo.Task330.main_logic(number)) == expected_value
<file_sep>"""
Tests for algo (pytest)
"""
import algo
import pytest


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, 1),
        (5888, 5888),
        (3, 3),
        ("0002", 2),
        ("+99999", 99999),
        ("  067 ", 67),
        (" 12", 12),
    ],
)
def test_task_with_one_int_validation_parameter_validate_data(number, expected_value):
    """
    Testing base class with validation method for correct number answer
    """

    assert algo.TaskWithOneIntValidationParameter.validate_data(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        ("1.2", TypeError),
        ("-3sdhv", TypeError),
        (0, ValueError),
        (1.2, TypeError),
        ("0o2", TypeError),
        ("-2", ValueError),
        ("-0.2", TypeError),
        ("-0", ValueError),
        ("-566", ValueError),
        (" ", TypeError),
        ("0  067 ", TypeError),
        ("+7m", TypeError),
    ],
)
def test_task_with_one_int_validation_parameter_validate_exceptions(number, expected_value):
    """
    Testing base class with validation method for exceptions
    """

    with pytest.raises(expected_value):
        algo.TaskWithOneIntValidationParameter.validate_data(number)


# Testing task 86a class main logic (must return  amount of digits in number)
@pytest.mark.parametrize("number, expected_value", [(1, 1), (5888, 4), ("567", 3), (1111111111, 10)])
def test_task86a_main_logic(number, expected_value):
    """
    Testing task 86b class main logic (must return sum of digits in number)
    """
    assert algo.Task86a.main_logic(number) == expected_value


# Testing task 86b class main logic (must return sum of digits in number)
@pytest.mark.parametrize("number, expected_value", [(1, 1), (5888, 29), ("567", 18), (1111101111, 9)])
def test_task86b_main_logic(number, expected_value):
    """
    Testing task 86b class main logic (must return sum of digits in number)
    """
    assert algo.Task86b.main_logic(number) == expected_value


# Testing task 330 class  dividers func (must return set of all dividers of the number expect number itself)
@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, {1}),
        (100, {1, 2, 4, 5, 10, 20, 25, 50}),
        (30, {1, 2, 3, 5, 6, 10, 15}),
        (47, {1}),
        (90, {1, 2, 3, 5, 6, 9, 10, 15, 18, 30, 45}),
        (198, {1, 2, 3, 6, 9, 11, 18, 22, 33, 66, 99}),
    ],
)
def test_task330_get_dividers(number, expected_value):
    assert algo.Task330.get_dividers(number) == expected_value


# Testing task 330 class main logic (must return number thats sum of dividers(from get_dividers) is equal to the number)
@pytest.mark.parametrize(
    "number, expected_value",
    [
        (10, [6]),
        (100, [6, 28]),
        (400, [6, 28]),
        (1000, [6, 28, 496]),
        (5000, [6, 28, 496]),
        (10000, [6, 28, 496, 8128]),
        (50000, [6, 28, 496, 8128]),
        (100000, [6, 28, 496, 8128]),
    ],
)
def test_task330_main_logic(number, expected_value):
    """
    Testing task 330 class  dividers func (must return set of all dividers of the number expect number itself)
    """
    assert list(algo.Task330.main_logic(number)) == expected_value


@pytest.mark.parametrize(
    "sequence, expected_value",
    [
        ([5], 0),
        ([9], 1),
        ([4, 5], 0),
        ([9, 13], 1),
        ([9, 12, 18, 21], 4),
        ([1, 5, 10, 15], 0),
    ],
)
def test_task178b_main_logic(sequence, expected_value):
    """
    Testing task 178b class main logic
    (must find the least number, that is bigger than n and is degree of number 2)
    """
    assert algo.Task178b.main_logic(sequence) == expected_value


@pytest.mark.parametrize(
    "sequence, expected_value",
    [
        ([5], 0),
        ([100], 1),
        ([4, 5], 1),
        ([9, 13], 0),
        ([4, 16, 36, 64], 4),
        ([1, 2, 10, 15], 0),
    ],
)
def test_task178c_main_logic(sequence, expected_value):
    """
    Testing task 178c class main logic
    (must return amount of numbers which are the square of the even number)
    """
    assert algo.Task178c.main_logic(sequence) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([18, 3, 17], 1),
        ([9, 12, 3], 0),
        ([12, 13, 13, 14], 1),
        ([16, 16, 16, 16], 0),
    ],
)
def test_task178d(input_value, expected_value):
    """
    Testing task 178d class main logic
    (find amount of elements, which satisfy the condition\nAk < (Ak-1 + Ak+1) / 2.)
    """
    assert algo.Task178d.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        ([22, 33, 13, 19], 1),
        ([3, 6, 9, 8, 21, 37], 0),
        ([40, 60], 0),
        ([8, 8, 8], 0),
    ],
)
def test_task178e(input_value, expected_value):
    """
    Testing task 178e class main logic (find amount of elements, which satisfy the condition\n2**k < Ak < k!)
    """
    assert algo.Task178e.main_logic(input_value) == expected_value


@pytest.mark.parametrize("input_value, expected_value",
                         [
                             (1, [1, '\n']),
                             (2, [1, '\n', 1, 1, '\n', ]),
                             (4, [1, '\n', 1, 1, '\n', 1, 2,
                                  1, '\n', 1, 3, 3, 1, '\n']),
                             (5, [1, '\n', 1, 1, '\n', 1, 2, 1, '\n', 1, 3, 3, 1,
                                  '\n', 1, 4, 6, 4, 1, '\n',]),
                         ])
def test_task555(input_value, expected_value):
    """
    Testing task 555 class main logic (build first n rows of Pascal's triangle)
    """
    assert list(algo.Task555.main_logic(input_value)) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (
            20,
            [
                [3, 4, 5],
                [6, 8, 10],
                [9, 12, 15],
                [12, 16, 20],
                [5, 12, 13],
                [8, 15, 17],
            ],
        ),
        (5, [[3, 4, 5]]),
        (10, [[3, 4, 5], [6, 8, 10]]),
        (1, []),
    ],
)
def test_task554_main_logic(number, expected_value):
    """
    Testing task 554 class main logic
    (must return list of pythagorean triplets)
    """
    assert algo.Task554.main_logic(number + 1) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, 0),
        (2, 0),
        (15, 1),
        (16, 1),
        (17, 2),
        (32, 2),
        (64, 2),
        (65, 3),
        (72, 3),
        (128, 3),
        (256, 3),
        (257, 4),
        (4000, 5),
        (10_000, 6),
    ],
)
def test_task107_main_logic(number, expected_value):
    """
    Testing task 107 class main logic (must return  the largest integer k, at which 4 ^k < m)
    """
    assert algo.Task107.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, ()),
        (7, ()),
        (13, (3, 2)),
        (272, (16, 4)),
        (317, (14, 11)),
        (300, ()),
        (6340, (78, 16)),
        (41410, (197, 51)),
        (67, ()),
        (32187, ()),
    ],
)
def test_task243a_main_logic(number, expected_value):
    """
    Testing task 243a class main logic (must return True if there are two numbers (x, y) that x ^2 + y ^2 = n)
    """
    assert algo.Task243a.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (1, []),
        (7, []),
        (13, [(3, 2)]),
        (272, [(16, 4)]),
        (317, [(14, 11)]),
        (300, []),
        (6340, [(78, 16), (72, 34)]),
        (41410, [(197, 51), (183, 89), (181, 93), (159, 127)]),
        (100000, [(316, 12), (300, 100), (260, 180)]),
        (
            1000000000,
            [
                (31600, 1200),
                (30672, 7696),
                (30000, 10000),
                (26000, 18000),
                (24560, 19920),
            ],
        ),
    ],
)
def test_task243b_main_logic(number, expected_value):
    """
    Testing task 243a class main logic (must return True if there are two numbers (x, y) that x ^2 + y ^2 = n)
    """
    assert algo.Task243b.main_logic(number) == expected_value


# Testing task 108 class main logic ( must return the least number, that is bigger than n and is degree of number 2)
@pytest.mark.parametrize("number, expected_value", [(2, 4), (123, 128), (1034, 2048), (100020, 131072)])
def test_task108_main_logic(number, expected_value):
    """
    Testing task 108 class main logic ( must return the least number,
    that is bigger than n and is degree of number 2)
    :param: int
    :return: int
    """
    assert algo.Task108.main_logic(number) == expected_value


# Testing task 331a class main logic ( must return the sum of 3 integers in power 2, that is equal to n)
@pytest.mark.parametrize(
    "number, expected_value",
    [(19, ["1^2 + 3^2 + 3^2"]), (20, []), (75, ["1^2 + 5^2 + 7^2"]), (4, [])],
)
def test_task331a_main_logic(number, expected_value):
    """
    Testing task 331a class main logic ( must return the sum of 3 integers in power 2,
    that is equal to n)
    :param: int
    :return: list
    """
    assert algo.Task331a.main_logic(number) == expected_value


# Testing task 331b class main logic ( must return the array of sums of 3 integers in power 2, that is equal to n)
@pytest.mark.parametrize(
    "number, expected_value",
    [
        (19, ["1^2 + 3^2 + 3^2", "3^2 + 1^2 + 3^2", "3^2 + 3^2 + 1^2"]),
        (20, []),
        (
            75,
            [
                "1^2 + 5^2 + 7^2",
                "1^2 + 7^2 + 5^2",
                "5^2 + 1^2 + 7^2",
                "5^2 + 5^2 + 5^2",
                "5^2 + 7^2 + 1^2",
                "7^2 + 1^2 + 5^2",
                "7^2 + 5^2 + 1^2",
            ],
        ),
        (4, []),
    ],
)
def test_task331b_main_logic(number, expected_value):
    """
    Testing task 331b class main logic ( must return the array of sums of 3 integers in power 2,
    that is equal to n)
    :param: int
    :return: list
    """
    assert algo.Task331b.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "data, expected_value",
    [
        ("1.2", ValueError),
        ("-3ssss", ValueError),
        ("0", ValueError),
        ("445", ValueError),
        ("7m 456", TypeError),
        ("7115m 4", TypeError),
        ("124 4d56", TypeError),
        ("7,5555 456", TypeError),
        ("7 456", algo.InvalidInput),
        ("44894 10", algo.InvalidInput),
        ("5555 5", algo.InvalidInput),
    ],
)
def test_task_with_two_int_validation_parameters_validate_exceptions_task87(data, expected_value):
    """
    Testing base class with validation method for exceptions
    """

    with pytest.raises(expected_value):
        algo.Task87.validate_data(data)


@pytest.mark.parametrize(
    "number, quantity, expected_value",
    [
        ("78451", 2, 6),
        ("421", 3, 7),
        ("1234567890", 10, 45),
        ("52138", 4, 14),
        ("17", 2, 8),
        ("32", 1, 2),
    ],
)
def test_task87_main_logic(number, quantity, expected_value):
    """
    Testing task 87 class main logic
    """
    assert algo.Task87.main_logic(number, quantity) == expected_value


@pytest.mark.parametrize(
    "data, expected_value",
    [
        ("1.2", ValueError),
        ("-3ssss", ValueError),
        ("0", ValueError),
        ("445", ValueError),
        ("7m 456", TypeError),
        ("7115m 4", TypeError),
        ("124 4d56", TypeError),
        ("7,5555 456", TypeError),
    ],
)
def test_task_with_two_int_validation_parameters_validate_exceptions_task226(data, expected_value):
    """
    Testing base class with validation method for exceptions
    """

    with pytest.raises(expected_value):
        algo.TaskWithTwoIntValidationParameters.validate_data(data)


@pytest.mark.parametrize(
    "number1, number2, expected_value",
    [
        (12, 36, [36, 72, 108, 144, 180, 216, 252, 288, 324, 360, 396]),
        (78, 5, []),
        (78, 12, [156, 312, 468, 624, 780]),
        (444, 822, [60828, 121656, 182484, 243312, 304140]),
        (77, 127, []),
    ],
)
def test_task226_main_logic(number1, number2, expected_value):
    """
    Testing task 226 class main logic
    """
    assert algo.Task226.main_logic(number1, number2) == expected_value


@pytest.mark.parametrize(
    "data, expected_value",
    [
        ("1.2", TypeError),
        ("lol", TypeError),
        (1.2, TypeError),
        ("40o", TypeError),
        ("-2", ValueError),
        ("-0.2", TypeError),
        ("-0", ValueError),
        ("-566", ValueError),
        (" ", TypeError),
        ("0  02223 ", TypeError),
        ("+777m", TypeError),
    ],
)
def test_task_with_two_int_validation_parameters_validate_exceptions_task559(data, expected_value):
    """
    Testing base class with validation method for exceptions
    """
    with pytest.raises(expected_value):
        algo.TaskWithOneIntValidationParameter.validate_data(data)


# Testing eratosthenes function in task 559
@pytest.mark.parametrize(
    "number, expected_value",
    [
        (24, [2, 3, 5, 7, 11, 13, 17, 19, 23]),
        (50, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]),
        (62, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61]),
        (88, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83]),
    ],
)
def test_task559_eratosthenes(number, expected_value):
    """
    Testing eratosthenes function in task 559
    """
    assert algo.Task559.eratosthenes(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (24, [3, 7, 15]),
        (50, [3, 7, 15, 31]),
        (61, [3, 7, 15, 31]),
        (88, [3, 7, 15, 31, 63]),
        (7700, [3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095]),
    ],
)
def test_task559_mersen_number(number, expected_value):
    """
    Testing mersen_numbers function in task 559
    """
    assert algo.Task559.mersen_numbers(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [
        (456, [3, 7, 31, 127]),
        (1234, [3, 7, 31, 127]),
        (2, []),
        (100000, [3, 7, 31, 127, 8191]),
        (748452, [3, 7, 31, 127, 8191, 131071, 524287]),
        (12, [3, 7]),
        (6, [3]),
    ],
)
def test_task559_main_logic(number, expected_value):
    """
    Testing task 559 class main logic
    """
    assert algo.Task559.main_logic(number) == expected_value


@pytest.mark.parametrize("number, expected_value", [(3, "NO"), (6, "YES"), (18, "YES"), (13, "NO")])
def test_task88a_main_logic(number, expected_value):
    """
    Testing task 88a class main logic ( input number n, we should check, if 3 is in n^2 number)
    """
    assert algo.Task88a.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "number, expected_value",
    [(3, 3), (121, 121), (1222, 2221), (1250, 521), (54789, 98745)],
)
def test_task88b_main_logic(number, expected_value):
    """
    Testing task 88b class main logic ( input number n, we should revert it)
    """
    assert algo.Task88b.main_logic(number) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, 1),
        (3, 3),
        (234, 432),
        (2347689, 9347682),
        (55, 55),
        (13, 31),
        (9934792443522434, 4934792443522439),
    ],
)
def test_task88c(input_value, expected_value):
    """
    Testing task 88c class main logic (Swaps the first and last digits of number)
    """
    assert algo.Task88c.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (2, 121),
        (21, 1211),
        (234, 12341),
        (73451, 1734511),
        (333, 13331),
        (293480293702432, 12934802937024321),
        (0, 101),
    ],
)
def test_task88d(input_value, expected_value):
    """
    Testing task 88d class main logic (Adds the digit 1 to the beginning and end of the number)
    """
    assert algo.Task88d.main_logic(input_value) == expected_value


@pytest.mark.parametrize(
    "input_value, expected_value",
    [
        (1, [1, 0, 0, 0]),
        (3, [1, 1, 1, 0]),
        (31, [5, 2, 1, 1]),
        (310, [17, 4, 2, 1]),
        (2137, [46, 4, 2, 1]),
        (2140, [46, 4, 2, 2]),
        (2141, [46, 5, 0, 0]),

    ],
)
def test_task332(input_value, expected_value):
    """
    Testing task 332 class main logic (Finds natural x1, x2, x3, x4 which satisfy the condition of equality:
                                                                              x1^2 + x2^2 + x3^2 + x4^2 = n)
    """
    assert algo.Task332.main_logic(input_value) == expected_value<file_sep># Lv-575.Python-project-MC
<file_sep>pytest==6.2.2
parameterized==0.8.1
pre-commit
pylint==2.7.2
<file_sep>"""
Tests for algo (unittest)
"""
import unittest
from parameterized import parameterized
import algo


class TestTaskWithOneIntValidationParameter(unittest.TestCase):
    """
    Test class for one validation parameter
    """

    @parameterized.expand(
        [
            (1, 1),
            (5888, 5888),
            (3, 3),
            ("0002", 2),
            ("+99999", 99999),
            ("  067 ", 67),
            (" 12", 12),
        ]
    )
    def test_validation(self, number, expected_value):
        """
        Testing base class with validation method for correct number answer
        """
        self.assertEqual(algo.TaskWithOneIntValidationParameter.validate_data(number), expected_value)

    @parameterized.expand(
        [
            ("1.2", TypeError),
            ("-3sdhv", TypeError),
            (0, ValueError),
            (1.2, TypeError),
            ("0o2", TypeError),
            ("-2", ValueError),
            ("-0.2", TypeError),
            ("-0", ValueError),
            ("-566", ValueError),
            (" ", TypeError),
            ("0  067 ", TypeError),
            ("+7m", TypeError),
        ]
    )
    def test_validation_exception(self, number, expected_value):
        """
        Testing base class with validation method for exceptions
        """
        self.assertRaises(expected_value, algo.TaskWithOneIntValidationParameter.validate_data, number)


class TestTask86a(unittest.TestCase):
    """
    Test class for task 86a
    """

    # Testing task 86a class main logic (must return  amount of digits in number)
    @parameterized.expand([(1, 1), (5888, 4), ("567", 3), (1111111111, 10)])
    def test_main_logic(self, number, expected_value):
        """
        Testing task 86a class main logic (must return  amount of digits in number)
        """
        self.assertEqual(algo.Task86a.main_logic(number), expected_value)


class TestTask86b(unittest.TestCase):
    """
    Test class for task 86b
    """

    # Testing task 86b class main logic (must return sum of digits in number)
    @parameterized.expand([(1, 1), (5888, 29), ("567", 18), (1111011111, 9)])
    def test_main_logic(self, number, expected_value):
        """
        Testing task 86b class main logic (must return sum of digits in number)
        """
        self.assertEqual(algo.Task86b.main_logic(number), expected_value)


class TestTask330(unittest.TestCase):
    """
    Test class for task 330
    """

    # Testing task 330 class  deviders func (must return set of all deviders of the number excpet number itself)
    @parameterized.expand(
        [
            (1, {1}),
            (100, {1, 2, 4, 5, 10, 20, 25, 50}),
            (30, {1, 2, 3, 5, 6, 10, 15}),
            (47, {1}),
            (90, {1, 2, 3, 5, 6, 9, 10, 15, 18, 30, 45}),
            (198, {1, 2, 3, 6, 9, 11, 18, 22, 33, 66, 99}),
        ],
    )
    def test_get_dividers(self, number, expected_value):
        """
        Testing task 330 class  dividers func (must return set of all dividers of the number except number itself)
        """
        self.assertEqual(algo.Task330.get_dividers(number), expected_value)

    # Testing task 330 class main logic (must return number that's sum of dividers is equal to the number)
    @parameterized.expand(
        [
            (10, [6]),
            (100, [6, 28]),
            (400, [6, 28]),
            (1000, [6, 28, 496]),
            (5000, [6, 28, 496]),
            (10000, [6, 28, 496, 8128]),
            (50000, [6, 28, 496, 8128]),
            (100000, [6, 28, 496, 8128]),
        ],
    )
    def test_main_logic(self, number, expected_value):
        self.assertEqual(list(algo.Task330.main_logic(number)), expected_value)


class TestTask178b(unittest.TestCase):
    """
    Test class for task 178b
    """

    @parameterized.expand(
        [
            ([5], 0),
            ([9], 1),
            ([4, 5], 0),
            ([9, 13], 1),
            ([9, 12, 18, 21], 4),
            ([1, 5, 10, 15], 0),
        ]
    )
    def test_main_logic(self, sequence, expected_value):
        """
        Testing task 178b class main logic
        (must return amount of numbers divided by 3 and not divided by 5 in a sequence)
        """
        self.assertEqual(algo.Task178b.main_logic(sequence), expected_value)


class TestTask178c(unittest.TestCase):
    """Test class for task 178b"""

    @parameterized.expand(
        [
            ([5], 0),
            ([100], 1),
            ([4, 5], 1),
            ([9, 13], 0),
            ([4, 16, 36, 64], 4),
            ([1, 2, 10, 15], 0),
        ]
    )
    def test_main_logic(self, sequence, expected_value):
        """
        Testing task 178c class main logic
        (must return amount of numbers which are the square of the even number)
        """
        self.assertEqual(algo.Task178c.main_logic(sequence), expected_value)


class TestTask554(unittest.TestCase):
    """
    Test class for task 178b
    """

    @parameterized.expand(
        [
            (
                20,
                [
                    [3, 4, 5],
                    [6, 8, 10],
                    [9, 12, 15],
                    [12, 16, 20],
                    [5, 12, 13],
                    [8, 15, 17],
                ],
            ),
            (5, [[3, 4, 5]]),
            (10, [[3, 4, 5], [6, 8, 10]]),
            (1, []),
        ]
    )
    def test_main_logic(self, number, expected_value):
        """
        Testing task 554 class main logic
        (must return list of pythagorean triplets)
        """
        self.assertEqual(algo.Task554.main_logic(number + 1), expected_value)


class TestTask178d(unittest.TestCase):
    """
    Testing task class 178d
    """

    @parameterized.expand(
        [([18, 3, 17], 1), ([9, 12, 3], 0), ([12, 13, 13, 14], 1), ([16, 16, 16, 16], 0)]
    )
    def test_task178d(self, input_value, expected_value):
        """
        Testing task 178d class main logic
        (find amount of elements, which satisfy the condition\nAk < (Ak-1 + Ak+1) / 2.)
        """
        self.assertEqual(algo.Task178d.main_logic(input_value), expected_value)


class TestTask178e(unittest.TestCase):
    """
    Testing task class 178e
    """

    @parameterized.expand(
        [
            ([22, 33, 13, 19], 1),
            ([3, 6, 9, 8, 21, 37], 0),
            ([40, 60], 0),
            ([8, 8, 8], 0),
        ]
    )
    def test_task178e(self, input_value, expected_value):
        """
        Testing task 178e class main logic (find amount of elements, which satisfy the condition\n2**k < Ak < k!)
        """
        self.assertEqual(algo.Task178e.main_logic(input_value), expected_value)


class TestTask555(unittest.TestCase):
    """
    Testing task class 555
    """

    @parameterized.expand([
        (1, [1, '\n']),
        (2, [1, '\n', 1, 1, '\n', ]),
        (4, [1, '\n', 1, 1, '\n', 1, 2,
             1, '\n', 1, 3, 3, 1, '\n']),
        (5, [1, '\n', 1, 1, '\n', 1, 2, 1, '\n', 1, 3, 3, 1,
             '\n', 1, 4, 6, 4, 1, '\n',]),
    ])
    def test_task555(self, input_value, expected_value):
        """
        Testing task 555 class main logic (build first n rows of Pascal's triangle)
        """
        self.assertEqual([*algo.Task555.main_logic(input_value)], expected_value)


class TestTask107(unittest.TestCase):
    """
    Testing task 107 class main logic
    """

    @parameterized.expand(
        [
            (1, 0),
            (2, 0),
            (15, 1),
            (16, 1),
            (17, 2),
            (32, 2),
            (64, 2),
            (65, 3),
            (72, 3),
            (128, 3),
            (256, 3),
            (257, 4),
            (4000, 5),
            (10_000, 6),
        ]
    )
    def test_main_logic(self, number, expected_value):
        """
        Must return  the largest integer k, at which 4 ^k < m
        """
        self.assertEqual(algo.Task107.main_logic(number), expected_value)


class TestTask243a(unittest.TestCase):
    """
    Testing task 243a class main logic
    """

    @parameterized.expand(
        [
            (1, ()),
            (7, ()),
            (13, (3, 2)),
            (272, (16, 4)),
            (317, (14, 11)),
            (300, ()),
            (6340, (78, 16)),
            (41410, (197, 51)),
            (67, ()),
            (32187, ()),
        ]
    )
    def test_main_logic(self, number, expected_value):
        """
        Must return True if there are two numbers (x, y) that x ^2 + y ^2 = n
        """
        self.assertEqual(algo.Task243a.main_logic(number), expected_value)


class TestTask243b(unittest.TestCase):
    """
    Testing task 243b class main logic
    """

    @parameterized.expand(
        [
            (1, []),
            (7, []),
            (13, [(3, 2)]),
            (272, [(16, 4)]),
            (317, [(14, 11)]),
            (300, []),
            (6340, [(78, 16), (72, 34)]),
            (41410, [(197, 51), (183, 89), (181, 93), (159, 127)]),
            (100000, [(316, 12), (300, 100), (260, 180)]),
            (
                1000000000,
                [
                    (31600, 1200),
                    (30672, 7696),
                    (30000, 10000),
                    (26000, 18000),
                    (24560, 19920),
                ],
            ),
        ]
    )
    def test_task243b_main_logic(self, number, expected_value):
        """
        Must return all of the two numbers (x, y) that x ^2 + y ^2 = n
        """
        self.assertEqual(algo.Task243b.main_logic(number), expected_value)


class TestTask108(unittest.TestCase):
    """
    Testing task 108
    """
    @parameterized.expand([(2, 4), (123, 128), (1034, 2048), (100020, 131072)])
    def test_task108_main_logic(self, number, expected_value):
        """
        Testing task 108 class main logic ( must return the least number, that is bigger than n and is degree of number 2)
        :param: int
        :return: int
        """
        self.assertEqual(algo.Task108.main_logic(number), expected_value)


class TestTask331a(unittest.TestCase):
    """
    Testing task 331a
    """
    @parameterized.expand([(19, ["1^2 + 3^2 + 3^2"]), (20, []), (75, ["1^2 + 5^2 + 7^2"]), (4, [])])
    def test_task331a_main_logic(self, number, expected_value):
        """
        Testing task 331a class main logic ( must return the sum of 3 integers in power 2, that is equal to n)
        :param int
        :return: list
        """
        self.assertEqual(algo.Task331a.main_logic(number), expected_value)


class TestTask331b(unittest.TestCase):
    """
    Testing task 331b
    """
    @parameterized.expand(
        [
            (19, ["1^2 + 3^2 + 3^2", "3^2 + 1^2 + 3^2", "3^2 + 3^2 + 1^2"]),
            (20, []),
                (
                75,
                [
                    "1^2 + 5^2 + 7^2",
                    "1^2 + 7^2 + 5^2",
                    "5^2 + 1^2 + 7^2",
                    "5^2 + 5^2 + 5^2",
                    "5^2 + 7^2 + 1^2",
                    "7^2 + 1^2 + 5^2",
                    "7^2 + 5^2 + 1^2",
                ],
            ),
            (4, []),
        ]
    )
    def test_task331b_main_logic(self, number, expected_value):
        """
        Testing task 331b class main logic ( must return the array of sums of 3 integers in power 2,
        that is equal to n)
        :param int
        :return: list
        """
        self.assertEqual(algo.Task331b.main_logic(number), expected_value)


class TestTask87(unittest.TestCase):
    """
    Testing all methods of task 87 class
    """

    @parameterized.expand(
        [
            ("1.2", ValueError),
            ("-3ssss", ValueError),
            ("0", ValueError),
            ("445", ValueError),
            ("7m 456", TypeError),
            ("7115m 4", TypeError),
            ("124 4d56", TypeError),
            ("7,5555 456", TypeError),
            ("7 456", algo.InvalidInput),
            ("44894 10", algo.InvalidInput),
            ("5555 5", algo.InvalidInput),
        ]
    )
    def test_exceptions(self, data, expected_value):
        """
        Testing base class with validation method for exceptions
        """
        self.assertRaises(expected_value, algo.Task87.validate_data, data)

    @parameterized.expand(
        [
            ("78451", 2, 6),
            ("421", 3, 7),
            ("1234567890", 10, 45),
            ("52138", 4, 14),
            ("17", 2, 8),
            ("32", 1, 2),
        ]
    )
    def test_main_logic(self, number, quantity, expected_value):
        """
        Testing task 87 class main logic
        """
        self.assertEqual(algo.Task87.main_logic(number, quantity), expected_value)


class TestTask226(unittest.TestCase):
    """
    Testing all methods of task 226 class
    """

    @parameterized.expand(
        [
            ("1.2", ValueError),
            ("-3ssss", ValueError),
            ("0", ValueError),
            ("445", ValueError),
            ("7m 456", TypeError),
            ("7115m 4", TypeError),
            ("124 4d56", TypeError),
            ("7,5555 456", TypeError),
        ]
    )
    def test_exceptions(self, data, expected_value):
        """
        Testing base class with validation method for exceptions
        """
        self.assertRaises(expected_value, algo.TaskWithTwoIntValidationParameters.validate_data, data)

    @parameterized.expand(
        [
            (12, 36, [36, 72, 108, 144, 180, 216, 252, 288, 324, 360, 396]),
            (78, 5, []),
            (78, 12, [156, 312, 468, 624, 780]),
            (444, 822, [60828, 121656, 182484, 243312, 304140]),
            (77, 127, []),
        ]
    )
    def test_main_logic(self, number1, number2, expected_value):
        """
        Testing task 226 class main logic
        """
        self.assertEqual(algo.Task226.main_logic(number1, number2), expected_value)


class TestTask559(unittest.TestCase):
    """
    Testing all methods of task 559 class
    """

    @parameterized.expand(
        [
            ("1.2", TypeError),
            ("lol", TypeError),
            (1.2, TypeError),
            ("40o", TypeError),
            ("-2", ValueError),
            ("-0.2", TypeError),
            ("-0", ValueError),
            ("-566", ValueError),
            (" ", TypeError),
            ("0  02223 ", TypeError),
            ("+777m", TypeError),
        ]
    )
    def test_exceptions(self, number, expected_value):
        """
        Test task 559 for exceptions
        """
        self.assertRaises(expected_value, algo.TaskWithOneIntValidationParameter.validate_data, number)

    @parameterized.expand(
        [
            (24, [2, 3, 5, 7, 11, 13, 17, 19, 23]),
            (50, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]),
            (62, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61]),
            (88, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83]),
        ],
    )
    def test_eratosthenes_function(self, number, expected_value):
        """
        Testing eratosthenes function in task 559
        """
        self.assertEqual(algo.Task559.eratosthenes(number), expected_value)

    @parameterized.expand(
        [
            (24, [3, 7, 15]),
            (50, [3, 7, 15, 31]),
            (61, [3, 7, 15, 31]),
            (88, [3, 7, 15, 31, 63]),
            (7700, [3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095]),
        ],
    )
    def test_mersen_function(self, number, expected_value):
        """
        Testing mersen_numbers function in task 559
        """
        self.assertEqual(algo.Task559.mersen_numbers(number), expected_value)

    @parameterized.expand(
        [
            (456, [3, 7, 31, 127]),
            (1234, [3, 7, 31, 127]),
            (2, []),
            (100000, [3, 7, 31, 127, 8191]),
            (748452, [3, 7, 31, 127, 8191, 131071, 524287]),
            (12, [3, 7]),
            (6, [3]),
        ]
    )
    def test_main_logic(self, number, expected_value):
        """
        Testing task 559 class main logic
        """
        self.assertEqual(algo.Task559.main_logic(number), expected_value)


class TestTask88a(unittest.TestCase):
    """
    Testing all methods of task 88a class
    """
    @parameterized.expand([(3, "NO"), (6, "YES"), (18, "YES"), (13, "NO")])
    def test_task88a_main_logic(self, number, expected_value):
        """
        Testing task 88a class main logic
        """
        self.assertEqual(algo.Task88a.main_logic(number), expected_value)


class TestTask88b(unittest.TestCase):
    """
    Testing all methods of task 88b class
    """
    @parameterized.expand([(3, 3), (121, 121), (1222, 2221), (1250, 521), (54789, 98745)])
    def test_task88b_main_logic(self, number, expected_value):
        """
        Testing task 88b class main logic
        """
        self.assertEqual(algo.Task88b.main_logic(number), expected_value)


class TestTask88c(unittest.TestCase):
    """
    Testing task 88c class main logic
    """

    @parameterized.expand(
        [
            (1, 1),
            (3, 3),
            (234, 432),
            (2347689, 9347682),
            (55, 55),
            (13, 31),
            (9934792443522434, 4934792443522439),
        ],
    )
    def test_task88c(self, input_value, expected_value):
        """
        Swap the first and last digits of n
        """
        self.assertEqual(algo.Task88c.main_logic(input_value), expected_value)


class TestTask88d(unittest.TestCase):
    """
    Testing task 88d class main logic
    """

    @parameterized.expand(
        [
            (2, 121),
            (21, 1211),
            (234, 12341),
            (73451, 1734511),
            (333, 13331),
            (293480293702432, 12934802937024321),
            (0, 101),
        ],
    )
    def test_task88d(self, input_value, expected_value):
        """
        Add the number 1 to the beginning and end of n
        """
        self.assertEqual(algo.Task88d.main_logic(input_value), expected_value)


class TestTask332(unittest.TestCase):
    """
    Testing task 332 class main logic
    """

    @parameterized.expand(
        [
            (1, [1, 0, 0, 0]),
            (3, [1, 1, 1, 0]),
            (31, [5, 2, 1, 1]),
            (310, [17, 4, 2, 1]),
            (2137, [46, 4, 2, 1]),
            (2140, [46, 4, 2, 2]),
            (2141, [46, 5, 0, 0]),
        ],
    )
    def test_task332(self, input_value, expected_value):
        """
        Find non-negative x1, x2, x3, x4 such that x1^2 + x2^2 + x3^2 + x4^2 = n
        """
        self.assertEqual(algo.Task332.main_logic(input_value), expected_value)

<file_sep>"""
Tests for somebody algo (unittest)
"""
import unittest
from parameterized import parameterized
import algo


class TestTaskWithOneIntValidationParameter(unittest.TestCase):
    """
    Class for testing tasks with one int validation parameter
    """

    @parameterized.expand(
        [
            (1, 1),
            (+100, 100),
            (2048, 2048),
            ("8", 8),
            ("101", 101),
            ("1024", 1024),
            (" 56", 56),
            ("   +78     ", 78),
            ("+13   ", 13),
        ]
    )
    def test_task_with_one_int_validation_parameter_validate_data_right(self, input_number, expected_number):
        """
        Testing base class with validation method for correct number answer
        """
        self.assertEqual(algo.TaskWithOneIntValidationParameter.validate_data(input_number), expected_number)

    @parameterized.expand(
        [
            ("five", TypeError),
            (13.8, TypeError),
            (2 + 3j, TypeError),
            ("2+3j", TypeError),
            ("", TypeError),
            (None, TypeError),
            (-60, ValueError),
            ("  -12  ", ValueError),
            ("-1001", ValueError),
        ]
    )
    def test_task_with_one_int_validation_parameter_validate_data_exception(self, input_number, expected_exception):
        """
        Testing base class with validation method for exceptions
        """
        self.assertRaises(expected_exception, algo.TaskWithOneIntValidationParameter.validate_data, input_number)


class TestTask88c(unittest.TestCase):
    """
    Testing task 88c class main logic
    """

    @parameterized.expand(
        [
            (1, 1),
            (4, 4),
            (234, 432),
            (1646, 6641),
            (333, 333),
            (3093, 3093),
            (264537, 764532),
            (12, 21),
            (1435, 5431),
        ]
    )
    def test_task88c(self, input_value, expected_value):
        """
        Swap the first and last digits of n
        """
        self.assertEqual(algo.Task88c.main_logic(input_value), expected_value)


class TestTask88d(unittest.TestCase):
    """
    Testing task 88d class main logic
    """

    @parameterized.expand(
        [
            (1, 111),
            (4, 141),
            (234, 12341),
            (1646, 116461),
            (333, 13331),
            (3093, 130931),
            (264537, 12645371),
            (12, 1121),
            (1435, 114351),
        ]
    )
    def test_task88d(self, input_value, expected_value):
        """
        Add the number 1 to the beginning and end of n
        """
        self.assertEqual(algo.Task88d.main_logic(input_value), expected_value)


class TestTask332(unittest.TestCase):
    """
    Testing task 332 class main logic
    """

    @parameterized.expand(
        [
            (1, [1, 0, 0, 0]),
            (4, [2, 0, 0, 0]),
            (234, [15, 3, 0, 0]),
            (1646, [40, 6, 3, 1]),
            (2141, [46, 5, 0, 0]),
            (2137, [46, 4, 2, 1]),
            (2149, [46, 5, 2, 2]),
            (12412, [111, 9, 3, 1]),
            (90475, [300, 21, 5, 3]),
        ]
    )
    def test_task332(self, input_value, expected_value):
        """
        Find non-negative x1, x2, x3, x4 such that x1^2 + x2^2 + x3^2 + x4^2 = n
        """
        self.assertEqual(algo.Task332.main_logic(input_value), expected_value)


class TestTask87(unittest.TestCase):
    """
    Testing task 87
    """
    @parameterized.expand(
        [("49850", 2, 5), ("14", 2, 5), ("548736", 4, 24), ("5870", 1, 0), ("247845225", 1, 5), ("558062862", 5, 24)]
    )
    def test_main_logic(self, number, quantity, expected_value):
        """
        Testing task 87 class main logic
        """
        self.assertEqual(algo.Task87.main_logic(number, quantity), expected_value)


class TestTask226(unittest.TestCase):
    """
    Testing task 226
    """
    @parameterized.expand(
        [
            (10, 3, []),
            (6, 15, [30, 60]),
            (250, 110, [2750, 5500, 8250, 11000, 13750, 16500, 19250, 22000, 24750]),
            (71, 140, []),
        ]
    )
    def test_main_logic(self, number1, number2, expected_value):
        """
        Testing task 226 class main logic
        """
        self.assertEqual(algo.Task226.main_logic(number1, number2), expected_value)


class TestTask559(unittest.TestCase):
    """
    Testing task 559
    """
    @parameterized.expand(
        [
            (126, [3, 7, 31]),
            (128, [3, 7, 31, 127]),
            (1, []),
            (8, [3, 7]),
            (8000, [3, 7, 31, 127]),
            (5, [3]),
            (13172, [3, 7, 31, 127, 8191]),
        ],
    )
    def test_main_logic(self, number, expected_value):
        """
        Testing task 559 class main logic
        """
        self.assertEqual(algo.Task559.main_logic(number), expected_value)


class TestTask107(unittest.TestCase):
    @parameterized.expand(
        [(1, 0), (3, 0), (4, 0), (16, 1), (17, 2), (45, 2), (64, 2), (65, 3), (95, 3), (100, 3), (256, 3), (257, 4)]
    )
    def test_task107(self, input_value, expected_value):
        self.assertEqual(algo.Task107.main_logic(input_value), expected_value)


class TestTask243a(unittest.TestCase):
    @parameterized.expand(
        [
            (24, ()),
            (104, (10, 2)),
            (328, (18, 2)),
            (611, ()),
            (1920, ()),
            (2311, ()),
            (9945, (99, 12)),
            (41410, (197, 51)),
        ]
    )
    def test_task243a(self, input_value, expected_value):
        self.assertEqual(algo.Task243a.main_logic(input_value), expected_value)


class TestTask243b(unittest.TestCase):
    @parameterized.expand(
        [
            (24, []),
            (104, [(10, 2)]),
            (328, [(18, 2)]),
            (611, []),
            (2000, [(44, 8), (40, 20)]),
            (2311, []),
            (9945, [(99, 12), (96, 27), (93, 36), (72, 69)]),
            (41410, [(197, 51), (183, 89), (181, 93), (159, 127)]),
        ]
    )
    def test_task243b(self, input_value, expected_value):
        self.assertEqual(algo.Task243b.main_logic(input_value), expected_value)


class TestTask108(unittest.TestCase):
    """
    Test class for task 108
    """

    @parameterized.expand(
        [(5, 8), (16, 32), (1, 2), (65, 128), (8, 16), (55, 64), (256, 512), (1000, 1024), (13, 16), (2, 4)]
    )
    def test_task108(self, input_value, expected_value):
        """
        Testing task 108 class main logic
        (must find the least number, that is bigger than n and is degree of number 2)
        """
        self.assertEqual(algo.Task108.main_logic(input_value), expected_value)


class TestTask331a(unittest.TestCase):
    """
    Test class for task 331a
    """

    @parameterized.expand(
        [
            (20, []),
            (3, ["1^2 + 1^2 + 1^2"]),
            (26, ["1^2 + 3^2 + 4^2"]),
            (1, []),
            (42, ["1^2 + 4^2 + 5^2"]),
            (4, []),
            (7, []),
            (9, ["1^2 + 2^2 + 2^2"]),
            (6, ["1^2 + 1^2 + 2^2"]),
            (5, []),
        ]
    )
    def test_task331a(self, input_value, expected_value):
        """
        Testing task 331a class main logic
        (must return number as a sum of 3 squared numbers)
        """
        self.assertEqual(algo.Task331a.main_logic(input_value), expected_value)


class TestTask331b(unittest.TestCase):
    """
    Test class for task 331b
    """

    @parameterized.expand(
        [
            (
                    50,
                    [
                        "3^2 + 4^2 + 5^2",
                        "3^2 + 5^2 + 4^2",
                        "4^2 + 3^2 + 5^2",
                        "4^2 + 5^2 + 3^2",
                        "5^2 + 3^2 + 4^2",
                        "5^2 + 4^2 + 3^2",
                    ],
            ),
            (
                    45,
                    [
                        "2^2 + 4^2 + 5^2",
                        "2^2 + 5^2 + 4^2",
                        "4^2 + 2^2 + 5^2",
                        "4^2 + 5^2 + 2^2",
                        "5^2 + 2^2 + 4^2",
                        "5^2 + 4^2 + 2^2",
                    ],
            ),
            (9, ["1^2 + 2^2 + 2^2", "2^2 + 1^2 + 2^2", "2^2 + 2^2 + 1^2"]),
            (5, []),
            (1, []),
        ]
    )
    def test_task331b(self, input_value, expected_value):
        """
        Testing task 331b class main logic
        (must return number as all of combinations of sums of 3 squared numbers)
        """
        self.assertEqual(algo.Task331b.main_logic(input_value), expected_value)


class TestTask178d(unittest.TestCase):
    """
    Testing task class 178d
    """

    @parameterized.expand(
        [([9, 12, 3], 0), ([18, 3, 17], 1), ([18, 3, 17, 78], 2), ([18, 3, 17, 0], 1), ([17, 17, 17, 17], 0)]
    )
    def test_task178d(self, input_value, expected_value):
        """
        Testing task 178d class main logic
        (find amount of elements, which satisfy the condition\nAk < (Ak-1 + Ak+1) / 2.)
        """
        self.assertEqual(algo.Task178d.main_logic(input_value), expected_value)


class TestTask178e(unittest.TestCase):
    """
    Testing task class 178e
    """

    @parameterized.expand(
        [
            ([12, 45, 3, 19], 1),
            ([2, 4, 6, 8, 21, 34], 0),
            ([1, 45], 0),
            ([2, 2, 2], 0),
        ]
    )
    def test_task178e(self, input_value, expected_value):
        """
        Testing task 178e class main logic (find amount of elements, which satisfy the condition\n2**k < Ak < k!)
        """
        self.assertEqual(algo.Task178e.main_logic(input_value), expected_value)


class TestTask555(unittest.TestCase):
    """
    Testing task class 555
    """

    @parameterized.expand([
        (1, [1, '\n']),
        (2, [1, '\n', 1, 1, '\n', ]),
        (4, [1, '\n', 1, 1, '\n', 1, 2,
             1, '\n', 1, 3, 3, 1, '\n', ]),
        (6, [1, '\n', 1, 1, '\n', 1, 2, 1, '\n', 1, 3, 3, 1,
             '\n', 1, 4, 6, 4, 1, '\n', 1, 5, 10, 10, 5, 1, '\n', ]),
    ])
    def test_task555(self, input_value, expected_value):
        """
        Testing task 555 class main logic (build first n rows of Pascal's triangle)
        """
        self.assertEqual([*algo.Task555.main_logic(input_value)], expected_value)


class TestTask178b(unittest.TestCase):
    """
    Testing task class 178e
    """

    @parameterized.expand(
        [
            ([3, 6, 9, 12], 4),
            ([9, 15, 21, 33], 3),
            ([1, 45], 0),
            ([15, 2, 4], 0),
        ]
    )
    def test_task178b(self, input_value, expected_value):
        """
        Testing task 178b class main logic (Find numbers which are multiples of 3 and not multiples of 5)
        """
        self.assertEqual(algo.Task178b.main_logic(input_value), expected_value)


class TestTask178c(unittest.TestCase):
    """
    Testing task class 178e
    """

    @parameterized.expand(
        [
            ([4, 4, 4, 4], 4),
            ([16, 36], 2),
            ([1, 3], 0),
            ([16, 13, 4], 2),
        ]
    )
    def test_task178c(self, input_value, expected_value):
        """
        Testing task 178c class main logic (Find numbers which are squares of even numbers)
        """
        self.assertEqual(algo.Task178c.main_logic(input_value), expected_value)


class TestTask554(unittest.TestCase):
    """
    Testing task class 178e
    """

    @parameterized.expand(
        [
            (
                10,
                [
                    [3, 4, 5],
                    [6, 8, 10],
                ],
            ),
            (6, [[3, 4, 5]]),
            (11, [[3, 4, 5], [6, 8, 10]]),
            (2, []),
        ],
    )
    def test_task554(self, input_value, expected_value):
        """
        Testing task 554 class main logic (return list of pythagorean triplets)
        """
        self.assertEqual(algo.Task554.main_logic(input_value + 1), expected_value)


class TestTask86a(unittest.TestCase):
    """
    Testing all methods of task 86a class
    """

    @parameterized.expand([(15, 2), (441, 3), (9, 1), (123456798, 9), (15263, 5), (10526374859632104512, 20)])
    def test_task86a(self, input_value, expected_value):
        """
        Testing task 86a class main logic (must return  amount of digits in number)
        """
        self.assertEqual(algo.Task86a.main_logic(input_value), expected_value)


class TestTask86b(unittest.TestCase):
    """
    Testing all methods of task 86b class
    """

    @parameterized.expand(
        [(15, 6), (441, 9), (9, 9), (123456798, 45), (15263, 17), (0, 0), (10000, 1), (11111, 5), (1991, 20)]
    )
    def test_task86b(self, input_value, expected_value):
        """
        Testing task 86b class main logic (must return sum of digits in number)
        """
        self.assertEqual(algo.Task86b.main_logic(input_value), expected_value)


class TestTask330(unittest.TestCase):
    """
    Testing all methods of task 330 class
    """

    @parameterized.expand(
        [
            (15, {1, 3, 5}),
            (441, {1, 3, 7, 9, 49, 147, 21, 63}),
            (9, {1, 3}),
            (1, {1}),
            (127, {1}),
            (254, {1, 2, 127}),
            (1000, {1, 2, 4, 5, 100, 200, 8, 10, 40, 50, 500, 20, 25, 250, 125}),
        ]
    )
    def test_task330_get_dividers(self, number, expected_value):
        """
        Testing task 330 class  dividers func (must return set of all dividers of the number expect number itself)
        """
        self.assertEqual(algo.Task330.get_dividers(number), expected_value)

    @parameterized.expand(
        [
            (15, [6]),
            (441, [6, 28]),
            (9, [6]),
            (123456, [6, 28, 496, 8128]),
            (15263, [6, 28, 496, 8128]),
            (1000, [6, 28, 496]),
        ]
    )
    def test_task330_main_logic(self, number, expected_value):
        """
        Testing task 330 main logic (must return number that's sum of dividers is equal to the number)
        """
        self.assertEqual(list(algo.Task330.main_logic(number)), expected_value)


class TestTask88a(unittest.TestCase):
    """
    Testing all methods of task 88a class
    """
    @parameterized.expand(
        [
            (1, "NO"),
            (6, "YES"),
            (19, "YES"),
            (4, "NO"),
            (15, "NO"),
            (73, "YES"),
        ],
    )
    def test_task88a_main_logic(self, number, expected_value):
        """
        Testing task 88a class main logic
        """
        self.assertEqual(algo.Task88a.main_logic(number), expected_value)


class TestTask88b(unittest.TestCase):
    """
    Testing all methods of task 88b class
    """
    @parameterized.expand(
        [
            (4, 4),
            (123, 321),
            (45678, 87654),
            (100, 1),
            (2130000, 312),
        ],
    )
    def test_task88b_main_logic(self, number, expected_value):
        """
        Testing task 88b class main logic
        """
        self.assertEqual(algo.Task88b.main_logic(number), expected_value)
<file_sep>"""
Entry point for algo_task program
"""
import re
from algo import TASKS

if __name__ == "__main__":

    # get all subclasses of AlgoInterface
    # and sort them as (int, str)

    tasks = sorted(
        TASKS,
        key=lambda x: (int(re.search("[0-9]+", x.name())[0]), x.name()),
    )

    # Console menu
    print("Choose task from:")
    print("\n".join("\t{}. {}".format(i, task.name()) for i, task in enumerate(tasks, 1)))

    while True:
        # handaling wrong input
        try:
            position = int(input("Execute task (index): ")) - 1
        except ValueError:
            print("Not a valid input")
            continue
        if not 0 <= position < len(tasks):
            print("Index out of range!")
            continue

        # executing algorithm

        Task_to_execute = tasks[position]()
        Task_to_execute.execute()

        # exit condition
        if input("Do you want to continue? (y-yes, ANY_KEY for exit) ").lower() != "y":
            break
<file_sep>"""
Algo tasks realisation
"""
from abc import ABC, abstractmethod, abstractstaticmethod
from math import sqrt, gcd, floor, log, ceil, factorial
from typing import List, Tuple

# List of algo tasks
TASKS = []


def register(cls):
    """
    Decorator/funtion for class-task registration (added to list TASKS)
    """
    TASKS.append(cls)
    return cls


class AlgoInterface(ABC):
    """
    Interface for algo tasks
    subclasees must be only algo tasks
    """

    @abstractmethod
    def execute(self) -> None:
        """
        implement your algo task here
        """

    @abstractstaticmethod
    def name() -> str:
        """
        return name of task
        user representation
        """

    @abstractstaticmethod
    def main_logic(*args, **kwargs):
        """
        return task's answer
        """

    @abstractstaticmethod
    def validate_data(*args, **kwargs):
        """
        Validation of input data
        """


class TaskWithOneIntValidationParameter(AlgoInterface):
    """
    Abstract class for validation data with one parameter
    """
    @classmethod
    def validate_data(cls, *args, **kwargs):
        """
        Validation of data with one parameter
        Input number must be an natural
        """
        input_number, *_ = args
        string = str(input_number).strip()
        if not ((((string.startswith("-") or string.startswith("+")) and string[1:].isdigit())) or string.isdigit()):
            raise TypeError  # raises TypeError if not int

        number = int(input_number)

        if number <= 0:
            raise ValueError  # raises ValueError if not natural
        return number


class InvalidInput(Exception):
    """
    Custom extension
    """


class TaskWithTwoIntValidationParameters(AlgoInterface):
    """
    Class for validation of two int parameters
    """

    @classmethod
    def validate_data(cls, *args, **kwargs):
        """
        Validation of data with 2 parameters
        Input numbers must be integers
        """
        input_data, *_ = args
        number, number2 = input_data.split()
        if not number.isdigit() or not number2.isdigit():
            raise TypeError

        return number, number2


@register
class Task178d(TaskWithOneIntValidationParameter):
    """
    178) Natural numbers n, a1,…, an are given.
    Define number of members ak of the sequence a1,…, an:
    d) which satisfy the condition: Ak < (Ak-1 + Ak+1) / 2.
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        sequence: list = args[0]
        result = 0
        for i in range(1, len(sequence) - 1):
            if sequence[i] < (sequence[i - 1] + sequence[i + 1]) / 2:
                result += 1
        return result

    def execute(self) -> None:
        print(self.__doc__)
        size = input("Enter the size of sequence:")
        try:
            size = self.validate_data(size)
        except ValueError:
            print("ValueError exception thrown")
            return None
        print("Enter sequence of integer numbers by one in row:")
        sequence = [int(input()) for i in range(size)]
        for i in sequence:
            try:
                i = self.validate_data(i)
            except ValueError:
                print("ValueError exception thrown")
                return None
        print("Result:", self.main_logic(sequence))

        return None

    @staticmethod
    def name() -> str:
        return "178 г)"


@register
class Task88a(TaskWithOneIntValidationParameter):
    """
    A natural number n is given. Find out whether the digit 3 is included in the record of the number n^2.
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> str:
        """
        Return YES or NO whether the digit 3 is included in the record of the number n^2.
        """
        number: int = args[0]
        if isinstance(number, int) and number > 0:
            if str(number * number).find("3") != -1:
                return "YES"
        return "NO"

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input number")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(int(number))
        print("Is 3 in n^2?", result)
        return None

    @staticmethod
    def name() -> str:
        return "88 a)"


@register
class Task178b(TaskWithOneIntValidationParameter):
    """
    178) Natural numbers n, a1,…, an are given. Define
    number of members ak of the sequence a1,…, an:
    b) multiples of 3 and not multiples of 5;
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Given natural number n and a list of n elements.
        Find numbers which are multiples of 3 and not multiples of 5
        """
        sequence: list = args[0]
        counter = 0
        for element in sequence:
            if element % 3 == 0 and element % 5 != 0:
                counter += 1
        return counter

    def execute(self) -> None:
        print(self.__doc__)
        size = input("Enter the size of sequence:")
        try:
            size = self.validate_data(size)
        except ValueError:
            print("ValueError exception thrown")
            return None
        except TypeError:
            print("TypeError exception thrown")
            return None
        print("Enter the elements of sequence:")
        sequence = [int(input()) for _ in range(size)]
        for i in sequence:
            try:
                i = self.validate_data(i)
            except ValueError:
                print("ValueError exception thrown")
                return None

        print("Result:", self.main_logic(sequence))

        return None

    @staticmethod
    def name() -> str:
        return "178 б)"


@register
class Task107(TaskWithOneIntValidationParameter):
    """
    A natural number m is given.
    Find the largest integer k such that 4 ^k < m
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Return  the largest integer k, at which 4 ^k < m
        """
        m_number: int = args[0]
        k: float = log(m_number, 4)
        k: int = int(k) if k != int(k) or k == 0 else int(k) - 1
        return k

    def execute(self) -> None:
        """
        Processes user behavior and displays results
        :return: None
        """
        print(self.__doc__)

        input_data = input("Enter m: ")

        try:
            m_number = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        k = self.main_logic(m_number)
        print("k =", k)
        print("4 ^{} < {}".format(k, m_number))

        return None

    @staticmethod
    def name() -> str:
        return "107"


@register
class Task243a(TaskWithOneIntValidationParameter):
    """
    A natural number n is given.
    Can you imagine it as a sum of two squares of natural numbers?
    If yes, find a pair x, y of such natural numbers that n = x ^2 + y ^2
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> tuple:
        """
        Check if there are two numbers (x, y) that x ^2 + y ^2 = n
        """
        n_number: int = args[0]
        n_number_square: float = sqrt(n_number)

        for y_number in range(1, int(sqrt(n_number)) + 1):
            # n = x^2 + y^2
            # x^2 = sqrt(n)^2 - y^2 = (sq + y) * (sq - y)
            x_number = sqrt((n_number_square + y_number)
                            * (n_number_square - y_number))
            if int(x_number) == x_number:
                if int(x_number) >= y_number:
                    return int(x_number), y_number

            # prevention of calculation errors
            elif abs(round(x_number) - x_number) < 0.0000000001:
                if round(x_number) >= y_number:
                    return round(x_number), y_number

        return ()

    def execute(self) -> None:
        """
        Processes user behavior and displays results
        :return: None
        """
        print(self.__doc__)

        input_data = input("Enter n: ")

        try:
            n_number = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        exists = self.main_logic(n_number)
        if exists:
            print(
                "{x1} ^2 + {x2} ^2 = {N}".format(x1=exists[0], x2=exists[1], N=n_number))
        else:
            print("This number cannot be represented as the sum of two squares")

        return None

    @staticmethod
    def name() -> str:
        return "243 а)"


@register
class Task178c(TaskWithOneIntValidationParameter):
    """
    178) Natural numbers n, a1,…, an are given. Define
    number of members ak of the sequence a1,…, an:
    c) which are squares of even numbers;
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Given natural number n and a list of n elements.
        Find numbers which are squares of even numbers.
        """
        sequence: list = args[0]
        counter = 0
        for element in sequence:
            root = sqrt(element)
            if root ** 2 == element and root % 2 == 0:
                counter += 1

        return counter

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Enter the size of sequence:")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("ValueError exception thrown")
            return None
        print("Enter the elements of sequence:")
        sequence = [int(input()) for i in range(number)]
        for i in sequence:
            try:
                i = self.validate_data(i)
            except ValueError:
                print("ValueError exception thrown")
                return None
            except TypeError:
                print("TypeError exception thrown")
                return None

        print("Result:", self.main_logic(sequence))
        return None

    @staticmethod
    def name() -> str:
        return "178 в)"


@register
class Task86a(TaskWithOneIntValidationParameter):
    """
    86. A natural number n is given.
    a) How many digits are in the number n.
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Count amount of digits in number
        :param number: int
        :return: int
        """
        number: int = args[0]
        return len(str(number))

    def execute(self) -> None:
        """
        input natural number N \n
        find amount of its digits
        """
        print(self.__doc__)
        input_data = input("Enter number: ")

        try:
            number = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        # number must be natural
        print(self.main_logic(number))

        return None

    @staticmethod
    def name() -> str:
        """
        Returns name of a class in user representation
        """
        return "86 a)"


@register
class Task554(TaskWithOneIntValidationParameter):
    """
    A natural number n is given. Get all Pythagorean
    triples of natural numbers, each of which does not exceed n, i.e.
    all triples of natural numbers a, b, c such that
    a^2 + b^2 = c^2 (a ≤ b ≤ c ≤ n).
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> list:
        """
        Finds triples less than given natural number n using Euclid's formula
        (Modified to print not only primitive triples)
        """
        num: int = args[0]
        res = []
        for m_var in range(2, ceil(sqrt(num))):
            for n_var in range(1, m_var):
                # m and n are coprime and not both odd
                if gcd(m_var, n_var) == 1 and (m_var - n_var) % 2 and (m_var ** 2 + n_var ** 2) < num:
                    a_var = m_var ** 2 - n_var ** 2
                    b_var = 2 * m_var * n_var
                    c_var = m_var ** 2 + n_var ** 2
                    if a_var > b_var:
                        a_var, b_var = b_var, a_var
                    k_var = 1
                    while k_var * c_var < num:
                        res.append(
                            [k_var * a_var, k_var * b_var, k_var * c_var])
                        k_var += 1
        return res

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Enter n: ")
        try:
            num = self.validate_data(number)
        except ValueError:
            print("ValueError exception thrown")
            return None
        except TypeError:
            print("TypeError exception thrown")
            return None
        res = self.main_logic(num + 1)
        for row in res:
            for el in row:
                print(el, end=' ')
            print()
        return None

    @staticmethod
    def name() -> str:
        return "554"


@register
class Task87(TaskWithTwoIntValidationParameters):
    """
    Given natural n, m. Get the sum of the last m digits numbers n.
    """

    @staticmethod
    def main_logic(*args, **kwargs):
        number, quantity, *_ = args
        sum_, len_of_number = 0, len(number)
        for i in range(quantity):
            sum_ += int(number[len_of_number - i - 1])
        return sum_

    @classmethod
    def validate_data(cls, *args, **kwargs):
        input_data, *_ = args
        number, quantity_str = super().validate_data(input_data)
        quantity, len_of_number = int(quantity_str), len(number)
        if quantity > len_of_number:
            raise InvalidInput

        return number, quantity_str

    def execute(self) -> None:
        """
        Combine validation data + main logic
        """
        print(self.__doc__)
        try:
            input_data = input("Enter number and m:")
            number, quantity_str = self.validate_data(input_data)
        except ValueError:
            print("Please enter the second value")
            return None
        except TypeError:
            print("You've entered not natural number")
            return None
        except InvalidInput:
            print("m must be less than number of digits number")
            return None
        # numbers must be natural
        result = self.main_logic(number, int(quantity_str))
        print(
            "The sum of the last {} digits of number {} is".format(
                int(quantity_str), number),
            result,
        )

        return None

    @staticmethod
    def name() -> str:
        return "87"


@register
class Task86b(TaskWithOneIntValidationParameter):
    """
    86. A natural number n is given.
    b) What is the sum of its numbers?
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Count sum of digits in the number
        :param number: int
        :return: int
        """
        number: int = args[0]
        return sum(map(int, list(str(number))))

    def execute(self) -> None:
        """
        input natural number N \n
        find sum of its digits
        """
        print(self.__doc__)

        input_data = input("Enter number N: ")
        try:
            number = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        # number must be natural
        print(self.main_logic(number))
        return None

    @staticmethod
    def name() -> str:
        return "86 б)"


@register
class Task330(TaskWithOneIntValidationParameter):
    """
    330. A natural number is called perfect if it is equal
    to the sum of all its divisors, except for itself.
    The number 6 is perfect, since 6 = 1 + 2 + 3.
    The number 8 is not perfect, since 8 ≠ 1 + 2 + 4.
    Given a natural number n. Get all perfect numbers less than n.
    """

    @staticmethod
    def get_dividers(numb: int) -> set[int]:
        """
        Finds all deviders of an integer except the number itself
        :param number: int
        :return: set[int]

        complexity O(sqrt(numb))
        """

        # using set to avoid duplicates of deviders
        deviders = {1}
        # starting from 2 because 1 is always devider of natural number
        for i in range(2, int(numb ** 0.5) + 2):
            if numb % i == 0:
                deviders.add(numb // i)
                deviders.add(i)
        return deviders

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Its a generator that find all numbers that is ideal
        :param number: int
        :return: int
        """
        number: int = args[0]
        for i in range(2, number):
            if sum(Task330.get_dividers(i)) == i:
                yield i

    def execute(self) -> None:
        """
        input natural number N \n
        find all "ideal" numbers that is less than N \n

        "ideal" - number the sum of witch deviders(without the number itself)
        is equal to the number
        """
        print(self.__doc__)

        number = input("Enter number N: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        # general complixity of print all "ideal" numbers till number N
        # O(n*sqrt(n)) <==> O(n^(3/2))
        for numb in self.main_logic(number):
            print(numb)

        # alternative form (cons: print all values after forloop ends)
        # print(*(i for i in range(2, number)  if sum(get_deviders(i)) == i ))

        return None

    @staticmethod
    def name() -> str:
        return "330"


@register
class Task108(TaskWithOneIntValidationParameter):
    """
    \n108. You should enter the number\nThe aim is to find the least number,
    that is bigger than n and is degree of number 2\n
    """

    # complexity - O(1)

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Return the least number, that is bigger than n and is degree of number 2
        """
        number: int = args[0]
        return int(2 ** (floor(log(number, 2)) + 1))

    def execute(self) -> None:
        """
        Input data
        """
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(number)
        print("r = ", floor(log(number, 2)) + 1)
        print("Result (2^r) = ", result)
        return None

    @staticmethod
    def name() -> str:
        return "108"


@register
class Task226(TaskWithTwoIntValidationParameters):
    """
    Natural numbers m, n are given. Get all natural common multiples less than mn.
    """

    @staticmethod
    def main_logic(*args, **kwargs):
        value1, value2, *_ = args

        def lcm(var1, var2):
            return (var1 * var2) // gcd(var1, var2)

        lcm = lcm(value1, value2)
        return list(range(lcm, value1 * value2, lcm))

    def execute(self) -> None:
        """
        Combine validation data + main logic
        """
        print(self.__doc__)
        try:
            input_data = input("Enter n and m:")
            number1, number2 = self.validate_data(input_data)
        except ValueError:
            print("Please enter the second value")
            return None
        except TypeError:
            print("You've entered not natural number")
            return None
        # numbers must be natural
        number1, number2 = int(number1), int(number2)
        result = self.main_logic(number1, number2)
        if result:
            print("All common multiples less then {}: ".format(
                number1 * number2), end="")
            for element in result:
                print(element, end=", ")
            print()
        else:
            print("There are no such values")

        return None

    @staticmethod
    def name() -> str:
        return "226"


@register
class Task178e(TaskWithOneIntValidationParameter):
    """
    178) Natural numbers n, a1,…, an are given.
    Define number of members ak of the sequence a1,…, an:
    e) which satisfy the condition: 2**k < Ak < k!"
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        sequence: list = args[0]
        result = 0
        for i in sequence:
            if 2 ** (sequence.index(i) + 1) < i and i < factorial((sequence.index(i) + 1)):
                result += 1
        return result

    def execute(self) -> None:
        print(self.__doc__)
        size = input("Enter the size of sequence: ")
        try:
            size = self.validate_data(size)
        except ValueError:
            print("ValueError exception thrown")
            return None
        print("Enter sequence of integer numbers by one in row:")
        sequence = [int(input()) for i in range(size)]
        for i in sequence:
            try:
                i = self.validate_data(i)
            except ValueError:
                print("ValueError exception thrown")
                return None
        print("Result:", self.main_logic(sequence))

        return None

    @staticmethod
    def name() -> str:
        return "178 д)"


@register
class Task559(TaskWithOneIntValidationParameter):
    """
    A natural number n is given. Find all Mersen numbers less than n.
    (A prime number is called a Mersenne number if it can be represented as 2p - 1,\
    where p is also a prime number.)
    """

    @staticmethod
    def eratosthenes(number):
        """
        Eratosthene's sieve to get primes
        """
        sieve = list(range(number + 1))
        sieve[1] = 0
        for i in sieve:
            if i > 1:
                for j in range(i + i, len(sieve), i):
                    sieve[j] = 0
        sieve.pop(number)
        sieve_without_nulls = {x for x in sieve if x != 0}

        return sorted(set(sieve_without_nulls))

    @staticmethod
    def mersen_numbers(value):
        """
        Mersenne numbers
        """
        return sorted({2 ** i - 1 for i in range(2, int(log(value + 1, 2)) + 1)})

    @staticmethod
    def main_logic(*args, **kwargs):
        number_str, *_ = args
        number = int(number_str)
        return sorted(
            set(Task559.eratosthenes(number)).intersection(
                set(Task559.mersen_numbers(number)))
        )  # Mersenne primes

    def execute(self) -> None:
        """
        Combine validation data + main logic
        """
        print(self.__doc__)
        input_data = input("Enter n: ")

        try:
            number = self.validate_data(input_data)
        except ValueError:
            print("You've entered not natural number")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        # number must be natural
        result = self.main_logic(number)
        print("Mersenne primes less than {}:".format(
            int(input_data)), sorted(result))

        return None

    @staticmethod
    def name() -> str:
        return "559"


@register
class Task243b(TaskWithOneIntValidationParameter):
    """
    A natural number n is given.
    Can you imagine it as a sum of two squares of natural numbers?
    If yes, find all of the pairs x, y of such natural numbers that n = x ^2 + y ^2
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> List[Tuple[int, int]]:
        """
        Find all of the two numbers (x, y) that x ^2 + y ^2 = n
        """
        n_number: int = args[0]
        n_number_square: float = sqrt(n_number)

        squares_numbers = []

        for y_number in range(1, int(sqrt(n_number)) + 1):
            # n = x^2 + y^2
            # x^2 = sqrt(n)^2 - y^2 = (sq + y) * (sq - y)
            x_number = sqrt((n_number_square + y_number)
                            * (n_number_square - y_number))
            if int(x_number) == x_number:
                if int(x_number) >= y_number:
                    squares_numbers.append((int(x_number), y_number))

            # prevention of calculation errors
            elif abs(round(x_number) - x_number) < 0.0000000001:
                if round(x_number) >= y_number:
                    squares_numbers.append((round(x_number), y_number))

        return squares_numbers

    def execute(self) -> None:
        """
        Processes user behavior and displays results
        :return: None
        """
        print(self.__doc__)

        input_data = input("Enter n: ")

        try:
            n_number = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        all_squares = self.main_logic(n_number)

        if all_squares:
            for pair in all_squares:
                print(
                    "{x1} ^2 + {x2} ^2 = {N}".format(x1=pair[0], x2=pair[1], N=n_number))
        else:
            print("This number cannot be represented as the sum of two squares")

        return None

    @staticmethod
    def name() -> str:
        return "243 б)"


@register
class Task555(TaskWithOneIntValidationParameter):
    """
    Pascal's triangle is a numerical triangle in which there are ones
    at the edges, and each number inside is equal to the sum of the
    two above it in the nearest line above.
    Given natural n. Get first n rows of a triangle Pascal.
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:

        number: int = args[0]
        for i in range(number):
            for j in range(number - i + 1):
                print(end=' ')

            for j in range(i + 1):
                # C**k_n = n!/(k!*(n-r)!)
                yield factorial(i) // (factorial(j) * factorial(i - j))
            # for j in range(n - i + 1):
            #     print(end=" ")
            yield "\n"

    def execute(self) -> None:
        print(self.__doc__)
        print("Enter natural number: ", end=" ")
        number = int(input())
        try:
            number = self.validate_data(number)
        except ValueError:
            print("ValueError exception thrown")
            return None
        print(" ", end="")
        for i in self.main_logic(number):
            print(i, end=" ")

        return None

    @staticmethod
    def name() -> str:
        return "555"


@register
class Task88c(TaskWithOneIntValidationParameter):
    """
    A natural number n is given. Swap the first and last digits of n
    """

    @staticmethod
    def main_logic(n: int) -> int:
        """
        Switches first and last digits of the number
        """

        n = str(n)
        return int(n) if len(n) == 1 else int(n[-1] + n[1:-1] + n[0])

    def execute(self) -> None:
        print(self.__doc__)

        input_data = input(
            "Enter N to switch first and last digits of the number : ")

        try:
            n = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        print("Result: {}".format(self.main_logic(n)))

        return None

    @staticmethod
    def name() -> str:
        return "88 в)"


@register
class Task88d(TaskWithOneIntValidationParameter):

    """
    A natural number n is given. Add the number 1 to the beginning and end of n
    """

    @staticmethod
    def main_logic(n: int) -> int:
        """
        Inserts digit 1 on the start and last positions
        """

        n = str(n)
        return int("1" + n + "1")

    def execute(self) -> None:
        print(self.__doc__)

        input_data = input(
            "Enter N to insert digit 1 on the start and last positions of the number : ")
        try:
            n = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        print("Result: {}".format(self.main_logic(n)))
        return None

    @staticmethod
    def name() -> str:
        return "88 г)"


@register
class Task332(TaskWithOneIntValidationParameter):
    """
    A natural number n is given.
    Finds natural x1, x2, x3, x4 which satisfy the condition of equality: x1^2 + x2^2 + x3^2 + x4^2 = n
    """

    @staticmethod
    def main_logic(n: int) -> List[int]:
        """
        Returns coefficients of distribution of a natural number into 4 squares
        """

        res, tmp_res, counter = 0, 0, 0
        xs = [0, 0, 0, 0]
        for i in xs:
            counter += 1
            if tmp_res != n:
                while res <= n:
                    res = tmp_res + i ** 2
                    i += 1
                if i == 0:
                    i = 0
                elif i == 3 and counter == len(xs) and n == tmp_res + 4:
                    i = 2
                elif i == 2 and counter == len(xs) and n == tmp_res + 1:
                    i = 1
                else:
                    i -= 2
                res = i ** 2
                tmp_res += res
                xs[counter - 1] = i

        return xs

    def execute(self) -> None:
        print(self.__doc__)

        input_data = input(
            "Enter N to find Lagrange decomposition coefficients : ")
        try:
            n = self.validate_data(input_data)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None

        for i, x in enumerate(self.main_logic(n)):
            print("x" + str(i) + " = " + str(x))

        return None

    @staticmethod
    def name() -> str:
        return "332"


# for task 331. Checking whether we can represent given number as a sum of 3 number in power 2
# complexity ~ O(n)
def check(number, task):
    """
    Function to check in tasks 331a and 331b
    """
    array = []
    for i in range(1, int(sqrt(number)+1)):
        for j in range(1, int(sqrt(number - i ** 2))+1):
            third = number - i ** 2 - j ** 2
            if third > 0 and float(third ** (1 / 2)) % 1 == 0:
                array.append(str(i) + "^2 + " + str(j) + "^2 + " +
                             str(int(third ** (1 / 2))) + "^2")
                if task == "331 a":
                    return array
    return array


@register
class Task331a(TaskWithOneIntValidationParameter):
    """
    \n331 a. You should enter the number.\n
    The aim is to check whether we can represent given number as a sum of 3 number in power 2.
    And if yes, show the sum\n
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> List[str]:
        """Method return the sum of 3 squares"""
        number: int = args[0]
        result = check(number, "331 a")
        return result

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(number)
        if not result:
            print("It`s impossible!")
        else:
            print(result)
        return None

    @staticmethod
    def name() -> str:
        return "331 а)"


@register
class Task331b(TaskWithOneIntValidationParameter):
    """
    \n331 b. You should enter the number.\n
    The aim is to check whether we can represent given number as a sum of 3 number in power 2.
    And if yes, show all possible sums\
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> List[str]:
        """
        Method return list of all possible sums of 3 squares
        """
        number: int = args[0]
        result = check(number, "331 b")
        return result

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input!")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(number)
        if not result:
            print("It`s impossible!")
        else:
            print(result)
        return None

    @staticmethod
    def name() -> str:
        return "331 б)"


@register
class Task88b(TaskWithOneIntValidationParameter):
    """
    A natural number n is given. Reverse the order of the digits of the number n.
    """

    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Return the reversed number n.
        """
        number: int = args[0]
        return int("".join(reversed(str(number))))

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input number")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(number)
        print("Result = ", result)
        return None

    @staticmethod
    def name() -> str:
        return "88 б)"


def divisor(number):
    """
    find all divisors of the number
    """
    sum_of_divisors = 0
    for i in range(1, ceil(sqrt(number))):
        if i * i == number:
            sum_of_divisors += i
            break
        if number % i == 0:
            sum_of_divisors += i
            sum_of_divisors += number / i
    return sum_of_divisors


@register
class Task322(TaskWithOneIntValidationParameter):
    """
    Find a natural number from 1 to n with the maximum sum of divisors
    """
    @staticmethod
    def main_logic(*args, **kwargs) -> int:
        """
        Return a number with the maximum sum of divisors
        """
        number: int = args[0]
        number += 1
        maximal = 0
        number_with_maximal_sum = 0
        for i in range(1, number):
            if divisor(i) > maximal:
                maximal = divisor(i)
                number_with_maximal_sum = i
        return number_with_maximal_sum

    def execute(self) -> None:
        print(self.__doc__)
        number = input("Input natural number: ")
        try:
            number = self.validate_data(number)
        except ValueError:
            print("Wrong input number")
            return None
        except TypeError:
            print("Invalid type of input number")
            return None
        result = self.main_logic(number)
        print("Result = ", result)
        return None

    @staticmethod
    def name() -> str:
        return "322"
