Александър обнови решението на 02.11.2022 02:44 (преди над 2 години)
+from typing import List
+
+
+DIGIT_ROTATION_RANGE = {
+ -1: 1,
+ 0: 1,
+ 1: 1,
+ 2: 3,
+ 3: 3,
+ 4: 3,
+ 5: 3,
+ 6: 3,
+ 7: 4,
+ 8: 3,
+ 9: 4,
+}
+
+DIGIT_REPEAT_TO_CHAR = {
+ 0: {
+ 1: ' ',
+ },
+ 1: {
+ 1: '',
+ },
+ 2: {
+ 1: 'A',
+ 2: 'B',
+ 3: 'C',
+ },
+ 3: {
+ 1: 'D',
+ 2: 'E',
+ 3: 'F',
+ },
+ 4: {
+ 1: 'G',
+ 2: 'H',
+ 3: 'I',
+ },
+ 5: {
+ 1: 'J',
+ 2: 'K',
+ 3: 'L',
+ },
+ 6: {
+ 1: 'M',
+ 2: 'N',
+ 3: 'O',
+ },
+ 7: {
+ 1: 'P',
+ 2: 'Q',
+ 3: 'R',
+ 4: 'S',
+ },
+ 8: {
+ 1: 'T',
+ 2: 'U',
+ 3: 'V',
+ },
+ 9: {
+ 1: 'W',
+ 2: 'X',
+ 3: 'Y',
+ 4: 'Z',
+ },
+}
+
+BREAKER = "#"
+
+CHAR_TO_DIGIT_REPEAT = {
+
+ ' ': [0, 1],
+ 'A': [2, 1],
+ 'B': [2, 2],
+ 'C': [2, 3],
+ 'D': [3, 1],
+ 'E': [3, 2],
+ 'F': [3, 3],
+ 'G': [4, 1],
+ 'H': [4, 2],
+ 'I': [4, 3],
+ 'J': [5, 1],
+ 'K': [5, 2],
+ 'L': [5, 3],
+ 'M': [6, 1],
+ 'N': [6, 2],
+ 'O': [6, 3],
+ 'P': [7, 1],
+ 'Q': [7, 2],
+ 'R': [7, 3],
+ 'S': [7, 4],
+ 'T': [8, 1],
+ 'U': [8, 2],
+ 'V': [8, 3],
+ 'W': [9, 1],
+ 'X': [9, 2],
+ 'Y': [9, 3],
+ 'Z': [9, 4],
+}
+
+NORMALISED_ANGLE_MIN_LIMIT = 0
+NORMALISED_ANGLE_MAX_LIMIT = 359
+
+NUM_TO_ANGLE = {
+ 1: 30,
+ 2: 60,
+ 3: 90,
+ 4: 120,
+ 5: 150,
+ 6: 180,
+ 7: 210,
+ 8: 240,
+ 9: 270,
+ 0: 300,
+}
+
+ANGLE_TO_NUM = {angle: num for num, angle in NUM_TO_ANGLE.items()}
+
+
+def nums_to_text(nums: List[int]) -> str:
+ commands = [] # list of 2-sized lists [num; times met consecutively]
+ for num in nums:
+ if len(commands) == 0 or commands[-1][0] != num:
+ commands.append([num, 1])
+ else:
+ commands[-1][1] += 1
+
+ for i in range(len(commands)):
+ digit = commands[i][0]
+ repetition = commands[i][1]
+
+ if digit in [-1, 1]:
+ commands[i] = BREAKER
+ elif digit == 0:
+ # TODO for now, there is a question regarding that in the forum, we wait
+ commands[i][1] = 1
+ elif repetition > DIGIT_ROTATION_RANGE[digit]:
+ diff = repetition % DIGIT_ROTATION_RANGE[digit]
+ commands[i][1] = diff if diff != 0 else DIGIT_ROTATION_RANGE[digit]
+
+ res = []
+ for data_block in commands:
+ if data_block == BREAKER:
+ continue
+ else:
+ digit = data_block[0]
+ repetition = data_block[1]
+ res.append(DIGIT_REPEAT_TO_CHAR[digit][repetition])
+
+ return ''.join(res)
+
+
+def text_to_nums(text: str) -> List[int]:
+ chars = [char for char in text.upper()]
+
+ prev_char = None
+ res = []
+
+ for char in chars:
+ digit = CHAR_TO_DIGIT_REPEAT[char][0]
+ repetitions = CHAR_TO_DIGIT_REPEAT[char][1]
+ if prev_char != None and digit == CHAR_TO_DIGIT_REPEAT[prev_char][0]:
+ # insert breaker
+ res.append(-1)
+ for _ in range(repetitions):
+ res.append(digit)
+ prev_char = char
+
+ return res
+
+
+def nums_to_angle(nums: List[int]) -> int:
+ angles = [NUM_TO_ANGLE[num] for num in nums if num != -1]
+
+ total_normalised_angle = 0
+ for angle in angles:
+ total_normalised_angle += angle
+ if total_normalised_angle > NORMALISED_ANGLE_MAX_LIMIT:
+ total_normalised_angle %= (NORMALISED_ANGLE_MAX_LIMIT + 1)
+
+ return total_normalised_angle
+
+
+def angles_to_nums(angles: List[int]) -> List[int]:
+
+ def round_angle(angle: int):
+ angle /= 30
+ angle = round(angle)
+ angle *= 30
+ return angle
+
+ def normalise_angle(angle: int):
+ if NORMALISED_ANGLE_MAX_LIMIT < angle:
+ angle %= (NORMALISED_ANGLE_MAX_LIMIT + 1)
+
+ while angle < NORMALISED_ANGLE_MIN_LIMIT: # could be -719, need to be added to 360 twice
+ angle += (NORMALISED_ANGLE_MAX_LIMIT + 1)
+
+ return angle
+
+ nums = []
+ for angle in angles:
+ angle = normalise_angle(angle)
+ angle = round_angle(angle)
+ if angle in [0, 330]:
+ continue
+ nums.append(ANGLE_TO_NUM[angle])
+
+ return nums
+
+
+def is_phone_tastic(word: str) -> bool:
+ num_of_chars = len(word)
+ nums_from_word = text_to_nums(word)
+ angle_from_nums = nums_to_angle(nums_from_word)
+
+ return angle_from_nums % num_of_chars == 0