Кодирование принципов серверной части игры FizzBuzz
Эта статья посвящена кодированию неявных условий в FizzBuzz. Это заставляет вас переходить по строкам кода, которые дают аналогичный результат с другим синтаксисом.
Кому ?
Это для новичков в Эликсире. Но в конце это будет более информативным.
Что такое Fizz-Buzz?
Когда вы гуглите, вы найдете следующие фразы о FizzBuzz.
FizzBuzz - это очень простая задача программирования, которая используется на собеседовании с разработчиками программного обеспечения, чтобы определить, действительно ли кандидат может писать код.
Шипучка - это групповая игра в слова, которая помогает детям научиться делению. Игроки по очереди подсчитывают постепенно, заменяя любое число, делящееся на три словом «fizz», а любое число, делимое на пять, словом «buzz» и, если он делится на три и пять, со словом FizzBuzz или просто напечатайте само число.
Это все о FizzBuzz. О ... наконец-то вы узнали, что такое FizzBuzz. Так держать…
Что мы будем здесь кодировать?
Мы просто печатаем числа в диапазоне, заменяя их словами Fizz, Buzz и FizzBuzz, используя игровой протокол.
Время писать код…
Раздел Fizz
Здесь я назвал модуль FizzBuzz
, конечно, все делают то же самое и написали play/2
функцию.
Сначала мы просто печатаем числа в диапазоне и смотрим, как это работает.
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> IO.puts num end ) end end
играть / 2
Эта функция принимает два числа в качестве входных технически минимального и максимального значений в диапазоне. Итак, мы можем создать диапазон с помощью макроса ../2
.
мин Макс
Диапазон внутри представлен в виде структуры. Диапазон реализует протокол Enumerable
, что означает, что функции в модуле Enum
могут использоваться для работы с диапазонами.
Вы можете проверить реализованные протоколы с помощью i/1
i 1..2
Итак, мы воспользовались помощью функции each
в модуле Enum
, чтобы выполнить итерацию функции по диапазону и распечатать числа.
fn (num) - ›IO.puts num end
Здесь мы использовали анонимную функцию для печати чисел путем вызова IO.puts
внутри функции.
Сопоставление с образцом по входным значениям функции
Здесь мы напишем другую функцию с тем же именем play
, но на этот раз она принимает только один вход play/1
. В соответствии с ООП это называется перегрузкой метода.
Вот так выглядит код.
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end end
Изменения:
Вместо вызова IO.puts
внутри анонимной функции мы создали функцию для печати. Здесь, внутри определения функции play/1
, мы воспользовались предложением Elixir guard when
, чтобы выполнить условия игры.
Если число делится на три, остаток будет 0
. Итак, мы используем функцию rem/2
, чтобы получить остаток, и ==
, чтобы проверить значение истинности выражения. Если значение истинности равно true
, выполняется определение функции, в противном случае определение не выполняется.
Теперь скопируйте код и вставьте его в iex
. Компилируется хорошо.
Теперь вызовите функцию воспроизведения как
iex> FizzBuzz.play 1,20
Вы увидите ошибку времени выполнения. Он скомпилировался хорошо, но мы получили ошибку во время выполнения.
Вот так выглядит ошибка.
Исправление проблем
Что не так с нашим кодом?
Первым значением в диапазоне 1..20
будет 1
, потому что диапазоны всегда включают.
Первая итерация вызова функции будет выглядеть так:
Enum.each -- fn(1)-> play(1) end
Здесь play
функция запускается со значением 1
, но выражение предохранительного предложения rem(1, 3)==0
приведет к false
Таким образом, предложение функции не соответствует переданному значению.
Итак, нам нужно написать еще print
функцию, которая будет печатать числа, которые не делятся на 3, и вот так выглядит код.
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end def play(num) do IO.puts num end end
Теперь попробуйте, скопировав вставку вышеперечисленных строк кода внутрь iex
и вызовите функцию воспроизведения как FizzBuzz.play 1,20
.
Вы увидите, что числа, кратные трем итерациям, будут печатать Fizz
вместо числа.
Живая лента
Как и в случае с Fizz, мы должны добавить еще одну функцию play/1
function с защитным условием, проверяющим делимость на 5.
Давайте посмотрим обновленный код
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end def play(num) when rem(num, 5) == 0 do IO.puts "Buzz" end def play(num) do IO.puts num end end
Раздел FizzBuzz
Подобно Fizz и Buzz, мы можем проверить делимость числа на 3 и 5 с учетом НОК (наименьшее общее кратное) обоих чисел. НОК 3 и 5 равно 15. Итак, если число делится на 15, то оно делится как на 3, так и на 5.
Давайте добавим еще одну функцию.
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end def play(num) when rem(num, 5) == 0 do IO.puts "Buzz" end def play(num) when rem(num, 15) == 0 do IO.puts "FizzBuzz" end def play(num) do IO.puts num end end
Теперь скопируйте и вставьте приведенные выше строки кода и запустите функцию play/2
.
К нашему удивлению, он печатает Fizz вместо FizzBuzz на итерации 15.
Что не так с нашим кодом?
Исправление проблем
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end def play(num) when rem(num, 5) == 0 do IO.puts "Buzz" end def play(num) when rem(num, 15) == 0 do IO.puts "FizzBuzz" end def play(num) do IO.puts num end end
Давайте интерпретируем код на 15 итерациях.
Enum.each -- #15 play(15) -- play(15) when rem(15, 3) == 0 do
Выражение rem(15, 3)==0
приведет к true
. Итак, он просто печатает Fizz
и переходит к следующей итерации.
Итак, нам нужно изменить порядок наших функций. Функция play/1
с защитным условием rem(num, 15) == 0
должна быть выше всех остальных функций. Итак, сначала проверяется делимость на 15, затем на 3, а затем на 5.
Давайте обновим код.
defmodule FizzBuzz do def play(min, max) do Enum.each(min..max, fn(num)-> play(num) end ) end def play(num) when rem(num, 15) == 0 do IO.puts "FizzBuzz" end def play(num) when rem(num, 3) == 0 do IO.puts "Fizz" end def play(num) when rem(num, 5) == 0 do IO.puts "Buzz" end def play(num) when rem(num, 15) == 0 do IO.puts "FizzBuzz" end def play(num) do IO.puts num end end
Теперь скопируйте и вставьте приведенные выше строки кода в iex
и запустите функцию FizzBuzz.play 1, 20
.
Ура! Мы закончили логику кода.
Но в названии статьи написано, что нам нужно сделать это в семи (7) строках кода.
Давайте улучшим наш код.
Что еще мы можем улучшить?
Вместо того, чтобы каждый раз копировать вставку в iex
, мы можем создать файл fizz_buzz.ex
и вставить в него код.
Теперь запустите команду
iex fizz_buzz.ex
Вы должны находиться в том же каталоге, где существует файл.
В противном случае вам нужно запустить команду как
iex path/to/file/fizz_buzz.ex
Он загружает модуль в ваш новый iex
сеанс. Вы все еще можете проверить, загружен ли модуль с помощью Code.ensure_loaded FizzBuzz
Изменения в файле fizz_buzz.ex
можно перекомпилировать с помощью r FizzBuzz
. Здесь r
перекомпилирует и перезагружает данный модуль.
Улучшение кода.
Пока что наш код состоит из 20 строк после удаления пустых новых строк.
Теперь нам нужно улучшить наш код, чтобы он выглядел намного лучше, чем раньше.
Замены
В elixir мы можем заменить анонимную функцию fn(num)-> play(num) end
на &(play(&1))
Так что обновите строку
to
Сохраните файл и перекомпилируйте его с r fizz_buzz.ex
Мы можем упростить это, просто передав имя функции с арностью для перебора диапазона в each
Итак, обновим строку
Enum.each(min..max, &(play(&1)))
to
Enum.each(min..max, &play/1)
Теперь сохраните файл с обновлениями, затем перекомпилируйте и протестируйте его. Это все еще работает.
Однострочные функции в Elixir
Если вы четко соблюдаете логику кода, большинство наших определений функций представляют собой одну строку. Таким образом, мы можем избежать do .. end
блоков. Мы можем обновить определения наших функций с помощью do:
однострочного стиля.
#before def play(num) when rem(num, 15) == 0 do IO.puts "FizzBuzz" end #after updating def play(num, 3) when rem(num, 3) == 0, do: IO.puts "FizzBuzz"
Точно так же мы обновим остальные определения функций с помощью базы кода в стиле одной строки.
Вот так это выглядит после обновления
defmodule FizzBuzz do def play(min, max), do: Enum.each(min..max, &play/1) def play(num) when rem(num, 15) == 0, do: IO.puts "FizzBuzz" def play(num) when rem(num, 3) == 0, do: IO.puts "Fizz" def play(num) when rem(num, 5) == 0, do: IO.puts "Buzz" def play(num), do: IO.puts num end
Бум! Мы разработали кодовую логику в 7 строках. Это было здорово с твоей стороны ...
Эта статья изначально размещена в Блоге Ahamtech
Удачного кодирования…