Rubyrush: задачки на закрепление урока по циклам

Ruby для новичков [Rubyrush]

Вчера проходил циклы. было прикольно! Сегодня надо закрепить на практике и решить несколько задачек в рамках курса Rubyrush. Судя по названиям шагов, сейчас будут четыре задачи по циклам.

Что ж посмотрим что там ребята подготовили.

Rubyrush: задачки на закрепление урока по циклам
Задачи на закрепление темы: Циклы в Ruby.

Задача №1: Массив из N элементов и сумма

Условия задачи

Написать программу, которая выводит массив чисел от 1 до N. И выводит сумму всех чисел этого массива. Число N спрашивается у пользователя из консоли.

Как я решил задачу

Честно сказать — я долго мудохался с решением. Во первых я натупил с именами переменных и по привычки проставил двойное нижнее тире между словами в именах переменных (Видимо привычка из за вёрстки сайтов. я там классы по BEM задаю и всегда двойное нижнее подчёркивание).

Потом я заметил опечатки и исправил их, но это не помогло и программа работала не так как я задумал. Второй ошибкой новичка был косяк с отсутствующим выражением do в цикле while. Это все моя невнимательность, блин. Кстати, из за этой ошибки мой цикл работал не как цикл, а как разовое выражение — без повтора. Это интересный факт 🙂

Третья ошибка заключалась в том, что мне нужно было запрограммировать рассчитывать сумму всех элементов массива. Как было написано в подсказке, мне надо было внутри цикла это прописать и я прописал, да вот тока не так! я написал выражение:

Rubyrush: задачки на закрепление урока по циклам
Ошибка в программе при ращении задачи на массивы.

А надо было суммировать и перезаписать! А я просто суммировал!

Rubyrush: задачки на закрепление урока по циклам
Правильное решение для сложения элементов массива!

В итоге моя программка получилась что надо!

# Массив чисел. изначально он пуст
numbers = []
# элемент массива. изначально он равен нулю, что бы при первой итерации получилась единичка
numbers_item = 0
# сумма чисел - элементов массива
numbers_sum = 0

# Спросив у пользователя N
# и преобразовав его в число с помощью to_i
puts "Сколько чисел вы хотели бы задать?"
quantity = gets.chomp.to_i

# организовать цикл while на N итераций
while numbers.length < quantity do
  puts "Новая итерация"
  numbers_item += 1
  numbers_sum += numbers_item.to_i
  numbers << numbers_item
  
end

puts "Итого массив: " + numbers.to_s
puts "Итого сумма: " + numbers_sum.to_s

Сейчас буду смотреть как написали ребята в готовом решении и сравню код.

Ответ из курса с решением

# Объявили пустой массив
array = []

# Спрашивает у пользователя длину массива и записываем ее в number
puts 'Введите N'
number = gets.to_i

# Создадим переменную-счетчик итераций в цикле. Сначала он будет равен 1, так
# как числа в массиве должны быть от 1 до N.
index = 1

# Переменная, в которую будет накапливать сумму всех чисел
summa = 0

# Нам нужно N (number) чисел, значит нам нужно ровно number число итераций
while index <= number do
  # Записываем очередное число в массив
  array << index

  # Увеличиваем сумму
  summa += index

  # Увеличиваем счетчик для следующей итерации
  index += 1
end

# Выводим получившийся массив и сумму его чисел
puts array.to_s
puts 'Сумма чисел: ' + summa.to_s

Ну однозначно другой подход к решению задачки и это круто.

У них входящие данные не обрезают пробел. Видимо потому что для чисел это не так критично.

Rubyrush: задачки на закрепление урока по циклам

Счётчик элементов массива у них начинается с единички, и в условиях цикла while проверка на меньше или равно, а у меня счётчик с нуля начинается и проверка только на то что бы был меньше:

Rubyrush: задачки на закрепление урока по циклам

Тем не менее у меня работает все чётко, так же как у ребят в решении. Разве что короче все написано и понятней. Но моё решение тоже ГУД!

Выводы по итогу выполнения задачи

Массивы я пока плохо применяю. Долго думаю. Если и в следующей задачке буду так тупить — пойду переучивать и читать книжки по этой теме.

Задача №2: Максимальное из произвольных

Условия задачи

Объявите в программе пустой массив. Спросите у пользователя какой длины должен быть массив.

Запомните выбор пользователя и наполните массив нужным количеством случайных чисел. Числа должны быть в диапазоне от 0 до 100 (вспомните метод rand из прошлых задач). Выведите получившийся массив на экран.

После вывода массива найдите в нем максимальный по величине элемент и выведите на экран его значение.

Например:

Какой длины будет массив случайных чисел?
> 9
[55, 19, 54, 41, 74, 94, 87, 85, 49]
Самое большое число:
94

Моё решение задачи

# объявляю пустой массив
array = []
# элемент массива. изначально он равен нулю, что бы при первой итерации получилась единичка
array_item = 0

# сумма чисел - элементов массива
number = 0

# Задаю вопрос пользователю
puts "Человек, какой длинны должен быть этот грёбанный массив?"
# ну и сохраняю хотелку в переменную + обрезаю пробел и явно указываю тип объекта - число!
quantity = gets.chomp.to_i
# затем создаю цикл для наполнения массива случайными числами
while array.length < quantity do
  number = rand(100)
  array << number
end

puts "Итого массив: " + array.to_s
puts "Максимальное число в массиве: " + (array.max).to_s

Вторая задачка поддалась легче, только по двум причинам:

  1. я использовал часть кода из предыдущей задачи,
  2. я погуглил в интернетах, как найти максимальное число в массиве и тут, как оказалось, есть замечательные спец. методы max и min.

По сути это чит какой то, потмоу что в подсказке к уроку говорилось о том, что нужно использовать ДВА цикла, а я применил тока один, а на втором этапе работы программы просто использовал метод max.

Давайте посмотрим готовый ответ из урока. Там наверняка оба цикла и ребята как то хитро перебрасывают элементы массива при сравнении между собой.

Эталонное решение из урока

Внутри первого цикла они сделали лучше, так как не пришлось сначала объявлять переменную, а потом сохранять в неё случайное число, что бы присвоить это число массиву. У них всё проще.

Rubyrush: задачки на закрепление урока по циклам

Ну а у меня круче написан момент со счётчиком элементов. у них количество итераций сравнивается с введённым числом пользователя и в конце каждой итерации увеличивается на единицу.
а у меня сравнивается количество элементов в массиве с числом пользователя. и тоже работает. Прикол!

Rubyrush: задачки на закрепление урока по циклам

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

Затем пишут цикл, по условиям которого мы сравниваем значение переменной «Максимальное число» с элементом массива.

если максимальное число меньше текущего элемента массива, то значение переменной «Максимальное число» перезаписывается на значение равное текущему элементу.

По итогу работы цикла значение будет равно максимальному числу из массива.

Rubyrush: задачки на закрепление урока по циклам
Поиск наибольшего числа в массиве без использования метода max.

Решение авторов курса

# Объявили пустой массив
array = []

puts 'Какой длины будет массив случайных чисел?'
number = gets.to_i

index = 0

# Цикл должен сделать ровно number число итераций
while index < number do
  # Записываем произвольное число от 0 до 100 в массив
  array << rand(100)

  index += 1
end

# Выводим получившийся массив
puts array.to_s

# Объявляем переменную которая будет хранить максимальное найденное
# в массиве значение
max_value = 0

# Пробегаем по нашему массиву и ищем самое большое число
for item in array do
  # Если текущий элемент больше максимального значения то записываем значение
  # этого элемента в качестве нового максимального значения
  if item > max_value
    max_value = item
  end
end

# В итоге в max_value останется наибольшее из просмотренных в массиве чисел
puts 'Самое большое число:'
puts max_value.to_s

Круто, блин! Я тупанул и включили читы. Ну ничего. теперь я понял как это работает. Продолжаем обучение и на очереди третья задачка по циклам.

Задача №3: Проверка ввода пользователя

Условия задачи

Возьмите вашу игру, которую вы сделали в домашнем задании к уроку про «южное бутово» (если не делали — самое время сделать). В этой игре теперь защитите программу от неправильного ввода вариантов.

То есть если программа просит выбрать 1. ... 2. ... 3. ..., а пользователь вводит 7 или вообще посторонние символы, то программа повторяет свой вопрос и не продолжается пока не будет введен один из доступных вариантов.

Моё решение задачи

Как я писал ранее, я сделал мини игру про прогулку в лесу и встречу с монстром. Она была довольно прикольной. Собственно в ней и буду вносить доработки.

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

Теперь, когда я узнал как можно проверять входящие данные на истину или ложь, необходимость в этом варианте отпала, но уж больно он мне понравился. Так по русски 🙂 Так что пусть будет.

Все блоки кода в которых мы принимаем входящие данные и предлагаем варианты на выбор я обернул в цикл until в условиях цикла я прописал, что цикл работает до тех пор, пока значение переменной не будет соответствовать одному из существующих вариантов:

skill = nil
# проверяем что ввёл пользователь
until skill == "1" || skill == "2" || skill == "3" do
   puts "#{name}, выбери способность"
   puts "1. Силач"
   puts "2. Ловкач"
   puts "3. Распиздяй"
   skill = gets.chomp
end

Как только проверка вернёт нам true — цикл завершится.

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

Теперь игра стала еще лучше, а я завершил очередное задание.

справедливости ради я хочу уточнить, что подсмотрел решение и самостоятельно не смог придумать, как это реализовать.

Но после того как я подсмотрел — разобрал и смог повторить на практике в своей игре. Я отлично понял как работает цикл, так что будем считать что справился. А то я так до нового года курс не пройду 🙂

Кстати, моя игра лежит на Github. Если интересно — посмотрите её.

Задача № 4: Инвертирование массива циклом

Условия задания

Напишите программу, которая перевернет порядок элементов любого исходного массива. Переверните массив сами с помощью цикла.

Не используя встроенные методы reverse или reverse!

Например:

Исходный массив:
[1, 2, 3, 4, 5, 6, 7]
Новый массив, полученный из исходного:
[7, 6, 5, 4, 3, 2, 1]

Моё решение задачи

Так как по условиям задачи я не мог использовать методы reverse, и я тока начинаю программировать, решил не заморачиваться и действовать крайне логично и последовательно:

  1. взять последний элемент в массиве start: item = start[-1]
  2. и сохранить его в массив finish: finish << item
  3. а затем удалить последний элемент в массиве: start.delete_at(-1)
  4. и так до тех пор пока в массиве start есть элементы: while start.length > 0 do
start = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
finish =[]

while start.length > 0 do
  item = start[-1]
  finish <<  item
  start.delete_at(-1)
end

puts "исходный массив" + start.to_s
puts "итоговый массив" + finish.to_s
Rubyrush: задачки на закрепление урока по циклам
В результате работы цикла ВСЕ элементы в первом массиве поочерёдно переносятся в новый массив в обратном порядке.

Готовое решение от Rubyrush

В подсказке и примере решения задачи даётся более простой вариант решения поставленной задачи — мы просто проходимся по исходному массиву и сохраняем каждый элемент не в конец, а в начало итогового массива. Для этого они используют метод unshift.

Вот как выглядит их решение:

# Записываем массив в переменную numbers и выводим его на экран
numbers = [1, 2, 3, 4, 5, 6, 7]
puts 'Исходный массив:'
puts numbers.to_s

# Создадим новый массив (пока пустой), куда будем класть элементы исходного в
# обратном порядке
reverse_numbers = []

# Проходим в цикле по исходному массиву numbers
for item in numbers do
  # И добавляем каждый элемент в начало нового массива методом unshift (добавить
  # в начало)
  reverse_numbers.unshift(item)
end

# Осталось вывести полученный массив на экран
puts 'Новый массив, полученный из исходного:'
puts reverse_numbers.to_s

В сравнении с моим вариантом решения, их решение короче и понятней читается. Но и мой вариант не плох. Так что заслуживает право на существование в арсенале 😉

Новые методы и инструменты

  • max и min — узнал про отличные методы получения наибольшего и наименьшего числа в массиве.
  • rand — попробовал генерацию случайных чисел и это круто!
  • #{...} — узнал что при использовании интерполяции содержимое приводится к типу СТРОКА, тем самым нам не нужно лишний раз применять к числам метод явного приведения типов to_s.
  • if без else — оказывается что можно использовать if без else. В таком случае, если сработает условие — выполнится запрограммированное событие или программа минует этот блок кода и продолжит свою работу.
  • until — оказывается бывает не два вида циклов, а ЧЕТЫРЕ: while, if, unless и until. Until- это альтернатива циклу while. Он выполняется до тех пор, пока условие цикла не вернёт истину. А unless — противоположность if. Выполняется только если условие — ложное.
  • += — можно одновременно складывать и переопределять значение переменной. Это что то типа сокращённой записи.
  • unshift — данный метод получает набор значений и помещает их в начало массива, при этом имеющиеся в массиве элементы сдвигаются в право, то есть их левосторонние индексы увеличиваются.
Юрий Ронин