У меня нет большого опыта игры в Code Kata на Hackerrank, и я не фанат, который ищет хороший ранг на платформе Hackerrank. Но у меня есть время, чтобы решить одну проблему с Hackerrank.

Сегодня у меня есть интересный опыт по поиску достойного решения проблемы на Hackerrank. Сегодня я вижу эту ссылку https://www.hackerrank.com/contests/101hack48/challenges/walking-robots

И у меня есть мысль решить ее самостоятельно, я прочитал вопрос, вижу ввод и вывод, а также пример, и я собираюсь решить его, используя свои заметки.

Мне в голову не пришло ни одного решения. Я думаю, что этот вопрос - пустяковая проблема, нам не нужен какой-либо тип структуры данных и определенная алгоритмическая стратегия для ее решения.

И мне пришла в голову идея, почему бы не использовать TDD для решения такого рода проблем. Я помню, как дядя Боб однажды сказал: TDD - это создание вашего решения, которое вписывается в проблемные области. И я считаю, что TDD касается дизайна, формы и помогает мне понять проблему.

Я собираюсь установить pytest на свой виртуальный сервер и начать код с моего теста.

Первый тест называется дегенеративным тестом, если вы смотрели учебник по TDD от дяди Боба. Он всегда говорит: напишите самый простой тест и реализацию, когда сталкиваетесь с проблемой. Итак, я создаю тест под названием «test_when_there_is_just_one_robot». Что произойдет, если в одном роботе будет одна символьная инструкция? В самом деле, столкновения не произошло бы, если бы один-единственный робот двигался влево, вправо или оставался на своем месте.

def test_when_there_is_just_one_robot():
 instruction = ‘r’
 assert_walking_robot(instruction, 0)

После создания реализации и прохождения теста. Я перехожу на следующий уровень тестирования, чтобы масштабировать ввод. Я масштабирую входные данные в два раза больше, чем в предыдущем тесте, а именно:

def test_when_robot_walking_same_direction():
 instruction = [‘rr’, ‘ll’, ‘dd’]
 expected = [0, 0, 0]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Я раздавил ввод в одном тестовом примере, потому что он представлял ту же цель. Чтобы проверить, не приведет ли другой тип инструкции робота к конфликту, если бы был такой же тип инструкции.

Хорошо, а что потом? Я думаю, следующая легкая часть - это создание простой комбинации, когда тип инструкции не вызовет коллизии.

def test_when_robot_is_not_crashing():
 instruction = [‘ld’, ‘dr’, ‘lr’, ‘ll’, ‘rr’]
 for inst in instruction:
   assert_walking_robot(inst, 0)

Если робот идет слева, а второй робот остается на своем месте, столкновения не будет. И так далее. Я раздавил тестовый пример и собрал их в один тестовый пример.

Реализация просто должна убедиться, что тест пройден, я не думаю о каком-либо рефакторинге на этой фазе.

Далее, самый простой путь, который я мог сделать, - это масштабирование моего тестового примера. То есть, когда есть 3 робота, 2 идут вправо, а последний робот остается на своем месте. Будет столкновение с последним роботом.

def test_when_robot_is_crashing_with_stopped_robot_but_there_is_a_same_direction_robot_behind():
 instruction = [‘rrd’, ‘rrrd’, ‘rrrrd’]
 expected = [2, 3, 4]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Извините за длинное название тестового примера, но я просто хочу масштабировать команду «rd» в более масштабный тестовый пример, «rrrd», «rrrrd».

следующий, это

def test_when_robot_is_crashing_when_there_is_random_robot_stay_on_position():
 instruction = [‘rrdrr’, ‘rrrdrrr’, ‘rrrrdrrrr’, ‘drrrr’, ‘rrdrdrdr’]
 expected = [2, 3, 4, 0, 4]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Когда в середине инструкции есть случайно оставшийся робот. На этом этапе я мог получить образец для правильного и постоянного типа команды робота. Следующее, что мне нужно уточнить, - это левый тип команды.

То же самое и с правильным типом команды, здесь:

def test_when_robot_going_left_and_crash_the_stayed_robot():
 instruction = [‘ld’, ‘lld’, ‘dl’, ‘dll’, ‘dlll’]
 expected = [0, 0, 1, 2, 3]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Потому что, когда робот находится слева от оставшегося робота, он столкнется n раз.

Далее мы должны объединить правого, левого и оставшегося робота в позиции. Что будет примерно так:

def test_combination_right_and_left_but_crashed_with_stayed_robot():
 instruction = [‘rrdll’, ‘rrrdlll’, ‘rrdrdldll’]
 expected = [4, 6, 6]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Уф, я создал множество тестов, чтобы убедиться, что правый, левый и неподвижный робот станут одной интегрированной инструкцией.

Что дальше ? Есть одно условие, которое еще не рассмотрено, это условие, когда робот, идущий направо, и робот, идущий налево, сталкиваются.

def test_right_and_left_robot_are_crashed():
 instruction = [‘rl’, ‘rrl’, ‘rrrl’, ‘rrrrl’, ‘rll’, ‘rlrl’, ‘rllrll’, ‘lrlrlr’]
 expected = [2, 3, 4, 5, 3, 4, 6, 4]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Супер хитрый пример, потому что когда дается команда «rl». Правая команда и левая команда вызывают столкновение, которое возвращает «2 точки столкновения». Используя аналогичный шаблон, я масштабирую свой тестовый пример, добавляя ‘r’ перед ‘l’. И добавление ‘l’ после ‘r’.

Наконец, я объединяю все тестовые примеры в один:

def test_combination_of_right_left_and_stayed_robots():
 instruction = [‘rdl’, ‘rrdll’, ‘rldrl’]
 expected = [2, 4]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Когда комбинируется тип столкновения и также комбинируется весь тип команды.

def test_hackerrank():
 instruction = [‘r’, ‘lrrl’, ‘rrrll’, ‘rrdlldrr’, ‘rrrdllrllrrl’]
 expected = [0, 3, 5, 4, 11]
 for inst, exp in zip(instruction, expected):
   assert_walking_robot(inst, exp)

Последний тестовый пример посвящен созданию теста hackerrank и вуаля!

Очень рад выполнить эту задачу с помощью данной техники (TDD), потому что я использую эту технику в офисе каждый день, выполняя офисную задачу.

И урок, который я усвоил сегодня:

  1. Использование TDD не так уж и плохо, когда вы сталкиваетесь с такой же проблемой, как эта, потому что это бросает вызов вашим ожиданиям и разрабатывает свое решение.
  2. В коде невозможно потерять смысл
  3. Вы можете настроить некоторые алгоритмы, которые хотите использовать, на основе тестового примера. Я дважды настраиваю свой алгоритм, потому что я застреваю в двух последних тестовых примерах, которые я был создан ранее.
  4. Вы можете без проблем провести рефакторинг своего кода.

Для ссылки на код ›› https://github.com/byanjati/hackerrank/blob/master/test_walking_robot.py