Skip to content

Instantly share code, notes, and snippets.

@Asenim
Created November 27, 2024 20:34
Show Gist options
  • Save Asenim/405872a2012b613c944ccf87d2828cfc to your computer and use it in GitHub Desktop.
Save Asenim/405872a2012b613c944ccf87d2828cfc to your computer and use it in GitHub Desktop.

https://github.com/IT-DO/Hangman
Ревью от Алексея @Raketa4000az
[Anton K]

Простая реализация в процедурном стиле, выполнена в одном классе.

Недостатки реализации:

  1. Команды работают неправильно
Хотите сыграть в игру "Виселица" . . . ?
Для начала игры введите: 1 + Enter
Для выхода из игры введите: 0 + Enter
123
Приветствуем Вас в игре Виселица. Цель игры: угадать слово, вводя по одной букве за шаг.
  1. На старте не видно виселицы
  2. Вместо одиночной буквы можно ввести целое слово и игра ее примет
  3. Вместо буквы можно ввести цифру 1 и игра ее примет
Буквы, которые вы уже ввели: [1]
  1. Одну и ту же букву можно ввести несколько раз и игра ее примет, а потом даже правильную букву посчитает неправильной
Введите предполагаемую букву и нажмите Enter.
ф

Есть такая буква!

<тут картинка виселицы>
Загаданное слово: Ф***
Количество оставшихся попыток: 5
Буквы, которые вы уже ввели: [Ф]

Введите предполагаемую букву и нажмите Enter. 
Ф
Мимо! Попробуйте еще...
<тут картинка виселицы>

Загаданное слово: Ф***
Количество оставшихся попыток: 4
Буквы, которые вы уже ввели: [Ф, Ф]
  1. Совершенно ацкое пустое пространство в середине строки
Введите предполагаемую букву и нажмите Enter.                                                          Подсказка: Если хотите начать новый раунд, введите 0 + Enter
  1. При проигрыше в конце ресует пустую виселицу
Буквы, которые вы уже ввели: [А, А, Б, Ф, Ф]

Вы проиграли! Допущено слишком много ошибок.

Загаданное слово: ФЛЕШ

_____________
|           |
|           
|          
|          
|
‾‾‾‾‾‾‾‾‾‾‾‾‾
Хотите сыграть в игру "Виселица" . . . ?

Хорошо:

  1. Игра запускается
  2. Есть список ранее введенных букв. Да, работает неправильно, но он есть
  3. Возможность досрочно выйти из раунда
  4. Нейминг
  5. Широкое использование констант
  6. Простой понятный алгоритм

Замечания:

  1. Нейминг -Это не массив
ArrayList<String> array = new ArrayList<>();

-Название вводит в заблуждение. Метод не проверяет состояние, он его сообщает

String checkGameState(int mistakes)

--
Oracle Java code conventions, part."Naming conventions"
Мартин, "Чистый код", гл.2
-- 
  1. Комментарии -Коментарии тут в основном не несут полезной нагрузки, а констатируют очевидное
//точка входа в приложение
public static void main(String[] args)

//вывод виселицы в консоль
static void printHangman(int mistakes)

//пользовательское меню
static void menu()

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

-Комментарии, которые можно вообще не заметить. Один из них находится на расстоянии 14 сантиметров правее строки, которую комментирует. Какая цель существования этого комментария- чтобы его увидели или нет?

---
Мартин, "ЧК", гл.4
---
  1. Нарушение инкапсуляции, здесь ее у методов просто нет. Всегда явно указывай область видимости. В этой реализации публичным должен только метод main().

  2. Нарушение DRY, магические буквы, числа, слова. Вводи константы

if (input == '1') {
  //...
} else if (input == '0') {
  //...
}

//ПРАВИЛЬНО:
private final static char PLAY = '1';
private final static char QUIT = '0';

private static final String MAIN_MENU_QUESTION = "Хотите сыграть в игру \"Виселица\" . . . ?\nДля начала игры введите: %c + Enter\nДля выхода из игры введите: %c + Enter"
      .formatted(PLAY, QUIT);

if (input == PLAY) {
  //...
} else if (input == QUIT) {
  //...
}

--
Фаулер, "Рефакторинг", гл.8 п."Замена магического числа символической константой"
refactoring.guru "Замена магического числа символьной константой"
--
  1. Если в блоке if есть return(break, continue, throw, exit и т.д.), то else не пишется - это не имеет смысла
if (inputValidation(c)) {
  return c;
} else {
  System.out.println("Проверьте язык ввода, у нас только русские слова! ;)");
  //...
}

//ПРАВИЛЬНО:
if (inputValidation(c)) {
  return c;
} 
System.out.println("Проверьте язык ввода, у нас только русские слова! ;)");
  1. Используй классы через их интерфейсы
ArrayList<String> createDictionary() {...}
ArrayList<String> array = new ArrayList<>();

//ПРАВИЛЬНО:
List<String> createDictionary() {...}
List<String> array = new ArrayList<>();
  1. Рекурсия должна использоваться только там, где она оптимальна алгоритмически. Например при обходе дерева и как его частный случай- нахождения пути в Симуляции в BFS. В других ситуациях, где рекурсия может быть замененена циклом, она должна быть им замененена. Рекурсия тяжело читается и при определенных условиях может привести к переполнению стека
static void menu() {
  //...
  menu();
  //...
}

Убери рекурсию, замени ее использование на цикл while()

  1. Если нужно печатать текст с более, чем одним подстановочным значением или значение вставляется внутрь сообщения, используй форматированный вывод - тогда ты сразу будешь видеть шаблон.
System.out.println("Загаданное слово: " + maskWord.toUpperCase() + "\nКоличество оставшихся попыток: "
  + mistakes + "\nБуквы, которые вы уже ввели: " + userLetterSet.toString().toUpperCase() + "\n");

//ПРАВИЛЬНО:
System.out.printf("Загаданное слово: %s \nКоличество оставшихся попыток: %d \nБуквы, которые вы уже ввели: %s \n",
   maskWord.toUpperCase(), mistakes, userLetterSet.toString().toUpperCase());
  1. Нужно разделить валидацию для ввода букв и для ввода команд
public static boolean inputValidation(char userInput) {
  String regex = "[а-яА-ЯёЁ0-1]";
  return Pattern.matches(regex, String.valueOf(userInput));
}

Вывод: в целом для процедурного стиля не так плохо.

#ревью #виселица

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment