第 5 回 | 2024-10-25 🛜 オンデマンド¶
第 5 回は 🛜 オンデマンド講義
講義ページを自分で読み進め、いつもどおり課題を提出してください。講義のライブ配信や動画はありません。教室は開室しています。講義日に Moodle で質問をすると、翌日までにスピード対応します。
- さらに分岐する方法を学ぶ
- 変数のスコープについて学ぶ
1. さらに分岐する¶
1.1 条件をさらに分ける¶
if - eles
から条件をさらに分けたいときにはelse if ()
を使う。- 次のコードは、
age
が 18 未満のときはこども
, 18 以上 65 未満のときは大人
, 65 以上のときはお年寄り
と出力する。 - 一連の
if - eles if - else
は上から順にチェックしていき、最初に条件が成立したときの{ }
だけが実行される。
📙 Unit 21
#include <iostream>
int main()
{
int age;
std::cin >> age;
if (age < 18)
{
std::cout << "こども\n";
}
else if (age < 65)
{
std::cout << "大人\n";
}
else
{
std::cout << "お年寄り\n";
}
}
else if
やelse
の前後には空白行を作らないほうが、一連のif - else
が一つのまとまりであることがわかりやすい。
空白行を入れた場合(不適切)
1.2 条件をもっと分ける¶
else if ()
をさらに増やすことができる。- このプログラムは、
age
が 1 未満のときは赤ちゃん
, 1 以上 18 未満のときはこども
, 18 以上 65 未満のときは大人
, 65 以上のときはお年寄り
と出力する。
📙 Unit 21
#include <iostream>
int main()
{
int age;
std::cin >> age;
if (age < 1)
{
std::cout << "赤ちゃん\n";
}
else if (age < 18)
{
std::cout << "子ども\n";
}
else if (age < 65)
{
std::cout << "大人\n";
}
else
{
std::cout << "お年寄り\n";
}
}
順番に気を付ける
一連の if
~else
は上から順にチェックされる。そのため、次のような順番では、age
が 0 のときに「赤ちゃん」ではなく「子ども」と出力されてしまう。
2. 変数のスコープ¶
2.1 変数の生存期間¶
{ }
の内側で変数を作ると、その}
が閉じたときに変数の有効期間(スコープ)が終わり、その変数は消える。- (第 4 回の 1.8 も参照)
- 有効期間が終わった変数の名前は、別の新しい変数の名前として使うことができる。
- スコープを意識することで、コード内の変数の名前が増えすぎることを防げる。
- 次のコードでは
n
という名前の変数が 2 つ登場するが、それぞれ異なる変数である。
#include <iostream>
int main()
{
{
int n;
std::cin >> n;
std::cout << (n * 2) << "\n";
}
{
int n;
std::cin >> n;
std::cout << (n * n) << "\n";
}
}
2.2 スコープを意識して同じ名前の変数を複数作る¶
- スコープを意識することで、コードに登場する変数名の種類を抑制できる。その例を示す。
- 次のコードは、
n
が 2 のときに 2 つの数の和を、3 のときに 3 つの数の和を出力する。
改善前
#include <iostream>
int main()
{
int n;
std::cin >> n;
if (n == 2)
{
int a, b;
std::cin >> a >> b;
std::cout << (a + b) << "\n";
}
else if (n == 3)
{
int c, d, e;
std::cin >> c >> d >> e;
std::cout << (c + d + e) << "\n";
}
}
- 次のように変数名を書き換えることができる。
- 使用するアルファベットの種類を減らし、やや見通しの良いコードになった。
改善後
#include <iostream>
int main()
{
int n;
std::cin >> n;
if (n == 2)
{
int a, b;
std::cin >> a >> b;
std::cout << (a + b) << "\n";
}
else if (n == 3)
{
int a, b, c;
std::cin >> a >> b >> c;
std::cout << (a + b + c) << "\n";
}
}
✅ 振り返りチェックリスト¶
- さらに分岐する方法を学んだ
- 変数のスコープについて学んだ
課題¶
📝 提出課題¶
6 人の学生が C++ でプログラムを作成しました。しかし、それぞれに何らかの問題があるようです。
- ①~⑤ に対して問題点を指摘し、コードを修正してください(配点 100)
- 可能であればプログラムに追加の機能や改善を加え、それを説明してください(加点 20)
(練習)A さん「最小の硬貨の枚数になるようにおつりを計算するプログラム」¶
#include <iostream>
int main()
{
std::cout << "硬貨の枚数が最小になるようにおつりを計算します。\n";
std::cout << "おつりの金額を入力してください:\n";
int change;
std::cin >> change;
int coin500 = change / 500;
int coin100 = change / 100;
int coin50 = change / 50;
int coin10 = change / 10;
int coin5 = change / 5;
int coin1 = change;
std::cout << "500 円玉: " << coin500 << " 枚\n";
std::cout << "100 円玉: " << coin100 << " 枚\n";
std::cout << "50 円玉: " << coin50 << " 枚\n";
std::cout << "10 円玉: " << coin10 << " 枚\n";
std::cout << "5 円玉: " << coin5 << " 枚\n";
std::cout << "1 円玉: " << coin1 << " 枚\n";
}
解答例
【問題点】
各硬貨の枚数の計算に誤りがあり、その硬貨より大きい硬貨での支払いを無視している。
例えば 200 を入力したとき、100 円玉 2 枚のみになるべきだが、次のような不正な出力になる。
500 円玉: 0 枚
100 円玉: 2 枚
50 円玉: 4 枚
10 円玉: 20 枚
5 円玉: 40 枚
1 円玉: 200 枚
【修正方法】
修正するには、例えば 50 円玉の枚数は
(change % 100) / 50;
として、100 円までで払えなかった余りに対して計算するようにする。
【機能追加】
下記の 2 つの機能を追加した。
・0 枚の硬貨は出力しない。
・おつりがないときは「おつりはありません」と出力する。
【コード】
https://wandbox.org/permlink/0qgG4O2QyHYJx6tT
① B さん「クイズアプリだよ」¶
#include <iostream>
int main()
{
std::cout << "アメリカの首都は?\n";
std::cout << "1: ワシントン D.C.\n2: パリ\n3: ニューヨーク\n4: ロンドン\n";
int answer;
std::cin >> answer;
if (answer = 1)
{
std::cout << "正解!\n";
}
else
{
std::cout << "不正解!\n";
}
}
② C さん「成績を出力するプログラムを作った」¶
#include <iostream>
int main()
{
std::cout << "点数を入力してください:\n";
int score;
std::cin >> score;
if (90 <= score <= 100)
{
std::cout << "A\n";
}
else if (80 <= score < 90)
{
std::cout << "B\n";
}
else if (70 <= score < 80)
{
std::cout << "C\n";
}
else if (60 <= score < 70)
{
std::cout << "D\n";
}
else
{
std::cout << "F\n";
}
}
③ D さん「時間を秒で入力すると、時間、分、秒に変換します」¶
#include <iostream>
int main()
{
std::cout << "時間を秒で入力してください:\n";
int time;
std::cin >> time;
int hour = (time / 3600);
int minute = (time / 60);
int second = (time % 60);
std::cout << hour << "時間" << minute << "分" << second << "秒\n";
}
④ E さん「元号を判定するプログラム」¶
#include <iostream>
int main()
{
std::cout << "年月日を入力してください:\n";
int year, month, day;
std::cin >> year >> month >> day;
if ((year < 1912) && (month < 7) && (day < 30))
{
std::cout << "大正以前\n";
}
else if ((year < 1926) && (month < 12) && (day < 25))
{
std::cout << "大正\n";
}
else if ((year < 1989) && (month < 1) && (day < 8))
{
std::cout << "昭和\n";
}
else if ((year < 2019) && (month < 4) && (day < 30))
{
std::cout << "平成\n";
}
else
{
std::cout << "令和\n";
}
}
元号の期間は下記の表に基づくこととします。
元号 | 開始年月日 | 終了年月日 |
---|---|---|
大正 | 1912-07-30 | 1926-12-24 |
昭和 | 1926-12-25 | 1989-01-07 |
平成 | 1989-01-08 | 2019-04-30 |
令和 | 2019-05-01 |
⑤ F さん「ゲーム作ったけどバグってる」¶
乱数を生成する
このプログラムでは、今後の講義で扱う、乱数を生成する方法を先取りして使っています。次のコードを加えると、Random(a, b)
で a 以上 b 以下の整数の乱数を生成できます。
#include <iostream>
#include <random> // 乱数用
// min 以上、max 以下の乱数を生成する関数
int Random(int min, int max)
{
std::random_device rng;
return std::uniform_int_distribution<int>{ min, max }(rng);
}
int main()
{
for (;;)
{
// 主人公の HP
int playerHP = 200;
// 敵の HP
int enemyHP = 200;
std::cout << "----------------------------\n";
std::cout << "主人公\t HP: " << playerHP << "\n";
std::cout << "敵\t HP: " << enemyHP << "\n";
std::cout << "----------------------------\n";
std::cout << "行動を選択してください\n";
std::cout << "1: 攻撃 2: 回復 3: 逃げる\n";
int action;
std::cin >> action;
std::cout << "----------------------------\n";
if (action == 1) // 攻撃
{
std::cout << "主人公の攻撃!\n";
// 敵に与えるダメージを 20 ~ 40 の範囲でランダムに決定
int damage = Random(20, 40);
std::cout << "敵に" << damage << "のダメージ!\n";
enemyHP -= damage;
}
else if (action == 2) // 回復
{
std::cout << "主人公は 100 回復した!\n";
playerHP += 100;
}
else if (action == 3) // 逃げる
{
std::cout << "うまく逃げ切れた!\n";
break;
}
{
std::cout << "敵の攻撃!\n";
// 主人公に与えるダメージを 30 ~ 50 の範囲でランダムに決定
int damage = Random(30, 50);
std::cout << "主人公に" << damage << "のダメージ!\n";
playerHP -= damage;
}
if (playerHP <= 0)
{
std::cout << "主人公は力尽きた...【敗北】\n";
break;
}
else if (enemyHP <= 0)
{
std::cout << "敵を倒した!【勝利】\n";
break;
}
}
}