Решение на Телефонна любов от Антоан Ивайлов

Обратно към всички решения

Към профила на Антоан Ивайлов

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 31 успешни тест(а)
  • 6 неуспешни тест(а)

Код

# Task 1: "nums_to_text" relevant functions
def list_to_number(number_sequence):
result = 0
for num in number_sequence:
result = result * 10 + num
return result
# works correctly 100%, given correct number of numbers and only singly grouped characters, aka no mixes
def number_to_letter(raw_number, input_len):
num_code_to_char = {2: 'A', 22: 'B', 222: 'C', 3: 'D', 33: 'E', 333: 'F',
4: 'G', 44: 'H', 444: 'I', 5: 'J', 55: 'K', 555: 'L',
6: 'M', 66: 'N', 666: 'O', 7: 'P', 77: 'Q', 777: 'R',
7777: 'S', 8: 'T', 88: 'U', 888: 'V', 9: 'W',
99: 'X', 999: 'Y', 9999: 'Z', 0: ' '}
max_chars_per_code = {7: 4, 9: 4, 0: 1}
limit_of_input_chars = 3 # Most symbols have limit of 3
found_number = list_to_number(raw_number)
if found_number % 10 in max_chars_per_code:
limit_of_input_chars = max_chars_per_code[found_number % 10]
# Cycle until we are in valid limits of the input character
while input_len > limit_of_input_chars:
numbers_to_be_removed = limit_of_input_chars
# remove the number of designated 'extra' characters
while numbers_to_be_removed > 0:
found_number //= 10
numbers_to_be_removed -= 1
input_len -= limit_of_input_chars
return num_code_to_char[found_number]
def nums_to_text(nums):
final_str = ""
start_index = 0
end_index = 1
while start_index < len(nums):
raw_num = []
# creates a raw_num_input
while end_index < len(nums) and nums[start_index] == nums[end_index]:
end_index += 1
raw_num.extend(nums[start_index:end_index])
# We will work-up our raw_input_num into acceptable character
if raw_num != [-1]: # If raw_num is invalid (space-holder == -1), don't parse it
final_str += number_to_letter(raw_num, end_index - start_index)
start_index = end_index
end_index += 1
return final_str
# Task 2: "text_to_num" relevant functions
def number_to_list(number):
result = []
if number == 0: # Corner case check if the input is 'space'
result.append(0)
else:
# Because we will work with only single unique digits, we don't need to inverse the number before splitting it
while number > 0:
result.append(number % 10)
number //= 10
return result
# Alternative approach to these 2 keyboards, will be to use a bidict(from bidict library), which requires PIP?
def letter_to_number(letter):
char_code_to_num = {'A': 2, 'B': 22, 'C': 222, 'D': 3, 'E': 33, 'F': 333,
'G': 4, 'H': 44, 'I': 444, 'J': 5, 'K': 55, 'L': 555,
'M': 6, 'N': 66, 'O': 666, 'P': 7, 'Q': 77, 'R': 777,
'S': 7777, 'T': 8, 'U': 88, 'V': 888, 'W': 9,
'X': 99, 'Y': 999, 'Z': 9999, ' ': 0}
return char_code_to_num[letter]
def text_to_nums(text):
text = text.upper()
# We simulate a do-while cycle
curr_num = number_to_list(letter_to_number(text[0]))
nums_code = curr_num
index = 1
while index < len(text):
curr_num = number_to_list(letter_to_number(text[index]))
if nums_code[-1] == curr_num[0]: # the last digit of input is the same as the next digit of command
nums_code.append(-1)
nums_code.extend(curr_num)
index += 1
return nums_code
# Task 3: "nums_to_angle" relevant functions
def normalize_angle(raw_angle):
MAX_DEGREES_LIMIT = 360
while raw_angle < 0:
raw_angle *= -1
raw_angle = MAX_DEGREES_LIMIT - raw_angle
while raw_angle >= MAX_DEGREES_LIMIT:
raw_angle -= MAX_DEGREES_LIMIT
return raw_angle
def nums_to_angle(nums):
# -1 value is needed for the phone_tastic function when input with same following letter is found "HELLO"
nums_to_angle_chart = {1: 30, 2: 60, 3: 90, 4: 120, 5: 150, 6: 180, 7: 210, 8: 240, 9: 270, 0: 300, -1: 0}
raw_angle = 0
for num in nums:
raw_angle += nums_to_angle_chart[num]
return normalize_angle(raw_angle)
# Task 4: "angles_to_nums" relevant functions
def round_angle(raw_angle):
if raw_angle <= 15 or raw_angle > 315: # 0 should not be present in the output list
return nums_to_angle([-1])
counter = 0
while raw_angle > 15:
raw_angle -= 30 # 30 = quadrant size, aka single number range
counter += 1
if counter == 10: # 10 is equal to 300 degrees, which take up value 0 in our hashmap
counter = 0
# counter needs to be iterable for nums_to_angle
return nums_to_angle([counter])
def angles_to_nums(angles):
index = 0
# Normalize and round all input angles
while index < len(angles):
angles[index] = normalize_angle(angles[index])
angles[index] = round_angle(angles[index])
index += 1
phone_number = []
angle_to_nums_chart = {30: 1, 60: 2, 90: 3, 120: 4, 150: 5, 180: 6, 210: 7, 240: 8, 270: 9, 300: 0}
for angle in angles:
if angle != 0: # 0 = Invalid (pass by) angle, thus we skip it
phone_number.append(angle_to_nums_chart[angle])
return phone_number
# Task 5: "is_phone_tastic" relevant functions
def is_phone_tastic(word):
raw_nums = text_to_nums(word)
angle = nums_to_angle(raw_nums)
return angle % len(word) == 0

Лог от изпълнението

..........E.........E...E.E..E..E....
======================================================================
ERROR: test_empty_input (test.TestIsPhonetastic)
Test with empty input.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
IndexError: string index out of range

======================================================================
ERROR: test_all_chars (test.TestNumsToText)
Test for correct mapping of all chars.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
KeyError: 1

======================================================================
ERROR: test_multiple_timeouts (test.TestNumsToText)
Test with multiple '-1's next to each other.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
KeyError: -111

======================================================================
ERROR: test_random_mixed_case (test.TestNumsToText)
Test for a random mixed case.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
KeyError: 1

======================================================================
ERROR: test_starting_with_timeout (test.TestNumsToText)
Test with a sequence starting with a -1.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
KeyError: -11

======================================================================
ERROR: test_empty_input (test.TestTextToNums)
Test with empty input.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/storage/deedee/data/rails/pyfmi-2022/releases/20221020151654/lib/language/python/runner.py", line 67, in thread
    raise result
IndexError: string index out of range

----------------------------------------------------------------------
Ran 37 tests in 0.454s

FAILED (errors=6)

История (2 версии и 2 коментара)

Антоан обнови решението на 31.10.2022 12:21 (преди над 2 години)

+# Task 1: "nums_to_text" relevant functions
+def list_to_number(number_sequence):
+ result = 0
+ for num in number_sequence:
+ result = result * 10 + num
+ return result
+
+
+# works correctly 100%, given correct number of numbers and only singly grouped characters, aka no mixes
+def number_to_letter(raw_number, input_len):
+ num_code_to_char = {2: 'A', 22: 'B', 222: 'C', 3: 'D', 33: 'E', 333: 'F',
+ 4: 'G', 44: 'H', 444: 'I', 5: 'J', 55: 'K', 555: 'L',
+ 6: 'M', 66: 'N', 666: 'O', 7: 'P', 77: 'Q', 777: 'R',
+ 7777: 'S', 8: 'T', 88: 'U', 888: 'V', 9: 'W',
+ 99: 'X', 999: 'Y', 9999: 'Z', 0: ' '}
+
+ max_chars_per_code = {7: 4, 9: 4, 0: 1}
+
+ limit_of_input_chars = 3 # Most symbols have limit of 3
+
+ found_number = list_to_number(raw_number)
+ if found_number % 10 in max_chars_per_code:
+ limit_of_input_chars = max_chars_per_code[found_number % 10]
+
+ # Cycle until we are in valid limits of the input character
+ while input_len > limit_of_input_chars:
+ numbers_to_be_removed = limit_of_input_chars
+ # remove the number of designated 'extra' characters
+ while numbers_to_be_removed > 0:
+ found_number //= 10
+ numbers_to_be_removed -= 1
+ input_len -= limit_of_input_chars
+
+ return num_code_to_char[found_number]
+
+
+def nums_to_text(nums):
+ final_str = ""
+ start_index = 0
+ end_index = 1
+ while start_index < len(nums):
+ raw_num = []
+ # creates a raw_num_input
+ while end_index < len(nums) and nums[start_index] == nums[end_index]:
+ end_index += 1
+
+ raw_num.extend(nums[start_index:end_index])
+
+ # We will work-up our raw_input_num into acceptable character
+ if raw_num != [-1]: # If raw_num is invalid (space-holder == -1), don't parse it
+ final_str += number_to_letter(raw_num, end_index - start_index)
+ start_index = end_index
+ end_index += 1
+
+ return final_str
+
+
+# Task 2: "text_to_num" relevant functions
+def letter_to_number(letter):
+ char_code_to_num = {'A': [2], 'B': [2, 2], 'C': [2, 2, 2], 'D': [3], 'E': [3, 3], 'F': [3, 3, 3],
+ 'G': [4], 'H': [4, 4], 'I': [4, 4, 4], 'J': [5], 'K': [5, 5], 'L': [5, 5, 5],
+ 'M': [6], 'N': [6, 6], 'O': [6, 6, 6], 'P': [7], 'Q': [7, 7], 'R': [7, 7, 7],
+ 'S': [7, 7, 7, 7], 'T': [8], 'U': [8, 8], 'V': [8, 8, 8], 'W': [9],
+ 'X': [9, 9], 'Y': [9, 9, 9], 'Z': [9, 9, 9, 9], ' ': [0]}
+ return char_code_to_num[letter]
+
+
+def text_to_nums(text):
+ text = text.upper()
+
+ # We simulate a do-while cycle
+ curr_num = letter_to_number(text[0])
+ nums_code = curr_num
+
+ index = 1
+ while index < len(text):
+ curr_num = letter_to_number(text[index])
+ if nums_code[-1] == curr_num[0]: # the last digit of input is the same as the next digit of command
+ nums_code.append(-1)
+ nums_code.extend(curr_num)
+ index += 1
+ return nums_code
+
+
+# Task 3: "nums_to_angle" relevant functions
+def normalize_angle(raw_angle):
+ MAX_DEGREES_LIMIT = 360
+ while raw_angle < 0:
+ raw_angle *= -1
+ raw_angle = MAX_DEGREES_LIMIT - raw_angle
+
+ while raw_angle >= MAX_DEGREES_LIMIT:
+ raw_angle -= MAX_DEGREES_LIMIT
+ return raw_angle
+
+
+def nums_to_angle(nums):
+ # -1 value is needed for the phone_tastic function when input with same following letter is found "HELLO"
+ nums_to_angle_chart = {1: 30, 2: 60, 3: 90, 4: 120, 5: 150, 6: 180, 7: 210, 8: 240, 9: 270, 0: 300, -1: 0}
+
+ raw_angle = 0
+ for num in nums:
+ raw_angle += nums_to_angle_chart[num]
+ return normalize_angle(raw_angle)
+
+
+# Task 4: "angles_to_nums" relevant functions
+def round_angle(raw_angle):
+ if raw_angle <= 15 or raw_angle > 315: # This angles will be rounded to 0 or 330 degrees
+ raw_angle = 0 # Otherwise each line will have an "and" comparison, which will make the code clunky
+ elif raw_angle <= 45:
+ raw_angle = 30
+ elif raw_angle <= 75:
+ raw_angle = 60
+ elif raw_angle <= 105:
+ raw_angle = 90
+ elif raw_angle <= 135:
+ raw_angle = 120
+ elif raw_angle <= 165:
+ raw_angle = 150
+ elif raw_angle <= 195:
+ raw_angle = 180
+ elif raw_angle <= 225:
+ raw_angle = 210
+ elif raw_angle <= 255:
+ raw_angle = 240
+ elif raw_angle <= 285:
+ raw_angle = 270
+ else:
+ raw_angle = 300
+
+ return raw_angle
+
+
+def angles_to_nums(angles):
+ index = 0
+ # Normalize and round all input angles
+ while index < len(angles):
+ angles[index] = normalize_angle(angles[index])
+ angles[index] = round_angle(angles[index])
+ index += 1
+
+ phone_number = []
+ angle_to_nums_chart = {30: 1, 60: 2, 90: 3, 120: 4, 150: 5, 180: 6, 210: 7, 240: 8, 270: 9, 300: 0}
+ for angle in angles:
+ if angle != 0: # 0 = Invalid (pass by) angle, thus we skip it
+ phone_number.append(angle_to_nums_chart[angle])
+ return phone_number
+
+
+# Task 5: "is_phone_tastic" relevant functions
+
+def is_phone_tastic(word):
+ raw_nums = text_to_nums(word) # Maybe I could have written it in 1 line, but it would have been too ugly
+ angle = nums_to_angle(raw_nums)
+ return angle % len(word) == 0

Решението ти ми харесва. Честно казано, не видях нещо конкретно, което да спомената като обратна връзка, но мога да обобщя какво ми направи впечатление:
1) Доста методично решение - правим това, после това, накрая резултатът е това.
2) Чудесна практика да оставя коментари. На места може би излишни, но по-добре да има повече, отколкото никакви.
3) Имаш дублирана дефиниция на клавиатурата. Бих се опитал да я дефинирам веднъж, извън функциите. Иначе нов бутон в/у клавиатурата ще значи две промени в кода ти.
4) Логиката за закръгляване на ъгъла може да се напише на 3-4 реда. Би било по-лесно за поддръжка и няма да има толкова голям шанс от typo в стойностите ти.

Антоан обнови решението на 01.11.2022 22:03 (преди над 2 години)

# Task 1: "nums_to_text" relevant functions
def list_to_number(number_sequence):
result = 0
for num in number_sequence:
result = result * 10 + num
return result
# works correctly 100%, given correct number of numbers and only singly grouped characters, aka no mixes
def number_to_letter(raw_number, input_len):
num_code_to_char = {2: 'A', 22: 'B', 222: 'C', 3: 'D', 33: 'E', 333: 'F',
4: 'G', 44: 'H', 444: 'I', 5: 'J', 55: 'K', 555: 'L',
6: 'M', 66: 'N', 666: 'O', 7: 'P', 77: 'Q', 777: 'R',
7777: 'S', 8: 'T', 88: 'U', 888: 'V', 9: 'W',
99: 'X', 999: 'Y', 9999: 'Z', 0: ' '}
max_chars_per_code = {7: 4, 9: 4, 0: 1}
limit_of_input_chars = 3 # Most symbols have limit of 3
found_number = list_to_number(raw_number)
if found_number % 10 in max_chars_per_code:
limit_of_input_chars = max_chars_per_code[found_number % 10]
# Cycle until we are in valid limits of the input character
while input_len > limit_of_input_chars:
numbers_to_be_removed = limit_of_input_chars
# remove the number of designated 'extra' characters
while numbers_to_be_removed > 0:
found_number //= 10
numbers_to_be_removed -= 1
input_len -= limit_of_input_chars
return num_code_to_char[found_number]
def nums_to_text(nums):
final_str = ""
start_index = 0
end_index = 1
while start_index < len(nums):
raw_num = []
# creates a raw_num_input
while end_index < len(nums) and nums[start_index] == nums[end_index]:
end_index += 1
raw_num.extend(nums[start_index:end_index])
# We will work-up our raw_input_num into acceptable character
if raw_num != [-1]: # If raw_num is invalid (space-holder == -1), don't parse it
final_str += number_to_letter(raw_num, end_index - start_index)
start_index = end_index
end_index += 1
return final_str
# Task 2: "text_to_num" relevant functions
+def number_to_list(number):
+ result = []
+ if number == 0: # Corner case check if the input is 'space'
+ result.append(0)
+ else:
+ # Because we will work with only single unique digits, we don't need to inverse the number before splitting it
+ while number > 0:
+ result.append(number % 10)
+ number //= 10
+ return result
+
+
+# Alternative approach to these 2 keyboards, will be to use a bidict(from bidict library), which requires PIP?
def letter_to_number(letter):
- char_code_to_num = {'A': [2], 'B': [2, 2], 'C': [2, 2, 2], 'D': [3], 'E': [3, 3], 'F': [3, 3, 3],
- 'G': [4], 'H': [4, 4], 'I': [4, 4, 4], 'J': [5], 'K': [5, 5], 'L': [5, 5, 5],
- 'M': [6], 'N': [6, 6], 'O': [6, 6, 6], 'P': [7], 'Q': [7, 7], 'R': [7, 7, 7],
- 'S': [7, 7, 7, 7], 'T': [8], 'U': [8, 8], 'V': [8, 8, 8], 'W': [9],
- 'X': [9, 9], 'Y': [9, 9, 9], 'Z': [9, 9, 9, 9], ' ': [0]}
+ char_code_to_num = {'A': 2, 'B': 22, 'C': 222, 'D': 3, 'E': 33, 'F': 333,
+ 'G': 4, 'H': 44, 'I': 444, 'J': 5, 'K': 55, 'L': 555,
+ 'M': 6, 'N': 66, 'O': 666, 'P': 7, 'Q': 77, 'R': 777,
+ 'S': 7777, 'T': 8, 'U': 88, 'V': 888, 'W': 9,
+ 'X': 99, 'Y': 999, 'Z': 9999, ' ': 0}
return char_code_to_num[letter]
def text_to_nums(text):
text = text.upper()
# We simulate a do-while cycle
- curr_num = letter_to_number(text[0])
+ curr_num = number_to_list(letter_to_number(text[0]))
nums_code = curr_num
index = 1
while index < len(text):
- curr_num = letter_to_number(text[index])
+ curr_num = number_to_list(letter_to_number(text[index]))
if nums_code[-1] == curr_num[0]: # the last digit of input is the same as the next digit of command
nums_code.append(-1)
nums_code.extend(curr_num)
index += 1
return nums_code
# Task 3: "nums_to_angle" relevant functions
def normalize_angle(raw_angle):
MAX_DEGREES_LIMIT = 360
while raw_angle < 0:
raw_angle *= -1
raw_angle = MAX_DEGREES_LIMIT - raw_angle
while raw_angle >= MAX_DEGREES_LIMIT:
raw_angle -= MAX_DEGREES_LIMIT
return raw_angle
def nums_to_angle(nums):
# -1 value is needed for the phone_tastic function when input with same following letter is found "HELLO"
nums_to_angle_chart = {1: 30, 2: 60, 3: 90, 4: 120, 5: 150, 6: 180, 7: 210, 8: 240, 9: 270, 0: 300, -1: 0}
raw_angle = 0
for num in nums:
raw_angle += nums_to_angle_chart[num]
return normalize_angle(raw_angle)
# Task 4: "angles_to_nums" relevant functions
def round_angle(raw_angle):
- if raw_angle <= 15 or raw_angle > 315: # This angles will be rounded to 0 or 330 degrees
- raw_angle = 0 # Otherwise each line will have an "and" comparison, which will make the code clunky
- elif raw_angle <= 45:
- raw_angle = 30
- elif raw_angle <= 75:
- raw_angle = 60
- elif raw_angle <= 105:
- raw_angle = 90
- elif raw_angle <= 135:
- raw_angle = 120
- elif raw_angle <= 165:
- raw_angle = 150
- elif raw_angle <= 195:
- raw_angle = 180
- elif raw_angle <= 225:
- raw_angle = 210
- elif raw_angle <= 255:
- raw_angle = 240
- elif raw_angle <= 285:
- raw_angle = 270
- else:
- raw_angle = 300
+ if raw_angle <= 15 or raw_angle > 315: # 0 should not be present in the output list
+ return nums_to_angle([-1])
- return raw_angle
+ counter = 0
+ while raw_angle > 15:
+ raw_angle -= 30 # 30 = quadrant size, aka single number range
+ counter += 1
+ if counter == 10: # 10 is equal to 300 degrees, which take up value 0 in our hashmap
+ counter = 0
+ # counter needs to be iterable for nums_to_angle
+ return nums_to_angle([counter])
def angles_to_nums(angles):
index = 0
# Normalize and round all input angles
while index < len(angles):
angles[index] = normalize_angle(angles[index])
angles[index] = round_angle(angles[index])
index += 1
phone_number = []
angle_to_nums_chart = {30: 1, 60: 2, 90: 3, 120: 4, 150: 5, 180: 6, 210: 7, 240: 8, 270: 9, 300: 0}
for angle in angles:
if angle != 0: # 0 = Invalid (pass by) angle, thus we skip it
phone_number.append(angle_to_nums_chart[angle])
return phone_number
# Task 5: "is_phone_tastic" relevant functions
def is_phone_tastic(word):
- raw_nums = text_to_nums(word) # Maybe I could have written it in 1 line, but it would have been too ugly
+ raw_nums = text_to_nums(word)
angle = nums_to_angle(raw_nums)
return angle % len(word) == 0

Мислих си го много този вариант с двоен речник oще докато решавах решението първия път, тъй като ключа за едната функция е стойност за другата и обратно. Проучих малко нещата и се оказа, че има такова нещо като bidict от библиотекта bidict (не съм го импортвал иначе да, определено би било полезно - едната фунцкия ще го използва в прав вариант, другата ще го revers-не, използва и пак ще го върне в изходна позиция чрез reverse).