読者です 読者をやめる 読者になる 読者になる

小学校の先生のためのSwift Playgrounds講座 コードを学ぼう1<論理演算子>【解答】

f:id:PSYuki:20170403225928p:plain

こんばんは。ツムさんです。

 

プログラミングなんてやったことないぜキリッ

 

という先生のための Swift Playgrounds を使ったセミナーです。

 前回は、ifを使った条件分岐コードを勉強しました。ifを使うことで、条件に一致したとき(もしくはしなかったとき)に実行したプログラムが書けるようになりました。前回までの記事はこちら。

 

psyuki.hatenablog.com

 

 

psyuki.hatenablog.com

 

 

psyuki.hatenablog.com

 

 

psyuki.hatenablog.com

 

第5回は論理演算子です。

 

 

論理演算子とは

論理演算子、、いきなり意味の分からない言葉が出てきました。

数学的には、補元則(x ∨ ¬x = 1, x ∧ ¬ x = 0)が成り立つブール束でとてもよくお世話になるブール関数のことと言えばいいのでしょうか。

 

 論理演算子は、ifの条件文をもっと細かく制御するために使うことができます。論理演算子という名のとおり、論理演算するための演算子で、Swift Playgroundsでは、論理積(AND)、論理和(OR)、否定(NOT)の3種類が登場します。

 

演算子はそれぞれ、下のような記号で表されます。&&や||、! のことを論理演算子と呼びます。

  • 論理積(AND) ⇒ &&
  • 論理和(OR) ⇒ || (バーティカルバー x 2つ)
  • 否定(NOT) ⇒ ! (ビックリマーク)

 

論理演算子は、ベン図で表現すると分かりやすいですよね。

Wikipediaにいい例が載っていたので引用します。

 

f:id:PSYuki:20170420224132j:plain

 

f:id:PSYuki:20170420224140j:plain

f:id:PSYuki:20170420224146j:plain

引用 論理演算 - Wikipedia

 

論理積というのは、2つの集合(ifの条件)があるときに、2つの集合(条件)の重なった部分(且条件)を指します。論理和というのは、2つの集合(条件)全体(又は条件)を指します。否定は言葉通りで、その集合の外(条件外)を表します。

 

つまり、ifにおいて、

 

if condP && condQ

 

と書くと、condPかつcondQが成立した場合を指し(且条件)、

 

if condP || condQ

 

と書くと、condPまたはcondQのどちらかが成立した場合を指します(又は条件)

 

否定は、

 

if !condP

 

と書き、condPが成立しなかった(否定)場合に、ifの中のプログラムが実行されることになります。

 

NOT演算子を使う

最初のステージは、NOT演算子(否定)を使います。

このステージは、Byteくんの正面に真っすぐ道が伸びていて、4マスのうち3マスは宝石が置かれています。1マスだけ、空のマスとなっていて、そのマスの左側には別の道が続いています。

 

空のマスは、「コードを実行」する度に位置が変わります。4マスという距離は変わりません。

f:id:PSYuki:20170420225200p:plain

宝石が無いマスをifを使ってチェックしたい。というわけです。

今までに使ったifの条件としては、

isOnGem(宝石マスの上である)やisOnClosedSwitch(Offスイッチマスの上である)を使ってきました。今回は、宝石マスの上に「居ない」ことをチェックする必要があります。ここでNOT演算子が登場します。

 

「宝石マスの上に居る」が isOnGem でしたので、「宝石マスの上に居ない」はNOT演算子(!)を使って、!isOnGem と書けます。

 

プログラムは、forループを使い、4マス分を繰り返し処理します。1マスずつ進みながら、「宝石マスの上に居ない」場合、左へ向きを変えて階段の先の宝石を取って戻ってきます。

 

プログラムは下のようになりました。

f:id:PSYuki:20170420225059p:plain

「宝石マスの上に居ない」のでなければ、「宝石マスの上に居る」ことになるので、elseの中には、宝石を取る(collectGem())コマンドを書いています。

 

f:id:PSYuki:20170420225831p:plain

クリアしました! Byteくんも大喜びです。

 

NOTで周る

このステージは、Offスイッチが置いてあるマス(ゴール)までの形が変わります。ただし、何度「コードを実行」しても、ゴールまでのマスの数は変わりません。常に13マスです。

 

変わるのは、蛇のようにくねっている道の折れる箇所が変わります。戸愚呂の巻き方が変わるんです。

f:id:PSYuki:20170420230055p:plain

行き止まりの場合(isBlocked)という条件は既出でしたね。このステージは、行き止まりでない限りは1マスずつ前進、そうでない場合(=行き止まりの場合)は左へ方向を変えてやることでクリアすることができます。

f:id:PSYuki:20170420230547p:plain

(見えませんが)この形でも、

f:id:PSYuki:20170420230612p:plain

こんな形でもクリアすることができました。

 

上のプログラムで問題なくクリアできますが、若干上長な書き方になっています。分かりますか?プログラムの記述量を少しでも減らすことは、非常に意味のあることです。

NOTを使わない書き方でもこのステージはクリアすることが出来ます。

 

for i in 1 ... 13 {

    if isBlocked {

        turnLeft()

    }

    moveForward()

}

toggleSwitch()

 

どうですか?ifのプログラムが少しだけ短くなりました。同じことをするのに、プログラムを簡潔に書けるならそうするべきですが、Swift Playgroundsは教育用アプリなので、あえてNOT演算子を使っています。

 

面白いことに、NOTを使わないプログラムでこのステージをクリアすると、下のように「つっこみ」が入ります。

学習には独創力は要らないということですね。。

f:id:PSYuki:20170420231152p:plain

 

両方正しければ合格

このステージは論理積(AND)を使います。論理積を使うというくらいなので、ifの条件としては2つ以上の条件が必要です。ステージを見ると、Offスイッチが3つあります。最初のOnになっているスイッチは常にOnなので無視できます。

 

さて、このOffスイッチを押しにいくためにはどういった条件が必要になるでしょうか。

Byteくんの正面には、6個の宝石が並んでいます。スイッチへ続く道が伸びているマスも伸びていないマスも宝石は置かれているために、「宝石マスの上に居る」というisOnGem条件だけでは、区別できません。

 

よーくステージを見ると、道が分かれるマスの左手側(下の写真の上側)には、壁が存在しているのが分かります。見つけられますか??

f:id:PSYuki:20170420231342p:plain

「宝石マスの上に居る」条件と「左手が壁(行き止まり)」の2つの条件が同時に満たせればよさそうです。

 

 この2つの条件を論理積(AND⇒&&)でつないで ifを書いてみます。

 

if isBlockedlLeft && isOnGem

 

と書けます。

f:id:PSYuki:20170420231926p:plain

if isBlockedLeft

 

じゃダメ?と思うかもしれませんが、

この条件では、2マス目の宝石が無いマス(だけど左側には壁)に停まったときにも条件が成立してしまい。スイッチ(Onスイッチなのに!)を押しに行ってしまうのでダメです。宝石が無いマスもあり、左側に壁があってもなくても、宝石マスの上に居るなら宝石を取るためにelse ifを使っています。

f:id:PSYuki:20170420232341p:plain

クリアしました!

 

一方でも正しければ合格

このステージは論理和(OR)を使います。

f:id:PSYuki:20170420232401p:plain

ワープマスがありますが必ず通る必要があるのであまり意識しないでおきましょう。このステージは、方向を変えるための条件を考える必要があります。宝石マスがゴールなので、ここまでたどり着くまでの道のりをステージをグルグル回転させながら見てみましょう。

 

Byteくんは、何度も向きを変えながら進む必要がありますが、どうやら常に右に向きを変えながら進んでいけばゴールまでたどりつけそうです。

 

では、どんな条件のマスに停まったときに向きを変えればいいのでしょうか。

 

下の写真はByteくんのスタート位置です。1マス進むと行き止まりで、早速右へ向きを変える必要があります。

f:id:PSYuki:20170420232448p:plain

 

次の写真はワープマスの手前です。ここでもワープマスへ入るために向きを変える必要があります。

f:id:PSYuki:20170420232822p:plain

この2つのマスはどういった条件のマスでしょうか?

 

1つ目は、「行き止まり」でした。2つ目は、行き止まりではないけど、「左側に壁」がありますね。

 

この2つの条件を論理和(OR)で

 

if isBlocked || isBlockedLeft

 

と書けます。

この条件のときに右へ向きを変えるようにして、あとはひたすら真っすぐ進むようにプログラムしてあげると、

f:id:PSYuki:20170420233042p:plain

 

無事にクリアできました!

f:id:PSYuki:20170420233217p:plain

 

論理の迷宮

論理演算子最後のステージは、少し複雑です。一見すると処理のパターンを見つけ辛いコースになっています。

 

先ずは、メインストリートから外れたところに置かれている3つの宝石をどうやってとるか?を考えます。3つの宝石は、メインストリートから(Byteくんの進む方向から見て)常に右手側に位置します。

そして、道が枝分かれするマスには、宝石とOffスイッチの両方が配置されています。

宝石とOffスイッチの両方が置かれているのは、3箇所の枝分かれするマスだけです。

 

ということは、「宝石マスの上に居る」と「Offスイッチの上に居る」の条件を論理積(AND)で繋いであげれば、枝分かれした先の宝石を取りに行けそうですね。

 

枝分かれした先の宝石を取りに行く処理を関数(getGem)にしてみました。ifで条件が一致したときは、getGemを呼び出すことにします。

f:id:PSYuki:20170420234140p:plain

 

次に考えなければならないのは、Byteくんの方向を変える条件です。

 

Byteくんは、そのまま真っすぐ進むと壁にぶつかってしまうので、壁にぶつかった時点で左へ向きを変える必要があります。そのあと、再び左へ向きを変えて、コの字型に進む必要がありますが、この条件はどうたらいいでしょうか。

f:id:PSYuki:20170420233243p:plain

 

1つ目の条件は、「行き止まりである」です。2回目に向きを変える必要があるマスは行き止まりではないのですが、「右手側が壁」であることが使えそうです。

この2つの条件を論理和(OR)で繋いであげるとよさそうです。

f:id:PSYuki:20170420234100p:plain

 

論理積(AND)と論理和(OR)の条件を使ったif文は下のプログラムのように書けます。論理積(AND)の条件が成立したときは、枝分かれした先の宝石を取りに行く(getGem)のでした。

として論理和(OR)の条件が成立したときは、「左へ向きを変える」のでした。向きを変えるマスに停まったときは、実は足元にはOffスイッチがあるので、忘れずに押して(toggleSwitch)しておきます。

この2つの条件以外にも、単に宝石が置いてあるだけのマスもあるので、2つ目のelse ifには、「宝石マスの上に居ること」も追加しています。

f:id:PSYuki:20170420234305p:plain

 

無事にクリアできました!

f:id:PSYuki:20170420234645p:plain

 

論理演算子を使うことで、ifを使った細かい場合分けが出来るようになったことが理解できたと思います。

 

次回は、whileループを説明します。