# В этом файле мы объявим все методы, которые мы используем в игре «Виселица»

# Метод cls, очищающий экран, вызывает системную команду. В Mac OS/Linux —
# clear, в Windows — cls. Оператор || тут необходим на случай, если первый вызов
# пройдет неудачно (например, такой команды нет, как, например и, команды 'cls'
# на Linux). Если первый system вернет false будет вызвана другая команда.
def cls
  system('cls') || system('clear')
end

# Метод get_letters возвращает массив букв загаданного слова, которое было
# передано программе в консоли в качестве параметра.
def get_letters
  # Берем загаданное слово из командной строки
  slovo = ARGV[0]

  # Если при запуске программы не указали слово для отгадывания, мы не можем
  # продолжать игру, вылетаем с ошибкой
  if slovo == nil || slovo == ''
    abort 'Для игры введите загаданное слово в качестве аргумента при ' \
      'запуске программы'
  end

  # Разбиваем слово на буквы специальным методом split, который есть у всех
  # объектов класса Строка.
  #
  # Этот метод на вход принимает другую строку (разделитель) и разбивает
  # исходную на массив строк с указанными разделителем. Если в качестве
  # разделитея передать пустую строку (""), метод разобьет строку на символы.
  #
  # А метод encode('UTF-8') переводит строку в кодировку UTF-8.
  return slovo.encode('UTF-8').split('')
end

# Метод get_user_input занимается лишь тем, что спрашивает у пользователя,
# какую букву он хочет попробовать в качестве следующего хода.
def get_user_input
  # Чтобы цикл сработал хотя бы один раз, нужно записать в переменную letter
  # пустую строку.
  letter = ''

  # В цикле будем опрашивать юзера, пока он не введет что-нибудь
  while letter == ''
    # Спрашиваем у пользователя букву в консоли. Обратите внимание, что вместо
    # gets надо использовать STDIN.gets — особенность руби при использования
    # аргументов в командной строке (массива ARGV).
    letter = STDIN.gets.encode('UTF-8').chomp
  end

  # Возвращаем полученную от пользователя букву
  return letter
end

# Метод check_result проверяет введенную пользователем букву и кладет её в один
# из двух массивов — с «хорошими» буквами, которые есть в слове, и «плохими»,
# которых в слове нет.
#
# К тому же, нам очень важен результат, которые вернет этот метод. Мы
# договорились, что он возвращает
#
#  0 — если буква есть в слове (или уже была названа) и игра продолжается
# -1 — если введенной буквы нет в слове
#  1 — если всё слово угадано целиком
#
def check_result(user_input, letters, good_letters, bad_letters)
  # Если введенная буква уже есть в списке «хороших» или «плохих» сходу
  # вернем 0, так как ничего не изменилось, игра продолжится.
  if good_letters.include?(user_input) || bad_letters.include?(user_input)
    return 0
  end

  if letters.include? user_input
    # Если в слове есть буква запишем её в массив «хороших» букв
    good_letters << user_input

    # После этого слово может быть отгадано полностью (если это была последняя
    # неотгаданная буква). Поэтому делаем дополнительную проверку — угадано ли
    # на этой букве все слово целиком.
    #
    # Метод sort сортирует массив. В случае, если в массиве строки, он сортирует
    # их по алфавиту.
    #
    # https://ruby-doc.org/core-2.4.0/Array.html#method-i-sort
    #
    # Метод uniq, вызванный у массива, возвращает массив, но без дублированных
    # элементов. Если какая-то буква встречается в слове дважды, нам надо её
    # убрать.
    #
    # https://ruby-doc.org/core-2.4.0/Array.html#method-i-uniq
    #
    # Таким образом, letters.uniq.sort содержит все уникальные буквы слова в
    # алфавитном порядке. Например, если слово было «молоко», то массив будет
    # такой: ["к", "л", "м", "о"].
    if good_letters.uniq.sort == letters.uniq.sort
      # Если буквы в получившемся массиве совпадают с буквами в массиве
      # отгаданных букв (отсортированном), то это означает, что слово отгадано
      # полностью.
      return 1
    else
      # Иначе, игра продолжается. Мы отгадали букву, но не слово.
      return 0
    end
  else
    # Если в слове нет введенной буквы мы добавляем её в массив «плохих» букв и
    # возвращаем -1, чтобы основная программа поняла, что пользователь ошибся.
    bad_letters << user_input
    return -1
  end
end

# Метод get_word_for_print возвращает нам загаданное слово для вывода на экран:
# если буква отгадана, она отображается, иначе вместо неё отображаются
# подчеркивания.
#
# Например, если слово было «молоко» и отгадали буквы «о» и «к», то метод должен
# вернуть строку "__ о __ о к о".
def get_word_for_print(letters, good_letters)
  # Создадим переменную result, в которую будем «собирать» информацию для вывода
  result = ''

  # Проходимся по буквам загаданного слова (массив letters)
  for item in letters do
    if good_letters.include?(item)
      # Если эта буква уже отгадана (она есть в массиве «хороших» букв), она
      # будет отображена как есть. После неё также добавим пробел. Для красоты.
      result += item + ' '
    else
      # Если нету, вместо нее будет отображен прочерк. Ну и пробел.
      result += '__ '
    end
  end

  # Возвращаем получившуюся строку.
  return result
end

# Метод print_status выводит на экран текущий статус игры. В качестве входных
# параметром ему нужна все доступная информация об игре: массив загаданного
# слова, массивы «хороших» и «плохих» букв и общее число сделанных ошибок.
def print_status(letters, good_letters, bad_letters, errors)
  # Выводим слово с прочерками вместо не отгаданных ещё букв с помощью
  # метода get_work_for_print.
  puts "\nСлово: #{get_word_for_print(letters, good_letters)}"

  # Выводим «плохие» буквы и количество ошибок. Используем метод join, чтобы
  # «склеить» буквы вместе, добавив между ними запятую и пробел.
  #
  # https://ruby-doc.org/core-2.4.0/Array.html#method-i-join
  puts "Ошибки (#{errors}): #{bad_letters.join(', ')}"

  if errors >= 7
    # Если ошибок 7 или больше, пишем пользователю, что он проиграл
    puts 'Вы проиграли :('
  else
    # Если ещё нет, то проверяем результат уже известным нам способом
    if good_letters.uniq.sort == letters.uniq.sort
      # Если все буквым были отгаданы, поздравляем пользователя с победой
      puts "Поздравляем, вы выиграли!\n\n"
    else
      # Если нет — пишем, сколько раз пользователь ещё может ошибиться
      puts 'У вас осталось попыток: ' + (7 - errors).to_s
    end
  end
end
