# プログラマ勉強会 第2回 (範囲 条件分岐 ループ 論理演算) ## 条件分岐 if文 ゲームを作る際、ある条件下のみでこんな動作を実装したい!といった場面が多く表れます。 例えば、横スクロールアクションゲーム(マリオのようなゲーム)を作る場合、以下のような例が挙げられます。 - プレイヤーが敵とぶつかったら、ダメージを与えたい(残機を減らしたい) - プレイヤーの残機が0になったら、ゲームオーバーにしたい - 残り時間が0になったら、ゲームオーバーにしたい このような処理は、「if文」を用いることで簡単に実装できます! 試しに以下のコードを書いてみましょう。 《コード1》 ```cpp #include <iostream> int main() { int playerLife = 0;// プレイヤーの残機数 if(playerLife == 0){ std::cout << "ゲームオーバー!" << std::endl; } return 0; } ``` まず簡単に説明すると、ifの隣の()内には**条件**を、{}内には**条件を満たした際に実行する内容**を書きます。 上の例で言うと、条件は playerLife == 0 です。 == は「右辺の値と左辺の値が一致しているかどうか」を判定する役割を担っており、例ではplayerLifeの値が0の場合に「ゲームオーバー!」と出力してくれます。 上の == のように、右辺と左辺の値を比較してくれるものを**比較演算子**と呼びます。 以下によく使う比較演算子を置いときます。 ``` 演算子  trueになる条件(if文内が実行される条件) <    左辺が右辺より小さい場合 <=    左辺が右辺以下である場合 >    左辺が右辺より大きい場合 >=    左辺が右辺以上である場合 ==    左辺と右辺が一致する場合 !=    左辺と右辺が異なる場合 ``` ここで一つ。 if文が条件を満たすことを「真になる」だったり「trueになる」と言ったり、満たさない場合は「偽になる」や「falseになる」と言ったりします。以後はこのように説明させていただきます。 しかし、playerLifeが0の時に○○、1の時に○○、maxの時に○○...といった具合に、3つ以上に分岐させたい場合もありますよね。 ライフが減るにつれて、注意を促すように赤めのエフェクトが表示されるようになる、といった演出を見たことはありませんか?次はこれをイメージしてみましょう。 《コード2》 ```cpp #include <iostream> #include <string> int main(){ int playerLife;//ライフの数 std::string playerLifeColor;//ライフの色名 std::cin >> playerLife; if(playerLife => 3){ playerLifeColor = "Blue"; }else if(playerLife == 2){ playerLifeColor = "Yellow"; }else{ playerLifeColor = "Red"; } std::cout << playerLifeColor << std::endl; return 0; } ``` 新たに`else if()`が出てきました。これは、一つ上のif文がfalseだった場合に実行してくれるイメージです。 《コード2》の場合だと、「playerLifeが3以上ではない」とき、「playerLifeが2かどうか」を判定してくれるわけです。 最後に else です。この後ろには条件を書く必要がありません。`else`に続く{}内のコードは、 「`else`より前の一連の`if()`及び`if else()`がすべてfalseだった場合」に実行してくれる感覚で大丈夫です。 《コード2》では「playerLifeが3以上でも2でもない場合」にelse内を実行してくれます。 ## 論理演算子 しかし、ライフが3つは少ないですよね。快適なゲームを求めるのなら10個ぐらいあってもよいかもしれません。次は、 ・ライフが6以上のとき、青色。 ・ライフが3~5のとき、黄色。 ・ライフが1~2のとき、赤色。 となるようにしてみましょう。 ↑のようにライフの色を黄色にする場合、「ライフが3以上である」「ライフが5以下である」の二つの条件が必要そうです… こんなときは`&&`を使って以下のように書けます! 《コード3》 ```cpp #include <iostream> int main(){ int playerLife;//ライフの数 String playerLifeColor;//ライフの色名 std::cin >> playerLife; if(6 <= playerLife){ playerLifeColor = "Blue"; }else if(3 <= playerLife && playerLife <= 5){ playerLifeColor = "Yellow"; }else{ playerLifeColor = "Red"; } std::cout << playerLifeColor << std::endl; return 0; } ``` `else if(3 <= playerLife && playerLife <= 5)`の部分は、「playerLifeが3以上**かつ**playerLifeが5以下の場合」と言い換えることができます。この「**かつ**」こそが`&&`の役割です。 ※ `3 <= playerLife <= 5` のように一つにまとめることはできないので注意! 他の論理演算子も以下に示しておきます。どれもよく使うので覚えておいた方が良いですよ! *** - &&  意味      and  基本構造    if(「条件1」&&「条件2」)  真になる条件  「条件1」がtrue**かつ**「条件2」がtrue - | |  意味      or  基本構造    if(「条件1」||「条件2」)  真になる条件  「条件1」がtrue**または**「条件2」がtrue - !  意味      not  基本構造    if(!「条件」)  真になる条件  「条件」が**false** *** ## switch-case文 次はライフが10まである中、1~10それぞれで色を変えてみましょう。ここで、《コード2》のように`else if(playerLife == 1)`を10個繰り返すのはやや大変ですし、コードも長く、見づらくなってしまいます。ここでswitch-case文の出番です! 《コード4》 ```cpp #include <iostream> int main(){ int playerLife;//ライフの数 String playerLifeColor;//ライフの色名 std::cin >> playerLife; switch(playerLife){ case 1: playerLifeColor = "Red"; break; case 2: playerLifeColor = "Orange"; break; case 3: playerLifeColor = "Magenta"; break; case 4: playerLifeColor = "Pink"; break; case 5: playerLifeColor = "Yellow"; break; case 6: playerLifeColor = "Blue"; break; case 7: playerLifeColor = "SkyBlue"; break; case 8: playerLifeColor = "LightBlue"; break; case 9: playerLifeColor = "Green"; break; case 10: playerLifeColor = "YellowGreen"; break; default: playerLifeColor = "Black"; break; } std::cout << playerLifeColor << std::endl; return 0; } ``` まず、switchの隣の()内には変数や条件を書きます。今回は`playerLife`を入れてますね。そして次の行からはcaseがずらっと並んでいます。仕組みをざっくり言うと、**()内の値とcaseの横の値が一致するとき、そのcaseの部分からbreakまでのコードを実行**します。上の例で言えば、playerLifeが3の時は、`case 3:` と `break;`の間の`playerLifeColor = "Magenta";`を実行してくれます。 あと、各caseには基本breakが必要になります。ここのbreakには、実行時switch文から抜け出してくれるという役割があります。めちゃくちゃ伝わりづらいと思うので上の例で説明すると、もしも`case 1:`と同行のbreakが無かったら、`playerLifeColor = "Red";`だけでなく、`playerLifeColor = "Orange";`も実行されてしまいます。これはbreakが無いためにswitch文が終わらず、次の行の`case 2:`も実行されてしまうためです。break忘れには注意しましょう。 最後に、defaultについてです。これはif文で言うelseのようなもので、**()内の値がどのcaseの値とも一致しないときに実行される箇所**です。上の例で言えば、playerLifeが0や11、100のときに`playerLifeColor = "Black";`が実行されるのです。 ## ループ文 ゲームを作っていると、「100個分の床ブロックを生成したい」だとか、「40個分の弾幕を生成したい」ということがあります。生成するためのコードを100個分書くなんてことは非常に面倒なので、ここでループ文を身につけましょう! 今まで数値や文字を出力してきましたが、今回は`_`を床ブロック1つ分と見なして、ステージを作るような感じでやっていきましょう。イメージは↓のような感じです。 ``` _______________________________ ``` ### while文 まず以下のコードを書いてみましょう。 《コード5》 ```cpp #include <iostream> int main(){ int blockNum = 0;//ブロックの数 while(blockNum < 30){ std::cout << "_"; blockNum++;//インクリメント } return 0; } ``` whileの横の()には、ifと同じように「条件」を書きます。ifと違うのは、**()内がtrueである限り、{}内を実行し続ける**という点です。 1行づつ見ていきましょう。また、「プログラムは原則main関数内を上から1行ずつ実行する」ということも念頭に置いておいてください。 まず最初に`while(blockNum < 30)`に到達時、blockNumは0で`blockNum < 30`を満たすため{}内を実行し、`_`を1つ出力してblockNumの値に1を足します。(1ループ目) 次に`while(blockNum < 30)`に到達時、blockNumは1で`blockNum < 30`を満たすため{}内を実行し、`_`を1つ出力してblockNumの値に1を足します。(2ループ目) これを繰り返します。 ざっと飛ばして30ループ目、blockNumは29で`blockNum < 30`を満たすため、`_`を1つ出力してblockNumの値に1を足します。 そして31ループ目、blockNumは30であるため、`blockNum < 30`を満たしません。よって、{}内を実行せずにループが終了します。 ### for文 ループ文にはもう一つ、for文というものがあります。↑と同じ出力結果を こちらのループ文でも書いてみましょう。 《コード6》 ```cpp #include <iostream> int main(){ for(int i = 0;i < 30;i++){ std::cout << "_"; } return 0; } ``` for文の()には、`for(「初期化式」;「条件式」;「更新式」)`というように記述します。 **「条件式」がtrueである限り、{}内を実行し続ける**というのはwhile文と同じです。「初期化式」と「更新式」は↓で説明します。 また1行ずつ見ていきましょう。 まず最初に「初期化式」により、`i = 0`と初期化します。1ループ目のみに実行される箇所だと思ってくれればよいです。この時点でiは0で`i < 30`を満たすため{}内を実行し、`_`を1つ出力します。その後に更新式の内容を反映させます。例の場合、iに1を加えています。 2ループ目に入った時点で、iは1で`i < 30`を満たすため{}内を実行し、`_`を1つ出力します。その後更新式により、iに1を加えます。 またざっと飛ばして30ループ目、iは29で`i < 30`を満たすため{}内を実行し、`_`を1つ出力します。その後更新式により、iに1を加えます。 最後に31ループ目、iは30で`i < 30`を満たしません。よって{}内を実行せずにループが終了します。 ### continue と break 次に、ステージに穴を作る感覚でやってみましょう。左から数えて4の倍数の場所には穴(空白)を作ってみます。完成図は↓の感じ。 ``` ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ```