Урок 3 — Ветвление: операторы if и switch

Помечено: ,

  • В этой теме 0 ответов, 1 участник, последнее обновление 3 года, 2 месяца назад сделано Васильев Владимир Сергеевич.
Просмотр 0 веток ответов
  • Автор
    Сообщения
    • #3666
      @admin
      StudLance.ru

      Мы уже научились писать линейные программы, однако они не выглядят особо полезными, так как в любой интересной задаче встречаются условия.

      1 Условный оператор — if

      Наиболее простым и универсальным способом организовать ветвление в программе на С++ является следующая конструкция:

      if (условие == true) { // если условие верно
        операторы (выполняются если условие верно);
      }
      else { // в остальных случаях
        операторы (выполняются если условие ложно);
      }

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

      #include <iostream>
      using namespace std;
      
      int main() {
        int a, b;
        cout << "a, b : ";
        cin >> a >> b;
        
        if (a == b) cout << "a is equal to b" << endl;
        if (a != b) cout << "a is not equal to b" << endl;
        if (a > b) cout << "a is bigger than b" << endl;
        if (a < b) cout << "a is less than b" << endl;
        if (a >= b) cout << "a is bigger or equal to b" << endl;
        if (a <= b) cout << "a is less or equal to b" << endl;
      }

      Последовательность операторов, вложенных в фигурные скобки обычно называют ветвью. Фигурные скобки можно не ставить если ветвь состоит из единственной команды, также не обязательной является ветвь else (как в последней программе).

      1.1 Пример — Игра про башни

      Мы пишем игрушку, в которой есть башни, изменяющие характеристики персонажа если он попадает в зону их действия:

      Зеленым обозначены объекты, которые должны попасть под действие башни, но как наша программа смотжет их найти? — У объектов должны быть координаты (ObjX, ObjY), у башни — координаты и радиус действия (TowerX, TowerY, R). Расстояние между объектом и башней можно посчитать по известной формуле:

      $$Distance = \sqrt{(ObjX — TowerX)^2 + (ObjY — TowerY)^2}$$

      Запрограммировать вычисление такой формулы мы уже можем — для вычисления корня квадратного применим функцию sqrt из модуля cmath:

      #include <cmath>
      #include <iostream>
      using namespace std;
      
      int main() {
        double objX, objY, towerX, towerY;
        cout << "Tower position: ";
        cin >> towerX >> towerY;
      
        cout << "Object position: ";
        cin >> objX >> objY;
      
        double dx = objX - towerX,
               dy = objY - towerY;
        double distance = sqrt(dx*dx + dy*dy);
        
        cout << "distance: " << distance << endl;
      }

      Результаты работы программы будут примерно такими:

      Чтобы проверить, попадает ли персонаж в зону башни — заведите переменную, храняющую радиус ее действия (radius) и добавьте в программу следующее:

      if (radius > distance) {
        cout << "hit";
      }
      else {
        cout << "miss";
      }

      1.2 Решение квадратных уравнений

      Любой школьник умеет решать квадратные уровнения с использованием дискриминанта, но чем наши программы хуже? Общий вид уравнения:
      $$a\cdot x^2 + b\cdot x + c = 0$$

      Для простоты будем считать, что коэффициент a не равен нулю, тогда:
      $$
      D = b^2 — 4 \cdot a \cdot c,\\
      \begin{equation*}
      x_{1,2} =
      \begin{cases}
      \frac {-b \pm \sqrt{D}}{2 \cdot a} \quad &\text{$D > 0$} \\
      \frac {-b + \sqrt{D}}{2 \cdot a} \quad &\text{$D = 0$} \\
      \emptyset \quad &\text{$D < 0$}
      \end{cases}
      \end{equation*}$$

      Запишем программу, выполняющую проверки и вычисления по этим формулам:

      #include <cmath>
      #include <iostream>
      using namespace std;
      
      int main() {
        double a, b, c;
        
        cout << "enter a, b, c: ";
        cin >> a >> b >> c;
        
        double discriminant = b*b - 4*a*c;
        if (discriminant < 0)
          cout << "no roots" << endl;
        else {
          if (discriminant < 0.000001) 
            cout << "single root: " << -b / 2*a << endl;
          else {
            double root_1 = (-b + sqrt(discriminant)) / (2*a);
            double root_2 = (-b - sqrt(discriminant)) / (2*a);
            
            cout << "first root: " << root_1 << endl;
            cout << "second root: " << root_2 << endl;
          }
        }
      }

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

      Условие discriminant < 0.000001 соответствует проверке D=0 из описанной выше формулы. Дело в том, что выполнять проверку равенства дробных чисел бессмысленно — они могут содержать «мусор» в младших разрядах, в результате — числа, полученные по эквивалентным с точки зрения математики формулам, могут оказаться не равными с точки зрения компьютера. Такие числа сравниваются с погрешностью.

      1.3 Опять игрушка — подвижный игрок

      Мы пишем игрушку, где Персонаж может перемещаться как угодно, но не через стены. Пусть, персонаж двигается вправо и где-то на поле есть стена:

      Координаты (Px, Py, Wx, Wy) тут отсчитываются от верхнего левого угла, как это принято в программировании. Тогда, чтобы проверить, можно ли игроку двигаться дальше — можно применить такое составное условие:

      ЕСЛИ Px > Wx ИЛИ (Py+H) < Wy ИЛИ Py > (Wy+Hc) ИЛИ (Px+H) < Wx ТО:
        двигаться можно
      ИНАЧЕ
        двигаться нельзя

      Я рекомендую вам нарисовать на бумаге игрока и стену чтобы «почувствовать» каждое из этих условий, а затем — читать дальше.

      В приведенной формуле условия соединяются с помощью логического оператора ИЛИ — в языке С++ он обозначается так: ||. Можно «поиграться» со следующей программой:

      #include <cmath>
      #include <iostream>
      using namespace std;
      
      int main() {
        double wall_x = 3, wall_y = 5, wall_h = 10;
        double player_h = 5, player_w = 1;
        double player_x, player_y;
        
        cout << "player position: ";
        cin >> player_x >> player_y;
        
        if (player_x > wall_x || // игрок "за" стеной
            (player_y+player_h) < wall_y || // игрок целиком "выше" стены
            player_y > wall_y + wall_h || // игрок целиком "ниже" стены
            (player_x + player_w) < wall_x // игрок целиком "левее" стены
        ) {
          cout << "can move" << endl;
        }
        else {
          cout << "can't move" << endl;
        }
      }

      1.4 Проверка високосности года

      В обычном году 365 дней, а в високосном — 366. Эти цифры могут пригодиться нам, например в программе, вычисляющей количество дней до определенной даты. На википедии описан механизм определения високосности:

      • год, номер которого кратен 400, — високосный;
      • остальные годы, номер которых кратен 100, — невисокосные;
      • остальные годы, номер которых кратен 4, — високосные.

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

      #include <iostream>
      using namespace std;
      
      int main() {
        int year;
        cin >> year;
      
        if (year % 400 == 0) { 
          // год, номер которого кратен 400, — високосный;
          cout << "Leap year! \n";
        }
        else {
          //остальные годы, 
          if (year % 100 == 0) {
            // номер которых кратен 100, — невисокосные;
            cout << "Not leap year! \n";
          }
          else {
            // остальные годы,
            if (year % 4 == 0) {
              // номер которых кратен 4, — високосные.
              cout << "Leap year! \n";
            }
            else {
              // остальные - не високосные
              cout << "Not leap year! \n";
            }
          }
        }
      }

      Значительно улучшить код можно с помощью уже изученых составных условий и оператора «логического И», в С++ обозначаемого &&:

      #include <iostream>
      using namespace std;
      
      int main() {
        int year;
        cin >> year;
      
        if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
          cout << "Leap year! \n";
        else 
          cout << "Not leap year! \n";
      }

      Проверьте обе программы и постарайтесь понять почему они дают одинаковый результат.

      2 Оператор выбора — switch

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

      switch (выражение) {
        case значение_1: операторы_1; break;
        case значение_2: операторы_2; break;
        case значение_3: операторы_3; break;
        // …
        case значение_n: операторы_n; break;
        default: операторы; break;
      }

      Оператор работает следующем образом. Вычисляется значение выражения. Затем выполняются операторы, помеченные значением, совпадающим со значением выражения. То есть если, выражение принимает значение_1, то выполняются операторы_1 и т.д.. Если выражение не принимает ни одного из значений, то выполняются операторы, расположенные после слова default (если этой ветви нет — то не выполнится ничего).

      Оператор break осуществляет выход из блока case. Если он не указан, то будут выполняться следующие операторы из списка, несмотря на то, что значение, которым они помечены, не совпадает со значением выражения.

      В настоящий момент мы врядли можем найти удачное применение этому оператору, однако в будущем он нам очень пригодится. В качестве примера, рекомендую изучить следующую программу, выводящую название дня недели по его номеру:

      #include <iostream>
      using namespace std;
      
      int main () {
        unsigned int day_of_week;
        
        cout << "day number: ";
        cin >> day_of_week;
        
        switch (day_of_week) {
          case 1: cout<<"Monday" << endl; break;
          case 2: cout<<"Theusday" << endl; break;
          case 3: cout<<"Wednesday" << endl; break;
          case 4: cout<<"Thursday" << endl; break;
          case 5: cout<<"Friday" << endl; break;
          case 6: cout<<"Saturday" << endl; break;
          case 0: cout<<"Sunday" << endl; break;
          default: cout << "bad day number" << endl; break;
        }
      }

      StudLance.ru

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