Можете ли вы сделать то, что вы спрашиваете;возможно, однако вы заявили, что создаете игру Hangman на C ++, и я думаю, что вы делаете это с неправильным подходом, поэтому выбираете или реализуете неправильные алгоритмы. Вы пытаетесь пройти через две строки с возможной различной длиной от серверной части, что, если это не сделано правильно, может привести к проблемам, будет трудно отследить, особенно если их сравнения определяют условия цикла, операторы выхода или возврата.
Я реализовал свою версию «Палача», но теперь форматирование не самое красивое и словари уровней не генерируются из большого количества случайных слов. Я выражаю это в комментариях к коду, которые обычно читаются из текстового файла и сохраняются в этих структурах. Для простоты я инициализировал их случайными словами прямо в коде.
Посмотрите, что я сделал:
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <random>
class Game;
int main() {
using namespace util;
try {
Game game("Hangman");
game.start();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
class Game {
private:
std::string title_;
bool is_running_{ false };
std::string answer_;
std::string guessed_;
std::map<unsigned, std::vector<std::string>> dictionary_; // unsigned represents difficulty level of word
unsigned choosen_difficulty_;
std::string guessed_characters_{"\n"};
public:
Game(const std::string& title) : title_{ title }, choosen_difficulty_{ 0 } {
initialize();
start_over();
}
void start() {
is_running_ = true;
// the player has as many attempts as twice the length of hidden answer's word length.
int number_tries = answer_.size() * 2;
while (is_running_ || number_tries > 0) {
displayGuessedWord();
displayGuessedCharacters();
// ask the player to guess a character;
char guess;
// get a character and make sure it is a valid alphabet character
do {
std::cout << "Guess a character ";
std::cin >> guess;
// Note: I'm using ascii characters in this case
// but for demonstration purposes only!
if ((guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z')) {
std::cout << "invalid entry ";
}
} while ( (guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z') );
// test character and update guessed word and number of tries.
test_character(guess);
update_guessed_characters(guess);
number_tries--;
// failed condition
if (number_tries <= 0 && guessed_ != answer_) {
std::cout << "\nGame Over!\n";
is_running_ = try_again(number_tries);
// winning condition
} else if (number_tries > 0 && guessed_ == answer_) {
std::cout << "\nCongratulations!\n";
is_running_ = try_again(number_tries);
}
if (!is_running_) break;
}
}
private:
void displayGuessedWord() {
std::cout << '\n' << guessed_ << '\n';
}
void displayGuessedCharacters() {
std::cout << guessed_characters_ << '\n';
}
void initialize() {
// Normally this would be read in from a file upon game initialization
// but for demonstration purpose, I'll generate a few small vectors of strings
// and associate them to their difficulty level
// levels are based on 3 factors, the length of the word, the repetitive occurance
// of common characters, and the amount of less commonly used characters.
std::vector<std::string> level_1{ "ate", "cat", "dog", "coat", "coal", "does" };
std::vector<std::string> level_2{ "able", "believe", "balloon", "better", "funny", "happy" };
std::vector<std::string> level_3{ "ability", "carpenter", "dogmatic", "hilarious", "generosity", "hostility" };
// ... etc. I'll use just these here for simplicty where each vector has six entries, however,
// with random number generators, this can be done generically for any size
// or number of elements in each of the different vectors.
// create generate the map:
dictionary_[1] = level_1;
dictionary_[2] = level_2;
dictionary_[3] = level_3;
}
std::string getWordFromDictionary(unsigned difficulty, std::map<unsigned, std::vector<std::string>>& dict) {
auto level = dict[difficulty]; // extract the vector based on difficulty level
auto size = level.size(); // get the size of that vector
std::random_device dev; // create a random device
std::mt19937 rng(dev()); // create a pseudo random generator
// create a uniform int distribution type with the range from 0 to size-1
std::uniform_int_distribution<std::mt19937::result_type> dist(0, size - 1);
return level[dist(rng)]; // return a random string from this level.
}
void start_over() {
system("cls"); // Note: I'm running visual studio on Windows!
std::cout << "Welcome to " << title_ << '\n';
// We can use a random generator to pick a word from the given difficulty
// but first we need to get user input for the chosen level.
do {
std::cout << "Choose your difficulty [1-3]\n";
std::cin >> choosen_difficulty_;
if (choosen_difficulty_ < 1 || choosen_difficulty_ > 3) {
std::cout << "Invalid entry:\n";
}
} while (choosen_difficulty_ < 1 || choosen_difficulty_ > 3);
answer_ = getWordFromDictionary(choosen_difficulty_, dictionary_);
// clear and resize guessed word to be that of answer_ and add bunch of hypens.
guessed_.clear();
guessed_.resize(answer_.size(), '-');
// also reset the guessed_characters
guessed_characters_ = std::string("\n");
}
bool try_again(int& tries) {
std::cout << "Would you like to try again?\n";
char c;
std::cin >> c;
if (c == 'y' || c == 'Y') {
start_over();
// don't forget to update this so that the loop can repeat
tries = answer_.size() * 2;
return true;
}
else {
std::cout << "Thank you for playing " << title_ << '\n';
return false;
}
}
void test_character(const char c) {
// here is where you would use the standard library for taking the character
// passed into this function, updating the guessed_characters
// get all indexes
std::vector<unsigned> locations;
for (unsigned i = 0; i < answer_.size(); i++)
if (answer_[i] == c)
locations.push_back(i);
// now update the guessed word
if ( locations.size() > 0 )
for (size_t n = 0; n < locations.size(); n++)
guessed_[locations[n]] = c;
}
void update_guessed_characters(const char c) {
guessed_characters_.insert(0, &c); // just push to the front
}
};
Если вы заметиликак я структурировал игровой класс выше;Я использую циклы while и do-while вместе с циклами for и if-операторов и одним логическим флагом для определения состояния игры. Состояние игры также определяется по обновлению угаданных персонажей и угаданного слова. Тогда я сравниваю это с ответом. В зависимости от определенных условий цикл продолжит искать ввод от пользователя или завершится.
Я не гарантирую, что этот код не содержит ошибок на 100%, поскольку я не проводил тщательного тестирования или проверки угловых случаев или особых случаев, но код работал без ошибок, и я протестировал все основные игрыгосударственные дела. Кажется, он работает нормально.
Я знаю, что можно было бы сделать много улучшений и упрощений, если бы я решил использовать некоторые стандартные библиотечные функции для работы со строками, но я хотел проиллюстрировать отдельные шаги, которыеучаствуют в процессе разработки или мышления, создавая игру с состояниями и их переходами. Я мог бы также поместить объявление класса игры в его собственный заголовочный файл с его реализацией в файле cpp, но я оставил его как отдельный класс, который показан в main.cpp для простого копирования, вставки и компиляции.
В этой конкретной игре я не использовал операторы switch и case, я просто придерживался некоторых циклов while и do-while, нескольких циклов for и операторов if, поскольку в игре только несколько состояний и состояний. переходы, чтобы беспокоиться о. Эта реализация также демонстрирует задействованные алгоритмы и показывает, как они связаны друг с другом. Я надеюсь, что это поможет вам лучше понять процесс проектирования.
При создании игры с различными состояниями, имеющей небольшую сложность, вы должны сначала создать свою таблицу состояний и перечислить все ее переходы, прежде чем даже писать какой-либо код. Затем вы должны указать свои стартовые, продолжающиеся, выигрышные, неудачные и выходящие состояния или дела. Затем вам необходимо составить план перехода из одного состояния в другое в соответствии с необходимыми условиями. Это поможет вам в долгосрочной перспективе!
Как только у вас будет правильно выстроено игровое состояние и его переходы, вы можете начать выполнять необходимые функции для этих состояний и начать соединять их вместе. После этого вы должны написать внутреннюю часть функций или их реализацию того, что они будут делать.
И, наконец, после того, как у вас возникнет недостаток, вы захотите провести некоторую отладку и модульное тестирование, и если все будет хорошо, тогда будет безопасно улучшить ваши текущие алгоритмы или выбрать лучшие для пикаили наиболее эффективное исполнение.