def map_ord(word: str) -> list[int]: "Returns a list of integers representing the codepoint of the characters of a string." return [ord(c) for c in word] def is_ascii_printable(c: int) -> bool: "Given an integer representing the codepoint of a character, check whether it is a ASCII printable character." return c >= 0x20 and c < 0x7F def from_digits(digits: list[int], base: int) -> int: "Given a list of digits, calculate the integer represented by the digits in the given base." val = 0 for i in range(len(digits)): val *= base val += digits[i] return val def to_digits(val: int, base: int) -> list[int]: "Given an integer, returns the digits of the integer in the given base in little-endian order." digits = [] while val > 0: digits.append(val % base) val = val // base return digits def pick_uniform(s: list[int], z: int, i: int, digit: int) -> int: "Uniformly pick a value from the given “set” ``s`` with an offset ``digit`` and remove it from ``s``." index = round(digit + (i / (z + 1)) * len(s)) % len(s) value = s[index] del s[index] return value def get_comb(digits: list[int], s: list[int], z: int) -> tuple[int, ...]: "Returns a combination of ``z`` values from given “set” ``s`` according to ``digits``." comb = [] i = 1 for digit in digits: comb.append(pick_uniform(s, z, i, digit)) i += 1 if i > z: break if z > len(digits): for j in range(z - len(digits)): comb.append(pick_uniform(s, z, i, 0)) i += 1 return tuple(comb) def map_to_values(word: str, m: int, n: int) -> tuple[tuple[int, ...], tuple[int, ...]]: "Return 13 integers in two groups of length ``m`` and ``n`` according to the given ``word`` which is uniformly generated from integers in [10, 99]." assert m + n == 13 chrs = map_ord(word) assert all(is_ascii_printable(c) for c in chrs) from_base = 0x7F - 0x20 to_base = 100 - 10 s1 = list(range(10, 100)) s2 = s1.copy() p1 = to_digits(from_digits([c - 0x20 for c in chrs], from_base), to_base) p2 = p1.copy() p1.reverse() return (get_comb(p1, s1, m), get_comb(p2, s2, n))