Jump to content
Sign in to follow this  
V3ct0r

[C++] Игра "Угадай число!"

Recommended Posts

[C++] Игра "Угадай число!"

 

picture.png

 

Привет!

 

В данной статье мы напишем на языке программирования C++ простую игру "Угадай число". Компьютер загадывает натуральное число от 1 до 100 включительно, а игрок в свою очередь должен его отгадать. Если игрок назвал неправильное число, то компьютер дает подсказку: загаданное число больше или меньше числа игрока. Игра продолжается до тех пор, пока игрок не отгадает число.

 

Статья предназначена для начинающих программистов. Код будет выполнен в рамках стандарта C++11, автор будет использовать среду разработки Microsoft Visual Studio Community 2017 (скачать). Код должен успешно компилироваться как под Windows, так и под Linux, то есть является кроссплатформенным.

 

У игры очень простой алгоритм:

1) Компьютер "загадывает" случайное натуральное число от 1 до 100 включительно;

2) Игрок вводит предполагаемое число (ответ) с клавиатуры;

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

4) Если числа не равны, то "сказать" пользователю больше его ответ или меньше числа, загаданного компьютером. Перейти на шаг 2;

5) Числа равны. Поздравить игрока с победой и перейти на шаг 1.

 

Приступим к реализации игры.

 

Сначала компьютер загадывает случайное натуральное число от 1 до 100. Для этого используется генератор случайных чисел. Для работы с генератором случайных чисел будем применять 2 функции из стандартной библиотеки: srand() и rand().

 

Функция srand() нужна чтобы задать начало псевдослучайной последовательности чисел, генерируемой функцией rand(). Обычно, в функцию srand() передается текущее системное время. Чтобы получить текущее системное время можно использовать функцию time(). Функция srand() должна вызываться перед вызовом функции rand(), как правило, это делается один раз в начале работы программы. Если этого не сделать, то функция rand() все время будет "отдавать" одинаковые "случайные числа", и наша игра будет загадывать одни и те же числа.

// Запускаем генератор случайных чисел
std::srand(static_cast<unsigned int>(std::time(nullptr)));

Мы инициализировали генератор случайных чисел и теперь можем загадывать число от 1 до 100 с помощью функции rand(). Чтобы загадать очередное число будем использовать следующее выражение:

// Загадываем натуральное число
// от 1 до 100
int n = (std::rand() % 100) + 1;

Функция rand() может возвращать числа от 0 до 32767 включительно. Чтобы преобразовать этот "первичный" интервал в нужный нам интервал от 1 до 100, можно с помощью оператора % взять остаток от деления на 100 у любого числа из первичного интервала и прибавить к нему 1.

 

Например, функция rand() вернула число 256. Остаток от деления на 100 будет равен 56. Прибавляем единицу и получаем число 57, которое и должен будет отгадать игрок:

256 % 100 = 56
56 + 1 = 57

 

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

// Ответ игрока
int guess = 0;

// Просим игрока ввести ответ
std::cout << "Введите число:" << std::endl;
std::cout << ">> ";
std::cin >> guess;

С помощью оператора cin получаем целое число с клавиатуры - ответ игрока, и записываем данное число в переменную guess. Будем спрашивать игрока до тех пор, пока он не отгадает число. Для этого воспользуемся циклом do-while (см. ниже).

 

На данном этапе у нас есть два числа: загаданное компьютером и ответ игрока. Осталось их сравнить. Для сравнения двух чисел воспользуемся оператором if и операторами больше (>) - меньше (<):

// Ответ игрока
int guess = 0;

do
{
	/*
    		Тут получаем предполагаемое число (ответ) от игрока с клавиатуры
	*/
      
	// Проверяем ответ
	if (n > guess) {
		std::cout << "Не угадал! Моё число больше." << std::endl;
	}
	else if (n < guess) {
		std::cout << "Не угадал! Моё число меньше." << std::endl;
	}
} 
while (n != guess);

Если игрок не угадал число, то выводится соответствующее сообщение и цикл повторяется. В случае, если игрок угадал число, цикл прерывается и выводится сообщение о победе:

// Игрок угадал число
std::cout << "Верно! Загадать еще число? (Y/N)" << std::endl;
std::cout << ">> ";
std::cin >> answer;

В конце игры можно просто выйти из программы, а можно спросить игрока, хочет ли он чтобы компьютер загадал еще одно число и тем самым продолжить игру. Для этого поместим написанный выше код в цикл do-while (весь лишний код был заменен на комментарии):

// Ответ на вопрос "Загадать еще число?"
char answer = 0;

// Запускаем генератор случайных чисел
	
// Запускаем игровой цикл
do
{
	// Загадываем натуральное число // от 1 до 100
	do
	{
		// Получаем ответ от игрока
		// Сравниваем ответ игрока с загаднным компьютером числом
	} 
	while (/* игрок не угадал число */);

	// Игрок угадал число
	std::cin >> answer;
} 
while (std::strchr("Nn", answer) == nullptr);

В символьную переменную answer записываем ответ игрока с клавиатуры. Предполагается, что игрок введет символ Y (продолжить игру) или символ N (выйти из игры). Далее с помощью функции strchr() ищем введенный символ в строке "Nn". Таким образом, неважно в каком регистре игрок ввел символ: N или n.

while (std::strchr("Nn", answer) == nullptr);

Если в строке "Nn" не будет найден символ, введенный игроком с клавиатуры, то функция strchr() вернет нулевой указатель (nullptr) и цикл продолжится. Иначе функция вернет указатель на найденный в строке символ и цикл завершится. То есть, если игрок введет символ N или n, то программа завершится. Если он введет любой другой символ, то будет загадано новое число и игра продолжится.

 

После цикла происходит выход из программы - игра закрывается:

return 0;

 

Итак, были отмечены все ключевые особенности реализации варианта игры "Угадай число", поэтому далее приведу полный код программы:

#include <iostream>
#include <limits>
#include <ctime>
#include <cstdlib>


// Точка входа
int main(int argc, char *argv[])
{
	// Ответ на вопрос "Загадать еще число?"
	char answer = 0;

	// Поддержка русского языка
	setlocale(LC_ALL, "Russian");

	// Запускаем генератор случайных чисел
	std::srand(static_cast<unsigned int>(std::time(nullptr)));

	// Выводим правила игры
	std::cout << "Игра \"Угадай число\"" << std::endl;
	std::cout << "Привет! Я загадал число от 1 до 100. Угадай его!" << std::endl << std::endl;

	// Запускаем игровой цикл
	do
	{
		// Загадываем натуральное число
		// от 1 до 100
		int n = (std::rand() % 100) + 1;

		// Ответ игрока
		int guess = 0;
		
		do
		{
			// Просим игрока ввести ответ
			std::cout << "Введите число:" << std::endl;
			std::cout << ">> ";
			std::cin >> guess;

			// Проверим, что пользователь ввел число
			if (std::cin.fail() == true || (guess <= 0 || guess > 100))
			{
				std::cin.clear();
				std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
				std::cout << "Введите натуральное число от 1 до 100!" << std::endl;
				continue;
			}

			// Проверяем ответ
			if (n > guess) {
				std::cout << "Не угадал! Моё число больше." << std::endl;
			}
			else if (n < guess) {
				std::cout << "Не угадал! Моё число меньше." << std::endl;
			}
		} 
		while (n != guess);

		// Игрок угадал число
		std::cout << "Верно! Загадать еще число? (Y/N)" << std::endl;
		std::cout << ">> ";
		std::cin >> answer;
	} 
	while (std::strchr("Nn", answer) == nullptr);

    return 0;
}

 

При желании Вы можете добавить выбор игроком уровня сложности, например:

  • Легкий уровень - загадывается число в интервале от 1 до 100, неограниченное число попыток;
  • Средний уровень -  загадывается число в интервале от 1 до 1000, число попыток 25;
  • Сложный уровень -  загадывается число в интервале от 1 до 10000, число попыток 50.

 

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

<Заработанные очки> = max(0, 100 - <Число ходов>)

Очки хранить в памяти приложения или в файле:

// score.txt
Вася 100
Петя 53
Катя 42
Саша 65

 

Если у Вас есть какие-либо вопросы или замечания, то пишите о них в этой теме!

Share this post


Link to post
Share on other sites
38 minutes ago, Stinger said:

Как насчёт using namespace std; ?

Я привык явно указывать пространство имен, это мой стиль, мне так нравится. Становится понятно, что откуда берется, например, запись std::rand() говорит о том, что я использую функцию rand() из стандартной библиотеки, а не из какой-либо другой. Далее такой пример: у меня есть большой проект, в котором я использую ряд библиотек. Я решил использовать using namespace:

using namespace foo;
using namespace bar;

Из библиотеки foo я использую функцию func1(), а из библиотеки bar - функцию func2(). Все замечательно, все работает. Далее, через какое-то время библиотека foo обновляется и в нее добавляется функция func2() - функция с таким же именем, как и в библиотеке bar. В лучшем случае мой код не скомпилируется, а в худшем, если сигнатуры функций совпадают, это приведет к трудноуловимым багам и ошибкам.

 

Потом есть довольно общие названия различных объектов: string, iterator, list и так далее. Эти имена могут использоваться в разных библиотеках в рамках одного и того же проекта.

 

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

 

Что касается данной темы, то рассматриваемая программа очень простая и к тому же учебная. Поэтому вполне можно использовать using namespace std. Но все же я советую указывать пространство имен явно.

Share this post


Link to post
Share on other sites

Привет, @JustPruss!

 

Вот пример кода:

	// . . .

	// Число ходов
	unsigned int n = 10;

	// Открываем файл moves.txt
	std::ofstream file("moves.txt", std::ofstream::out);

	// Проверим, что при открытии файла не возникли ошибки
	if (file.fail() == true)
	{
		// При открытии файла возникла ошибка
		std::cout << "Не удалось открыть файл moves.txt!" << std::endl;
		return 1;
	}

	// Запишем в файл фразу "Число ходов: ..."
	file << "Число ходов: " << n;

	// Закроем файл
	file.close();

В результате в одной директории с программой будет создан файл "moves.txt" в который будет записано число сделанных ходов (в данном случае 10).

Share this post


Link to post
Share on other sites
4 часа назад, V3ct0r сказал:

Привет, @JustPruss!

 

Вот пример кода:


	// . . .

	// Число ходов
	unsigned int n = 10;

	// Открываем файл moves.txt
	std::ofstream file("moves.txt", std::ofstream::out);

	// Проверим, что при открытии файла не возникли ошибки
	if (file.fail() == true)
	{
		// При открытии файла возникла ошибка
		std::cout << "Не удалось открыть файл moves.txt!" << std::endl;
		return 1;
	}

	// Запишем в файл фразу "Число ходов: ..."
	file << "Число ходов: " << n;

	// Закроем файл
	file.close();

В результате в одной директории с программой будет создан файл "moves.txt" в который будет записано число сделанных ходов (в данном случае 10).

 спасибо большое, очень благодарен за такой пример

 

Share this post


Link to post
Share on other sites

Здравствуйте! Скажите, пожалуйста. А как можно реализовать эту игру в обратном порядке, т.е так , чтобы компьютер отгадывал число задуманное пользователем? Пытался сам, через рандом, но успехов ноль. 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

×
×
  • Create New...