····echo "*** New Game! ***"
··fi
··games="$(($games + 1))"
··guessed=""; guess=""; bad=${1:-6}
··partial="$(echo $match | sed "s/[^$empty${guessed}]/-/g")"
··# В этом блоке производится:
··#·· ввод буквы > анализ > вывод результатов > переход к началу.
··while ["$guess"!= "$match" −a "$guess"!= "quit"]; do
····echo ""
····if [! -z "$guessed"]; then·· #! —z означает "непустое значение".
······/bin/echo −n "guessed: $guessed, "
····fi
····echo "steps from gallows: $bad, word so far: $partial"
····/bin/echo −n "Guess a letter: "
····read guess
····echo ""
····if ["$guess" = "$match"]; then # Угадано!
······echo "You got it!"
····elif ["$guess" = "quit"]; then # Запрошен выход? Хорошо.
······exit 0
····# Теперь нужно проверить присутствие введенной буквы в слове.
····elif [$(echo $guess | wc −c | sed 's/[^[: digit: ]]//g') −ne 2]; then
······echo "Uh oh: You can only guess a single letter at a time"
····elif [! -z "$(echo $guess | sed 's/[[: lower: ]]//g')"]; then
······echo "Uh oh: Please only use lowercase letters for your guesses"
····elif [-z "$(echo $guess | sed "s/[$empty$guessed]//g")"]; then
······echo "Uh oh: You have already tried $guess"
····# Теперь можно проверить присутствие буквы в слове.
····elif ["$(echo $match | sed "s/$guess/-/g")"!= "$match"]; then
······guessed="$guessed$guess"
······partial="$(echo $match | sed "s/[^$empty${guessed}]/-/g")"
······if ["$partial" = "$match"]; then
········echo "** You've been pardoned!! Well done! The word was \"$match\"."
········guess="$match"
······else
········echo "* Great! The letter \"$guess\" appears in the word!"
······fi
····elif [$bad −eq 1]; then
······echo "** Uh oh: you've run out of steps. You're on the platform…"
······echo "** The word you were trying to guess was \"$match\""
······guess="$match"
····else
······echo "* Nope, \"$guess\" does not appear in the word."
······guessed="$guessed$guess"
······bad=$(($bad — 1))
····fi
··done
done
exit 0
Как это работает
Все проверки в этом сценарии достаточно интересны, чтобы исследовать их подробнее. Взгляните на строку , которая проверяет, не ввел ли пользователь больше одного символа.
Почему в сравнении используется число 2, а не 1? Потому что к предложенной пользователем букве в результате нажатия клавиши Enter добавляется символ перевода строки (\n). То есть правильно, когда строка содержит два символа, а не один. Команда sed в этой инструкции отбрасывает все нецифровые символы, чтобы исключить любые проблемы с начальными символами табуляции, которые так любит добавлять команда wc.
Проверка принадлежности к нижнему регистру в строке проста и понятна. Здесь удаляются все буквы нижнего регистра, и результат проверяется на равенство пустой строке.
Наконец, чтобы увидеть, предлагал ли уже пользователь эту букву: содержимое guess преобразуется так, что из него удаляются все буквы, присутствующие в переменной guessed. Затем проверяется, получилась ли в результате пустая строка .
Кроме всех этих проверок в сценарии hangman используется еще одна хитрость: в исходном слове все буквы, совпадающие с введенной, заменяются дефисами. Затем результат сравнивается с исходным словом . Если они различаются (то есть если одна или несколько букв заменены дефисами), значит, предложенная пользователем буква есть в слове. Например, если для загаданного слова cat пользователь ввел букву a, она будет записана в переменную guessed, которая получит значение '-a-'.
Одна из ключевых идей, лежащих в основе сценария hangman, — вывод частично угаданного слова из переменной partial, значение которой повторно собирается с каждой угаданной буквой. Поскольку в переменной guessed накапливаются буквы, угаданные игроком, команда sed преобразует в дефисы все буквы в исходном слове, которые отсутствуют в строке guessed .
Запуск сценария
Игра «виселица» принимает один необязательный аргумент: переданное ей число используется как максимально допустимое число ошибочных попыток, в противном случае их будет шесть (значение по умолчанию). В листинге 12.4 демонстрируется пример запуска сценария hangman без аргументов.
Результаты
Листинг 12.4. Сеанс игры «виселица»
$ hangman
steps from gallows: 6, word so far: —-
Guess a letter: e
* Great! The letter "e" appears in the word!