第 10 回 | 2024-12-06¶
- 真偽を表す型を学ぶ
- 否定の記号を学ぶ
- const について学ぶ
- 数学関数を学ぶ
- 関数の作り方を学ぶ
- 関数を作る練習をする
- Siv3D をインストールする方法を学ぶ
1. 真偽を表す型 bool¶
プログラムの中で、Yes か No の二択の状態を表現するとき、例えば int
型の 0
と 1
で表現することができるが、どちらが Yes なのか、2
や -1
はどうなのかといった曖昧さが生じる。C++ では、このような二択の状態を表現するための専用の型 bool
が用意されている。
bool
型は、true
と false
の二つの値だけを持つ。true
は Yes(真)を表し、false
は No(偽)を表す。
1.1 bool 型の値¶
bool
型の値はif
文の条件式に使うことができる。true
は真を表し、そのif
文の中の処理が実行される。false
は偽を表し、そのif
文の中の処理は実行されない。else
ブロックがあれば、else
ブロックの中の処理が実行される。
#include <iostream>
int main()
{
bool hasEnoughMoney = true;
if (hasEnoughMoney)
{
std::cout << "買う!\n";
}
else
{
std::cout << "買わない。\n";
}
}
1.2 比較演算の結果は bool 型¶
<
や==
などの比較演算子の結果はbool
型である。
#include <iostream>
int main()
{
int money = 1000;
int price = 2000;
bool hasEnoughMoney = (price <= money);
if (hasEnoughMoney)
{
std::cout << "買う!\n";
}
else
{
std::cout << "買わない。\n";
}
}
1.3 && と ||¶
bool
型の値を&&
と||
でつなげることができる。- 次のコードでは、所持金が十分かつ割引がある場合に商品を買う。
#include <iostream>
int main()
{
int money = 5000;
int price = 2000;
bool hasEnoughMoney = (price <= money);
bool isDiscounted = false;
if (hasEnoughMoney && isDiscounted)
{
std::cout << "買う!\n";
}
else
{
std::cout << "買わない。\n";
}
}
2. 否定の記号 !
¶
2.1 否定の記号 !
の使い方¶
!
は否定を表す記号で、bool
型の値を反転させた結果を返す。
#include <iostream>
int main()
{
bool isDiscounted = false;
if (!isDiscounted)
{
std::cout << "割引なし\n";
}
else
{
std::cout << "割引あり\n";
}
}
2.2 複雑な式の中での !
の使用¶
#include <iostream>
int main()
{
int money = 5000;
int price = 2000;
bool isDiscounted = false;
if ((price <= money) && !isDiscounted)
{
std::cout << "所持金は十分だが、割引がないので買わない。\n";
}
}
3. 再代入を禁止する const
¶
3.1 const の使い方¶
- 値を変更する予定が無い、あるいは変更させたくない変数を作る場合、型名の前に
const
を付ける。 const
の付いた変数は、それ以降変更できなくなる(変更操作がコンパイルエラーになる)。const
によって、プログラマのミスによる意図しない変数の値の変更を防ぐことができるため、使える場面では積極的にconst
を使うようにする。- 一般に、
const
を使っていれば使っているほど、良く設計された C++ コードと言える。 - 次のコードでは、商品の値段を固定するため
const
を付けている。商品の値段を途中で変更しようとするとコンパイルエラーになる。
#include <iostream>
int main()
{
// 商品の値段
const int price = 300;
// 買う個数
int n;
std::cin >> n;
//price = 3000; // コンパイルエラー: const を付けた変数は値を変更できない
std::cout << (price * n) << '\n';
}
4. 数学関数の使用¶
4.1 絶対値¶
<cmath>
をインクルードすると使えるstd::abs(x)
関数は、渡したdouble
型の値x
の絶対値をdouble
型で返す。- abs は absolute value(絶対値)の略。
#include <iostream>
#include <cmath>
int main()
{
const double x = std::abs(6.5);
std::cout << x << '\n';
std::cout << std::abs(-3.5) << '\n';
std::cout << std::abs(0.0) << '\n';
const double y = -2.3;
std::cout << std::abs(y) << '\n';
}
4.2 四捨五入¶
<cmath>
をインクルードすると使えるstd::round(x)
関数は、渡したdouble
型の値x
を四捨五入した値をdouble
型で返す。
#include <iostream>
#include <cmath>
int main()
{
const double x = std::round(1.4);
std::cout << x << '\n';
std::cout << std::round(1.5) << '\n';
std::cout << std::round(-3.3) << '\n';
const double y = 55.5;
std::cout << std::round(y) << '\n';
}
4.3 平方根¶
<cmath>
をインクルードすると使えるstd::sqrt(x)
関数は、渡したdouble
型の値x
の平方根をdouble
型で返す。- sqrt は square root(平方根)の略。
#include <iostream>
#include <cmath>
int main()
{
const double x = std::sqrt(2.0);
std::cout << x << '\n';
std::cout << std::sqrt(16.0) << '\n';
std::cout << std::sqrt(1.21) << '\n';
const double y = 55.5;
std::cout << std::sqrt(y) << '\n';
}
4.4 最小値¶
<algorithm>
をインクルードすると使えるstd::min(a, b)
関数は、渡した値a
,b
の小さいほうを返す。
#include <iostream>
#include <algorithm>
int main()
{
const int x = std::min(10, 20);
std::cout << x << '\n';
std::cout << std::min(-20, 40) << '\n';
std::cout << std::min(40, -20) << '\n';
const int y = 15;
std::cout << std::min(x, y) << '\n';
}
4.5 最大値¶
<algorithm>
をインクルードすると使えるstd::max(a, b)
関数は、渡した値a
,b
の大きいほうを返す。
#include <iostream>
#include <algorithm>
int main()
{
const int x = std::max(10, 20);
std::cout << x << '\n';
std::cout << std::max(-20, 40) << '\n';
std::cout << std::max(40, -20) << '\n';
const int y = 15;
std::cout << std::max(x, y) << '\n';
}
4.6 min と max の応用¶
std::min(a, b)
関数やstd::max(a, b)
関数はdouble
型にも対応する。a
,b
は両方とも同じ型にする必要がある。- 例:
a
もb
もint
型 - 例:
a
もb
もdouble
型
- 例:
#include <iostream>
#include <algorithm>
int main()
{
std::cout << std::min(5.5, 3.3) << '\n';
std::cout << std::max(5.5, 3.3) << '\n';
}
5. 関数の作り方¶
5.1 関数を作る¶
- 仕事に名前を付けることができ、これを関数という。
- 関数は「関数名」と「関数呼び出しの記号
()
」を使って呼び出す(実行する)ことができる。 - 関数を作る最も基本の文法は次の通りである。
- 使用例:
#include <iostream>
// Hello! と出力する仕事をする関数
void ShowMessage()
{
std::cout << "Hello!\n";
}
int main()
{
ShowMessage();
ShowMessage();
}
5.2 関数に引数を渡す¶
- 関数に特定の型の値をコピーして渡し、仕事の中で使ってもらうことができる。
- 渡す値 / 渡された値のことを引数(ひきすう)といい、前者を実引数、後者を仮引数と区別する。
- 引数がある関数を作る文法は次のとおりである。
- 使用例:
#include <iostream>
void ShowMessage()
{
std::cout << "Hello!\n";
}
void ShowInt(int n)
{
std::cout << n << '\n';
}
void ShowDouble(double x)
{
std::cout << x << '\n';
}
int main()
{
ShowMessage();
ShowMessage();
ShowInt(123);
ShowInt(-2000);
ShowDouble(1.23);
ShowDouble(-55.5);
}
- 仮引数の変数名は任意であり、仮引数の変数のスコープはその関数内のみである。
- プログラムの中に関数が複数あっても、プログラムが最初に
main()
関数を実行してくれるのは、C++ ではmain()
関数を最初に実行すると決められているためである。このような最初に呼び出される関数のことをエントリーポイントという。
5.3 複数の引数を渡す関数を作る¶
- 複数の引数を渡す関数を作る文法は次のとおりである。
- 使用例:
#include <iostream>
// 指定した回数だけ指定した文字を出力し、最後に改行する
void ShowLine(int count, char ch)
{
for (int i = 0; i < count; ++i)
{
std::cout << ch;
}
std::cout << '\n';
}
int main()
{
ShowLine(10, '*');
ShowLine(5, '-');
ShowLine(10, 'w');
}
- 3 つ以上の引数についても同様である。
同じ型の引数を、型を省略してまとめて記述することはできない
5.4 戻り値を返す関数を作る (1)¶
- 関数は、仕事の結果を、呼び出した側に
return 結果;
によって返すことができる。 - 返す値 / 返された値のことを戻り値(もどりち)という。
- 関数は
return
すると、そこで仕事を終了する。 - 戻り値がある関数を作る文法は次のとおりである。
- 使用例:
#include <iostream>
// 与えられた整数の平方を返す
int Square(int n)
{
return (n * n);
}
int main()
{
int a = Square(5);
std::cout << a << '\n';
std::cout << Square(11) << '\n';
// 関数の戻り値を引数にして関数を呼ぶこともできる
std::cout << Square(Square(4)) << '\n';
}
- 5.4 のように 1 行で戻り値を返す関数もあれば、複数行の仕事をしてから戻り値を返す関数もある。
5.5 戻り値を返す関数を作る (2)¶
return
を複数書くような関数もある。
#include <iostream>
// 与えられた 2 つの整数の差の絶対値を返す
int AbsDiff(int a, int b)
{
if (a < b)
{
return (b - a);
}
else
{
return (a - b);
}
}
int main()
{
std::cout << AbsDiff(50, 80) << '\n';
std::cout << AbsDiff(1, 11) << '\n';
}
5.6 戻り値が void である関数の return¶
- 戻り値が
void
である関数(戻り値の無い関数)は値を返せないが、return;
によって関数をそこで終了できる。
#include <iostream>
void ShowFee(int age)
{
if (age <= 3)
{
std::cout << "無料\n";
return;
}
std::cout << "2000 円\n";
}
int main()
{
ShowFee(40);
ShowFee(10);
ShowFee(3);
}
6. 関数を作る練習¶
6.1 与えられた 2 つの整数のうち、大きい方の値を返す関数¶
std::max()
のような関数を自分で作ると次のようになる。
#include <iostream>
// 与えられた 2 つの整数のうち、大きい方の値を返す関数
int MaxInt(int a, int b)
{
if (a < b)
{
return b;
}
else
{
return a;
}
}
int main()
{
std::cout << MaxInt(80, 50) << '\n';
std::cout << MaxInt(-100, -50) << '\n';
}
6.2 与えられた 4 つの整数のうち、最大の値を返す関数¶
- 複雑な関数を作るとき、既存の関数を部品として使うことで、簡単に書けることがある。
#include <iostream>
// 与えられた 2 つの整数のうち、大きい方の値を返す関数
int MaxInt(int a, int b)
{
if (a < b)
{
return b;
}
else
{
return a;
}
}
// 与えられた 4 つの整数のうち、最大の値を返す関数
int MaxInt4(int a, int b, int c, int d)
{
return MaxInt(MaxInt(a, b), MaxInt(c, d));
}
int main()
{
std::cout << MaxInt4(80, 50, 20, 0) << '\n';
std::cout << MaxInt4(-100, -50, -10, -200) << '\n';
std::cout << MaxInt4(0, 999, 0, 0) << '\n';
}
6.3 二点間の距離を求める関数¶
#include <iostream>
#include <cmath>
// 二点 (x1, y1), (x2, y2) 間の距離を返す
double Distance(double x1, double y1, double x2, double y2)
{
return std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
int main()
{
std::cout << Distance(0.0, 0.0, 10.0, 10.0) << '\n';
std::cout << Distance(3.0, 2.0, 7.0, 5.0) << '\n';
}
<cmath>
の std::hypot()
を使う
<cmath>
の std::hypot(x, y)
関数は、直角三角形の直角をなす辺の長さがそれぞれ x
, y
のときの斜辺の長さを返す。これを使うこともできる。
7. Siv3D(シブスリーディー)プログラミングの準備¶
- 第 12 回以降の講義の「グラフィックスプログラミング」では、C++ コードでゲームやアプリを簡単に開発できるフレームワーク「Siv3D」を使用する。
7.1 C++ の開発環境をインストールする¶
- 自分の PC にインストールする を参考に、C++ の開発環境をインストールする。
7.2 Siv3D をインストールする¶
順番を守る
- 7.1 が完了するまでは、ここの内容は実行しない。
- Windows で 7.1 が完了したら、一度 Visual Studio を終了してから、この内容を実行する。
- C++ コードでゲームやアプリを簡単に開発できるフレームワーク「Siv3D」をインストールする。Siv3D 公式サイト にアクセスし、「Siv3D をダウンロードする」から、使用している OS に応じた開発キットをダウンロードする。
- 該当ページの指示通り進めれば、Siv3D で作成したプログラムの実行までたどり着ける。
- 次のような画面が表示されたら、インストールは成功。
トラブルシューティング
① Windows の 3. の手順でどれだけ探しても「OpenSiv3D_0.6.15」の項目が見つからない¶
- 手順ページにある『プロジェクト テンプレートの項目に「OpenSiv3D」が見つからない場合』を参照してください。
② Windows の 4. の手順でエラーが出て実行できない¶
- Visual Studio 2022 が最新のバージョン(17.12 以降)になっているかを確認し、Visual Studio Installer を使って Visual Studio 2022 の更新を行ってください。
③ M1 ~ M3 mac の 3. の手順でエラーが発生し、プログラムが起動しない。¶
- 手順ページにある『M1 - M3 Mac における Rosetta モードの有効化』を参照してください。
④ それ以外¶
- Moodle または講義時間内に質問してください。Moodle での質問時は、トラブルの様子を示すスクリーンショットを添えてください。
✅ 振り返りチェックリスト¶
- 真偽を表す型を学んだ
- 否定の記号を学んだ
- const について学んだ
- 数学関数を学んだ
- 関数の作り方を学んだ
- 関数を作る練習をした
- Siv3D をインストールする方法を学んだ
📝 課題¶
🐣 練習問題¶
標準出力を使って図形を描く関数を実装してください。解答テンプレートが与えられるので、それを完成させてください。実装する関数は次の 1 つです。
1. 長方形を描く関数¶
引数 | 説明 |
---|---|
width |
長方形の幅 |
height |
長方形の高さ |
ch |
描画に使う文字 |
解答テンプレート
#include <iostream>
void DrawRectangle(int width, int height, char ch)
{
// ここにコードを書く
}
int main()
{
DrawRectangle(5, 1, '*');
std::cout << '\n';
DrawRectangle(3, 6, '@');
std::cout << '\n';
DrawRectangle(10, 5, '#');
}
解答例
#include <iostream>
void DrawRectangle(int width, int height, char ch)
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
std::cout << ch;
}
std::cout << '\n';
}
}
int main()
{
DrawRectangle(5, 1, '*');
std::cout << '\n';
DrawRectangle(3, 6, '@');
std::cout << '\n';
DrawRectangle(10, 5, '#');
}
📝 ① 提出課題(50 点)¶
標準出力を使って図形を描く関数を実装してください。解答テンプレートが与えられるので、それを完成させてください。
実装する関数は次の 3 つです。
1. 長方形の枠を描く関数¶
引数 | 説明 |
---|---|
width |
長方形の幅 |
height |
長方形の高さ |
ch |
枠の描画に使う文字 |
- 長方形の枠以外の部分は空白文字を使う。
2. チェッカーボードを描く関数¶
引数 | 説明 |
---|---|
width |
チェッカーボード全体の幅 |
height |
チェッカーボード全体の高さ |
cellSize |
チェッカーボードの 1 マスの幅および高さ |
ch1 |
チェッカーボードの最も左上のマスの描画に使う文字 |
ch2 |
もう一方のマスの描画に使う文字 |
3. 円を描く関数¶
引数 | 説明 |
---|---|
radius |
円の半径 |
- 描画には塗りつぶし文字として
#
を使い、円以外の部分は空白文字を使います。 - 【ボーナス加点】円の周において、必要な部分に中間色の塗りつぶし文字として
+
を使い、エッジをスムーズにします。専門用語でいうと「アンチエイリアス処理」を行ってください。外周のすべてを+
で描くわけではないことに注意が必要です。
エッジをスムーズにする例
解答テンプレート
#include <iostream>
#include <cmath>
void DrawRectangleOutline(int width, int height, char ch)
{
// ここにコードを書く
}
void DrawCheckerboard(int width, int height, int cellSize, char ch1, char ch2)
{
// ここにコードを書く
}
void DrawCircle(int radius)
{
// ここにコードを書く
}
int main()
{
DrawRectangleOutline(10, 5, '*');
std::cout << '\n';
DrawRectangleOutline(3, 3, '#');
std::cout << '\n';
DrawRectangleOutline(1, 5, '@');
std::cout << '\n';
DrawCheckerboard(10, 8, 2, 'O', '#');
std::cout << '\n';
DrawCheckerboard(12, 10, 3, ' ', '#');
std::cout << '\n';
DrawCheckerboard(15, 15, 4, '-', '|');
std::cout << '\n';
DrawCircle(4);
std::cout << '\n';
DrawCircle(6);
std::cout << '\n';
DrawCircle(12);
std::cout << '\n';
}
出力例
**********
* *
* *
* *
**********
###
# #
###
@
@
@
@
@
OO##OO##OO
OO##OO##OO
##OO##OO##
##OO##OO##
OO##OO##OO
OO##OO##OO
##OO##OO##
##OO##OO##
### ###
### ###
### ###
### ###
### ###
### ###
### ###
### ###
### ###
### ###
----||||----|||
----||||----|||
----||||----|||
----||||----|||
||||----||||---
||||----||||---
||||----||||---
||||----||||---
----||||----|||
----||||----|||
----||||----|||
----||||----|||
||||----||||---
||||----||||---
||||----||||---
+##+
######
+######+
########
########
+######+
######
+##+
+####+
########
##########
+##########+
############
############
############
############
+##########+
##########
########
+####+
++####++
+##########+
+##############+
+################+
+##################+
####################
+####################+
######################
+######################+
+######################+
########################
########################
########################
########################
+######################+
+######################+
######################
+####################+
####################
+##################+
+################+
+##############+
+##########+
++####++
DrawCircle
の表示結果は、計算方法によって異なる場合があります。若干の違いは許容されます。- 採点時には
main()
関数にテストケースを追加します。解答テンプレート以外の文字やサイズにも対応できるようにしてください。
課題 ① は、コードまたはコードの共有 URL(Wandbox)を提出してください。
円の描画のヒント
- 一辺が半径の倍の長さを持つ正方形を考えます。
- 各マス目の中心の座標について、円の中心の座標からの距離を考えます。
📝 ② 事前課題(50 点、提出なし)¶
- 課題 ② で提出するものはありません。
- 第 12 回以降の講義で必要になるため、7.1~7.3 を参考に C++ の開発ツールと Siv3D をインストールしてください。
- 第 12 回の提出課題で一定の基準を満たした場合に、この課題で満点の 50 点を獲得します。それ以外の場合、この課題の得点は 0 点になります。
なるべく早めに取り組みましょう
インストールでトラブルがあった場合は、Moodle や講義時間でサポートします。第 12 回講義ぎりぎりになると講義時間内に対応できない可能性があり、今後の課題提出に支障が出るおそれがあります。