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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×