Pythonロボティクスコース レッスン 17 *

テーマ.4-4 かみつきワニゲームの制作

乱数機能を学んでロボットにランダムな動きを加えよう

このレッスンで学ぶこと

このレッスンでは、リストを操作する各種メソッドと乱数を発生する機能について学びます。また、リストと乱数を使って、センサー(赤外線フォトリフレクタ)に指を近づけるとコンピュータ内部でくじを引き、はずれを引くとワニ型ロボットがかみつく動作をするロシアンルーレット風ゲームを作成します。

新しいPython文法の学習

始めに、今回のレッスンで初めて扱うPythonの文法について学習しましょう。

2. 1 リストを操作するメソッド

プログラムを書く際には、データをまとめて扱いたいということが良くあります。データを1つにまとめる方法としては、既に学習した、リスト や 辞書 が考えられます。Pythonでは、リストや辞書の要素を操作するための便利なメソッドがいくつか用意されていますので、見ていきましょう。

■ 要素の追加を行うメソッド

リストに対して要素を追加するメソッドは以下の3つがあります。

  • .append(x) : リストの末尾に要素 x を1つ追加します。
  • .insert(i, x) : リストの任意の場所 i に要素 x を1つ追加します。
  • .extend(xs) : リストの後ろにリスト xs を連結します。
■ .append(x)メソッド

.append(x) メソッドは引数を1つとり、受け取った値をリストの末尾に追加します。

【 サンプルコード 2-1-1 】
(実行結果)
■ .insert(i, x) メソッド

.insert(i, x) メソッドは引数を2つとり、1つ目の引数で値を追加したい場所を指定できます。

【 サンプルコード 2-1-2 】
(実行結果)

これらの結果より、もともとその位置にあった値の1つ手前に、値が追加されることがわかります。

■ .extend(xs) メソッド

.extend(xs) メソッドは .append(x) メソッドと似ていますが、値をリストの末尾に追加するのではなく、リストを末尾に連結します。

【 サンプルコード 2-1-3 】
(実行結果)

■ 要素の削除を行うメソッド

次リストに対して要素を削除するメソッドは以下の3つがあります。

  • .pop(i) : リストの任意の場所 i から要素を1つ削除します。 (もし指定が無い場合、末尾から1つ削除します。)
  • .remove(i) : リストの要素から i に等しい最初の要素を1つ削除します。 (削除するものが存在しない場合エラーが発生します。)
  • .clear() : リストの全ての要素を削除します。
■ .pop(i) メソッド

.pop(i) メソッドは引数を1つとり、受け取った値をインデックスとして、要素の削除を行います:

【 サンプルコード 2-2-1 】
(実行結果) ※左から「0番目」「1番目」・・・と数える
■ .remove(i) メソッド

.remove(i) メソッドは引数を1つとり、受け取った値をリストから探し出し、最初の1つを削除します。

【 サンプルコード 2-2-2 】
(実行結果)
■ .clear() メソッド

.clear() メソッドは、リストから全ての要素を削除します。

【 サンプルコード 2-2-3 】
(実行結果)

2. 2 リストとジェネレータ

Studuino:Bitのような小型コンピュータでプログラミングを行うとき、メモリ容量 というものに注意する必要があります。

メモリとは、コンピュータがなんらかの作業を行うときに使用する机のようなもので、メモリ容量が大きいほど机が広く、同時に扱える作業の量が多くなります。メモリ容量は高性能なコンピュータであるほど大きくなります。

例えば、Studuino:Bit上でものすごく大きいサイズのリストを作成すると、メモリ容量が不足していることを示すエラーが発生します。

【 サンプルコード 2-3-1 】

このプログラムを実行すると、以下のように、MemoryError: memory allocation failed, allocating XXX bytes と表示されます。

(実行結果)

このようなメモリ不足への対処として、Pythonにおいては「値が必要になったときに、必要な部分だけを計算する」仕組みがあります、これを ジェネレータ と呼びます。

よく用いるジェネレータが、for文を使った反復処理で何度も取り扱ってきたrange()関数です。これは、順番に数字を生成してくれるジェネレータです。

例えば、以下のプログラムを実行してみてください。

【 サンプルコード 2-3-2 】
(実行結果)

もしそのままリストを作成した場合、1,000,000個もの要素を持つリストは、【 サンプルコード 2-3-1 】でエラーが発生したように、Studuino:bitでは扱うことができません。ですがこのように、ジェネレータであればそれが可能になります。

range()関数は、引数を3つ取ることができ、それぞれ次のような機能を持ちます。

  • range(N) : 0 ~ N - 1 までの数値を生成できるジェネレータを作成する。
  • range(start, stop) : start ~ stop - 1 までの数値を生成できるジェネレータを作成する。
    例)range(1, 10) ⇒ 1 ~ 9 までの数値を生成できるジェネレータとなる。
  • range(start, stop, step) : start ~ stop - 1 までの数値を、step 刻みで生成できるジェネレータを作成する。
    例)range(1, 10, 2) ⇒ 1 ~ 9 までの数値を、2 刻みで生成できる ( 1 , 3 , 5 … ) ジェネレータとなる。

なお、Lesson 4-1で「定数」という考え方を学習しましたが、ジェネレータは 書き換えが不可能 という意味で、定数と同じ役割をもつ考えることもできます。

【 サンプルコード 2-3-3 】
(実行結果)

もし、ジェネレータから読み書きが可能な通常のリストを作成したい場合、list(~) 関数を用います。

【 サンプルコード 2-3-4 】

2. 3 ランダムさを取り扱う

プログラムを作成していると、ランダムに何かを行いたいということがあります。例えば、くじ引きゲームをStuduino:bitで作成する場合、用意したくじの中からランダムに引くといった処理が必要になります。

Pythonでは、random モジュールを使用することで、さまざまなランダムさを取り扱うことができます。代表的なものは下記の通りです。

  • random.random() : 0 以上,1未満の 実数 をランダムに生成します。
  • random.randint(a, b) : a 以上,b 以下の 整数 をランダムに生成します。
  • random.uniform(a, b) : a 以上,b 以下の 実数 をランダムに生成します。
  • random.choice(xs) : リスト xs を引数にとり、ランダムに1つ要素を選んで返します。

■ random() 関数

random() 関数は、ランダムに数値を生成する最も基本的な関数です。0~1の範囲でランダムな浮動小数点数を生成します。

【 サンプルコード 2-4-1 】
(実行結果の例)
※実行する度に結果が変わることを確認しましょう。

■ random.randint(a, b) 関数

random.randint(a, b) 関数は、ランダムに数値を生成する範囲を決めることができ、なおかつその数値を整数に限定します。

【 サンプルコード 2-4-2 】
(実行結果の例)
※実行する度に結果が変わることを確認しましょう。

■ random.uniform(a, b) 関数

random.uniform(a, b) 関数は、random.randint(a, b) 関数の実数(浮動小数点数)版です。

【 サンプルコード 2-4-3 】
(実行結果の例)
※実行する度に結果が変わることを確認しましょう。

■ random.choice(xs) 関数

random.choice(xs) 関数は、文字列やリスト、タプルなどシーケンスなデータxsからランダムに1つの要素を返します。くじ引きゲームなどを作成する際に使いやすい関数と言えるでしょう。

【 サンプルコード 2-4-4 】
(実行結果の例)
※実行する度に結果が変わることを確認しましょう。

ワニ型ロボットの組み立て

組立説明書を開き、手順に沿ってワニ型ロボットを組み立てましょう。

3. 1 組み立てに必要なパーツ

  • Studuino:bit×1
  • ロボット拡張ユニット×1
  • 電池ボックス×1
  • サーボモーター×1
  • 赤外線フォトリフレクタ×1
  • センサー接続コード(3芯15cm)×1
  • ブロック基本四角(黒)×1
  • ブロック三角(グレー)×4
  • ブロック三角(赤)×4
  • ブロックハーフA(グレー)×2
  • ブロックハーフC(白)×4
  • ブロックハーフD(白)×6
  • ステー×4
【 アーテックブロックの形状 】
【 ワニ型ロボットの組み立て説明書 】

ワニ型ロボットの組み立て説明書

かみつきワニゲームのプログラム作成

かみつきワニゲームは、次の機能を組み合わせて作成します。

  1. ボタンAを押すとゲームを開始する機能
  2. くじを用意して、はずれを決める機能
  3. センサー(赤外線フォトリフレクタ)が反応すると、くじを引く機能
  4. はずれを引いたときにワニ型ロボットがかみつく機能
  5. はずれを引かなかったときに音で知らせる機能

また、各機能のプログラムは次の流れで順番に実行します。

【 かみつきワニゲームのプログラムの処理の流れ 】

プログラムの見通しを良くするため、各機能はできるだけ関数にまとめて実行します。次の手順に沿って順番に実装し、かみつきワニゲームのプログラムを完成させましょう。

4. 1 くじを用意してはずれを決める機能の作成

はじめに、くじとなる数字のリストを用意します。このリスト中からいくつかの数字をはずれのくじとして選び、別のリストに保存します。センサーが反応するたびにこのくじを引き、引いたくじの数字がはずれくじのリストに含まれていれば、ワニ型ロボットがかみつく動作をします。このはずれくじの数字を決めるコードを書き、関数にまとめましょう。

■ くじの数とはずれくじの数を決める

はずれの引きやすさは、全体のくじの数とはずれくじの数で決まります。今回は一度引いたくじは元に戻さない(リストから除く)方法でプログラムを作成するため、後で引くほど、はずれくじを引く確率が高くなります。

それぞれの数を決めて次の変数に保存しましょう。

■ はずれのくじを選ぶ関数を作成する

新たに関数を定義します。list()関数range()関数の組み合わせで、決めたくじの数と同じ長さをもつ数字のリストを作成します。また、はずれくじを保存するための空のリストも用意します。このリストにランダムに選んだ数字を追加していきます。

追加【4~6行目】

はずれくじをランダムに選ぶためにrandomモジュールchoice() 関数を使います。はずれくじの数だけ繰り返しchoice()関数でリストlotteriesからランダムに1つ数字を選びます。選ばれた数字は一時的に変数に保存し、append()メソッドでリストlost_lotteriesに追加し、remove()メソッドでリストlotteriesからその要素を削除します。

追加【1行目、9~13行目】

これで、「くじを用意して、はずれを決める機能」が完成しました。

4. 2 センサーが反応するとくじを引く機能の作成

指を近づけたことは、ワニ型ロボットに取り付けた赤外線フォトリフレクタで感知します。まずは、指を近づけたときの赤外線フォトリフレクタの値から確認していきましょう。

■ 赤外線フォトリフレクタのしきい値を決める

次のコードを追加して、赤外線フォトリフレクタの値を調べます。

変更・追加【1行目、3行目、8行目、10行目~13行目】

上のプログラムを実行し、ワニ型ロボットの口を開けた状態で、赤外線フォトリフレクタの表面から少し離した所に指を固定して、ターミナル上に表示された値を確認します。

(ターミナルの表示例)

この値を参考にして、指が近づいた と判断できる赤外線フォトリフレクタの しきい値 を決めましょう。また、次から以下の4行のコードは使わないため、削除しておきます。

■ ゲーム開始後に指が近づいたことを感知するとくじを引く関数を作成する

決めたしきい値は変数に保存して使います。くじを引く処理は、新たに関数を定義してその中にコードをまとめます。この関数はゲーム開始時に実行します。ゲーム開始直後にlist()関数とrange()関数の組み合わせでくじを作成します。また、用意したchoice_lost_lotteries()関数ではじれくじのリストを作成します。その後は無限ループで赤外線フォトリフレクタの値を繰り返し取得し、しきい値を超えた場合は、randomモジュールのchoice()関数でリストlotteriesからランダムに1つ数字を選び、変数に保存します。

追加【9行目、20~27行目】

4. 3 はずれを引くとかみつく機能の作成

続けて、引いたくじ(数字)がはずれの場合はワニ型ロボットがかみつく動作を行い、はずれでない場合は音で知らせる機能を作成します。

■ かみつく動作と音で知らせる関数の作成

かみつく動作の関数では、ブザーから低い音を鳴らしながら次の動きを3回繰り返します。

音ではずれでないことを知らせる関数には短く高い音を鳴らす処理と次のくじを引くまでの間にすこし時間をあけるために1秒間処理を停止するコードをまとめます。

追加【1~2行目、12行目、14~21行目、23~25行目】

■ かみつく動作と音で知らせる関数の作成

引いたくじ(数字)がはずれかどうかを判定して、上で用意した2つの関数bite()sound_of_safe()を実行します。かみつく動作を行ったあとは、無限ループを抜けて一度ゲームを終了します。はずれ以外を引いた場合は、くじのリストlotteriesからそのくじ(数字)をremove()メソッドで削除します。

追加【44~49行目】

4. 4 残りの機能の作成とプログラム全体の流れのまとめ

最後にゲーム開始音を鳴らす関数とワニ型ロボットを初期状態にリセットする関数を用意し、無限ループで始めに確認した全体のプログラムの流れにもとづいて順番に各関数を実行するコードを追加してプログラムを完成させましょう。

【かみつきワニゲームのプログラムの処理の流れ】

【 サンプルコード 4-5-1 】
変更・追加【1行目、27~30行目、32~33行目、60~66行目】

課題:はずれを引く確率を常に一定にしたプログラムへの変更

上で完成したプログラムはくじを引くたびに、はずれを引く確率が上がるようになっていました。ここでは課題として、常に一定の確率ではずれを引くようにプログラムを変更してみましょう。

<ヒント>

下の絵を参考にして、確率を一定にするための条件をよく考えましょう。

5. 1 プログラムの作成例

【 サンプルコード 4-5-1 】では、57行目のlotteries.remove(num)で、一度引いたくじの数字をリストlotteriesから除外していましたが、ここでは引いたくじは除外せず、元に戻すことになるので、この1行のコードを削除するだけで、はずれの確率を常に一定にすることができます。

削除【57行目】

おわりに

6. 1 このレッスンのまとめ

このレッスンでは新たに次のことを学習しました。

  • メソッドを使ったリストの要素の操作
    追加:append(), insert(), extend()
    削除:pop(), remove(), clear()
  • list()関数とrange()関数を組み合わせた数字リストの作成
  • メモリの使用量を抑えられるジェネレータ
  • 乱数を扱うrandomモジュールとその関数
    random(), randint(), uniform(), choice()

また、学習した乱数機能を応用してくじ引きの仕組みをつくり、はずれを引くとワニ型ロボットがかみつくゲームを制作しました。

6. 2 次のレッスンについて

次のレッスンからは、より高度なプログラム制御を行うためのPythonの文法を重点的に学習していきます。

TOP