diff --git a/api/advent22_api/core/helpers.py b/api/advent22_api/core/helpers.py index 9be5fa5..2f22828 100644 --- a/api/advent22_api/core/helpers.py +++ b/api/advent22_api/core/helpers.py @@ -3,7 +3,7 @@ import random import re from datetime import date, datetime, timedelta from io import BytesIO -from typing import Any, Self, Sequence, TypeVar +from typing import Any, Iterable, Self, Sequence, TypeVar from fastapi.responses import StreamingResponse from PIL import Image @@ -32,6 +32,53 @@ def set_len(seq: Sequence[T], len: int) -> Sequence[T]: return list(itertools.islice(infinite, len)) +def spread( + given: Iterable[int], + n: int, + rnd: Random | None = None, +) -> list[int]: + """ + Zu `given` ganzen Zahlen `n` zusätzliche Zahlen hinzunehmen. + + - Die neuen Werte sind im selben Zahlenbereich wie `given` + - Zuerst werden alle Werte "zwischen" den `given` Werten genommen + """ + + if n == 0: + return [] + + if len(set(given)) > 1: + range_given = range(min(given), max(given) + 1) + first_round = set(range_given) - set(given) + + elif len(set(given)) == 1: + if (a := next(iter(given))) > 0: + range_given = range(1, a + 1) + else: + range_given = range(1, n + 1) + + first_round = set(range_given) - set(given) + + else: + range_given = range(1, n + 1) + first_round = range_given + + result = sorted(first_round)[: min(n, len(first_round))] + + full_rounds = (n - len(result)) // len(range_given) + result += list(range_given) * full_rounds + + remain = n - len(result) + if rnd is None: + result += list(range_given)[:remain] + + else: + result += rnd.sample(range_given, remain) + rnd.shuffle(result) + + return result + + async def list_images_auto() -> list[str]: """ Finde alle Bilddateien im "automatisch"-Verzeichnis diff --git a/api/test/test_spread.py b/api/test/test_spread.py new file mode 100644 index 0000000..450a978 --- /dev/null +++ b/api/test/test_spread.py @@ -0,0 +1,77 @@ +from advent22_api.core.helpers import spread + + +def test_easy() -> None: + assert spread([1, 4], 0) == [] + assert spread([1, 4], 1) == [2] + assert spread([1, 4], 2) == [2, 3] + assert spread([1, 4], 5) == [2, 3, 1, 2, 3] + assert spread([1, 4], 10) == [2, 3, 1, 2, 3, 4, 1, 2, 3, 4] + + +def test_tight() -> None: + assert spread([1, 2], 0) == [] + assert spread([1, 2], 1) == [1] + assert spread([1, 2], 2) == [1, 2] + assert spread([1, 2], 5) == [1, 2, 1, 2, 1] + assert spread([1, 2], 10) == [1, 2, 1, 2, 1, 2, 1, 2, 1, 2] + + assert spread([1, 2, 3, 4, 5], 0) == [] + assert spread([1, 2, 3, 4, 5], 1) == [1] + assert spread([1, 2, 3, 4, 5], 2) == [1, 2] + assert spread([1, 2, 3, 4, 5], 5) == [1, 2, 3, 4, 5] + assert spread([1, 2, 3, 4, 5], 10) == [1, 2, 3, 4, 5, 1, 2, 3, 4, 5] + + +def test_more_given() -> None: + assert spread([0, 5, 10], 0) == [] + assert spread([0, 5, 10], 1) == [1] + assert spread([0, 5, 10], 2) == [1, 2] + assert spread([0, 5, 10], 5) == [1, 2, 3, 4, 6] + assert spread([0, 5, 10], 10) == [1, 2, 3, 4, 6, 7, 8, 9, 0, 1] + + assert spread([0, 1, 2, 5, 10], 0) == [] + assert spread([0, 1, 2, 5, 10], 1) == [3] + assert spread([0, 1, 2, 5, 10], 2) == [3, 4] + assert spread([0, 1, 2, 5, 10], 5) == [3, 4, 6, 7, 8] + assert spread([0, 1, 2, 5, 10], 10) == [3, 4, 6, 7, 8, 9, 0, 1, 2, 3] + + +def test_one_given() -> None: + assert spread([0], 0) == [] + assert spread([0], 1) == [1] + assert spread([0], 2) == [1, 2] + assert spread([0], 5) == [1, 2, 3, 4, 5] + assert spread([0], 10) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + assert spread([1], 0) == [] + assert spread([1], 1) == [1] + assert spread([1], 2) == [1, 1] + assert spread([1], 5) == [1, 1, 1, 1, 1] + assert spread([1], 10) == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + + assert spread([2], 0) == [] + assert spread([2], 1) == [1] + assert spread([2], 2) == [1, 1] + assert spread([2], 5) == [1, 1, 2, 1, 2] + assert spread([2], 10) == [1, 1, 2, 1, 2, 1, 2, 1, 2, 1] + + assert spread([5], 0) == [] + assert spread([5], 1) == [1] + assert spread([5], 2) == [1, 2] + assert spread([5], 5) == [1, 2, 3, 4, 1] + assert spread([5], 10) == [1, 2, 3, 4, 1, 2, 3, 4, 5, 1] + + assert spread([10], 0) == [] + assert spread([10], 1) == [1] + assert spread([10], 2) == [1, 2] + assert spread([10], 5) == [1, 2, 3, 4, 5] + assert spread([10], 10) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 1] + + +def test_none_given() -> None: + assert spread([], 0) == [] + assert spread([], 1) == [1] + assert spread([], 2) == [1, 2] + assert spread([], 5) == [1, 2, 3, 4, 5] + assert spread([], 10) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]