ボタン¶
これまでは、デバイスに何かをさせるコードを作成しました。これは 出力 と呼ばれます。しかし、物事に反応するためのデバイスも必要です。このような事は 入力 と呼ばれます。
これを憶えるの簡単です: 出力はデバイスが世界に出すものであり、入力はデバイスが処理するものです。
micro:bit で入力を行う最も当たり前の手段は、 A
と B
のラベルのついた2個のボタンです。ボタンが押されたことに反応するには MicroPython が必要そうです。
これはとても簡単です:
from microbit import *
sleep(10000)
display.scroll(str(button_a.get_presses()))
このスクリプトの全貌は、1万ミリ秒(すなわち10秒)スリープしている間にボタン A
を押した回数をスクロール表示するというものです。それでおしまい!
これはほとんど役に立たないスクリプトですが、面白い新アイデアをいくつか紹介します:
sleep
関数 は micro:bit を指定のミリ秒数だけスリープさせます。プログラムの実行を一時停止させたいなら、この関数を使うとよいです。関数 は メソッド のようなものですが、 オブジェクト にドットで結びつけられていません。button_a
というオブジェクトがあり、そのget_presses
メソッド で押した回数を得られます。
get_presses
は数値を返し、 display.scroll
は文字だけを表示するので、数値を文字列に変換する必要があります。これを行うのが str
関数です(「string」 の略 ~ 指定されたものを文字列に変換します)。
3行目はちょっと玉ねぎみたいになってます。括弧が玉ねぎ状になっているので、display.scroll
が str
を含み、それがまた button_a.get_presses
を含んでいることがわかるでしょう。Python は、最初に最も内側の答えを出し、次の外側に向かって実行していこうとします。これは 入れ子 (nesting)といいます。このようなコードは、ロシアのマトリョーシカ人形の作りと同じです。
あなたがボタンを10回押したとしましょう。Python が3行目で起こっていることをどう処理しているかは以下のとおりです:
Python は行全体を解釈して、 get_presses
の値を求めます:
display.scroll(str(button_a.get_presses()))
Python はボタンが何回押されたかを知ったので、この数値を文字列に変換します:
display.scroll(str(10))
もう、Python は何をスクロール表示するのかが分かりました:
display.scroll("10")
これは大変な作業のように見えるかもしれませんが、MicroPython はこれを非常に高速に行います。
イベントループ¶
何かが起こるのを待つプログラムが必要になることがよくあります。これを行うには、ボタンを押すなどの特定のイベントにどう反応するかを定義するコードの周りにループを作ります。
Python でループを作るために、 while
キーワードを使います。これは何かが True
であるかをチェックします。True
であるなら、ループの 本文 と呼ばれる コードブロック を実行します。そうでない場合は、ループから抜け出し(本文を無視して)、後のプログラムを続行します。
Pythonでは、コードブロックを簡単に定義できます。紙の上に書かれた to-do リストがあるとします。これはたぶん次のようなものになります:
Shopping
Fix broken gutter
Mow the lawn
To-do リストをもう少し具体的にしたいと思ったら、次のように書くかもしれません:
Shopping:
Eggs
Bacon
Tomatoes
Fix broken gutter:
Borrow ladder from next door
Find hammer and nails
Return ladder
Mow the lawn:
Check lawn around pond for frogs
Check mower fuel level
メインタスクがサブタスクに分解されていることが一目瞭然です。メインタスクの下に関連するものがサブタスクとして インデント (字下げ)された構造になっています。つまり Eggs
, Bacon
, Tomatoes
が Shopping
に関連づけられていることは明らかです。インデントすることで、タスクが互いにどのように関連しているかを一目で分かりやすくします。
これは 入れ子 (nesting)と呼ばれます。入れ子を使って次のようなコードブロックを定義します:
from microbit import *
while running_time() < 10000:
display.show(Image.ASLEEP)
display.show(Image.SURPRISED)
running_time
関数は、デバイスが始動してからのミリ秒数を返します。
while running_time() < 10000:
の行は動作時間が1万ミリ秒(すなわち10秒)未満であるかをチェックします。このチェックにとおり、 その実行中に見ていたならば 、イメージ Image.ASLEEP
を表示します。これが、先の to-do リストのように while
文の下にインデントされていることに注目してください。
もちろん、実行時間が 10000 ミリ秒以上になれば、その後の Image.SURPRISED
を表示します。どうしてかって? while
条件は False
になるので(running_time
はもう < 10000
ではありません)、ループが終了し、 while
ループのコードブロックの後のプログラムを続けて実行します。あなたのデバイスは 10 秒間眠ってから、驚いた顔で目を覚まします。
それを試してみてください!
イベントの処理¶
MicroPython がボタンを押すイベントに反応するようにしたい場合、ボタンが押されたかをチェックする is_pressed
を無限ループの中に入れます。
無限ループは簡単です:
while True:
# 処理の実行
(while
は何かが True
であるかをチェックし、そうであればコードブロックを実行するということを思い返してください。つまり、条件に True
を指定すると明らかに True
であるので、無限ループを実現できるわけです!)
簡単なサイバーペットを作りましょう。あなたが A
ボタンを押している場合を除き、常に悲しい顔をします。あなたが B
ボタンを押すと死にます。(これがとても楽しいゲームではないことが分かりますので、きっとあなたが楽しいゲームにする方法をあみだしてくれることでしょう):
from microbit import *
while True:
if button_a.is_pressed():
display.show(Image.HAPPY)
elif button_b.is_pressed():
break
else:
display.show(Image.SAD)
display.clear()
どのボタンが押されているかをチェックする方法がわかりますか? if
, elif
(「else if」 の短縮形), else
を使っています。これは 条件文 というもので、次のように処理します:
if 何か is True:
# 何かを行う
elif 他の何か is True:
# 別の何かを行う
else:
# さらに別の何かを行う
これは英語に非常に似ています!
is_pressed
メソッドは2つの結果だけを返します: True
か False
です。ボタンを押している場合は True
を返し、そうでない場合は False
を返します。上記のコードを日本語で表すと「永遠に、ボタン A が押されたら幸せな顔を表示し、ボタン B が押されたらループから抜け、さもなければ悲しい顔を表示します」となります。ループの外に抜ける(永遠に動き続けるプログラムを止める)には break
文を使います。
最後に、サイバーペットが死んで、ディスプレイを clear
します。
このゲームをあまり悲惨なものでなくする方法を考えてみませんか? 両方 のボタンが押されたことをチェックするにはどうしますか? (ヒント: Python には、複数の条件(True
または False
のどちらかを結果とするもの)のチェックを助ける論理演算子 and
, or
, not
があります。