Игра Угадай число на С++

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 месяц, 3 нед. назад.

  • Автор
    Сообщения
  • #5502
    @admin

    После того, как освоены уроки по С++, неплохо бы написать небольшую игру. Игра будет следующей — компьютер загадывает число в диапазоне, заданном пользователем. Пользователь пытается угадать число, при этом компьютер сообщает больше загаданное число или меньше. Кроме того, программа выводит минимальное количество шагов, за которое можно было отгадать. И конечно же предлагает сыграть еще.

    Выглядит просто, но, как всегда есть куча подводных камней. Как бы мы хотели видеть функцию main? — примерно так:

    int main() {
      int from, to;
      
      srand(time(NULL));
      
      while (true) {
        if (false == need_play())
          break;
        
        get_range(from, to);
        
        game(from, to);
      }
    }

    С этого всегда стоит начинать, чтобы код программы получился читабельным.

    Нам многократно потребуется запрашивать у пользователя целое число, выводя перед этим некоторое пояснение. Напишем такую функцию:

    int get_int(const string& text) {
      int value;
      cout << text;
      cin >> value;
      return value;
    }

    Очевидно, нам потребуется генерировать случайное число в диапазоне — по ссылке нужно взять функцию rand_between. Функция эта работает корректно только если нижняя граница диапазоне меньше верхней, проверку этого стоит вынести отдельно: (кстати, приведенная функция — прекрасный пример цикла с постусловием, который таки нечасто используется)

    void get_range(int& from, int& to) {
      do {
        from = get_int("from: ");
        to = get_int("to: ");
      } while (from >= to);
    }

    Программа должна запрашивать у пользователя нужно ли играть еще один раунд. Для этого считываем с потока ввода символ до тех пор, пока не появится 'y' или 'n', ну и обрабатываем их соответствующим образом:

    bool need_play() {
      char need_play;
      while (true) {
        cout << "exit [y|n]: ";
          
        cin >> need_play;
        
        if (need_play == 'n')
          return true;
        if (need_play == 'y')
          return false;
      }
    }

    Конструкция while(true) в этой программе часто используется и задает она «вечный цикл», выход из него осуществляется с помощью break, ну или return (из функции). Эта программа должна завершать работу при вводе 'y', но мы не исопльзовали функцию exit, т.к. она опасная.

    Как определить минимальное число попыток? — разумный человек, наверное должен догадаться использовать бинарный поиск, ну в самом деле — числа то в диапазоне упорядочены. Первым числом будет середина диапазона, после ответа «слева» или «справа» мы сможем сразу половину диапазона отбросить и так далее. Оптимальное число шагов при этом равно $$log_2{n}$$, где n — ширина диапазона. Однако, С++ не позволяет вам вычислить двоичный логарифм — стандартная библиотека позволяет вычислить натуральный или десятичный логарифм функциями log и log10, соответственно. Чтобы вычислить логарифм по произвольному основанию используют следующую формулу:
    $$\log_a{x} =\frac{\log_b{x}}{\log_b{a}}$$
    На С++ это выглядит так:

    int minimal_attemps(const int from, const int to) {
      return ceil(log((double)(to-from+1)) / log(2.));
    }

    Результат округляется вверх с помощью стандартной функции ceil.

    Последняя наша функция генерирует число, запрашивает вариант пользователя и общается с ним:

    void game(const int from, const int to) {
      int computer_number = rand_between(from, to);
      int user_number;
      int count = 0;
      
      do {
        count++;
        user_number = get_int("your number: ");
        if (user_number < computer_number) {
          cout << "computer number is greater" << endl;
        }
        if (user_number > computer_number) {
          cout << "computer number is less" << endl;
        }
      } while (user_number != computer_number);
      
      cout << "Well done! You guessed my number in " << count << " attempts."
           << " Minimum number of attempts which can be guaranteed for"
           << " the guess is " << minimal_attemps(from, to) << endl;
    }

    Результат выглядит следующим образом:

Для ответа в этой теме необходимо авторизоваться.