CHaser解説(Blockly編)

第2部 チュートリアル

9章 変数と関数を活用する

⚠️ ネタバレ注意

各ステージの「解答例」は折りたたんであります。自分の力で挑戦してから開いてください。

9章 変数と関数を活用する

ここまでのステージでも、条件分岐や繰り返しを駆使して、それなりに複雑なプログラムを組んできました。しかし、プログラムが複雑になるほど、同じような処理があちこちに散らばって、組み立てるのも見返すのも大変になっていきます。この章では、プログラムを整理して読みやすくするための、変数と関数という2つの道具を学びます。

変数のブロックは2つで1組

7-1に入る前に、変数を表すブロックを見ておきましょう。ステージ7-1のツールボックスには、ピンク色のブロックが2種類、最初から用意されています。

図:ステージ7-1の変数ブロック。上が値を取り出す側、下が値を入れる側
図:ステージ7-1の変数ブロック。上が値を取り出す側、下が値を入れる側

上の移動方向が、変数の中身を取り出すブロックです。他のブロックのくぼみにはめ込んで使います。下の移動方向 に 〔 〕をセットが、変数に値を入れるブロックです。「をセット」と書いてあるほうが入れる側、と覚えてください。

変数は「名前の付いた箱」です。「セット」で箱に入れておけば、あとは移動方向ブロックを置くだけで、いつでも中身を取り出せます。なお、このステージでは箱の名前(「移動方向」)はあらかじめ決められています。自分で新しい変数を作れるようになるのは、ステージ8以降と本番のプログラミング画面です。

7-1 変数を活用しよう

課題:右方向にアイテムがあるかどうかを一度だけ調べて方針を決め、あとはその方針に沿ってずっと進み続けるプログラムを作ろう。

ステージ7-1のマップとクリア条件

ステージ7-1のマップ
ステージ7-1のマップ
クリア条件 内容
アイテム 1個ゲットする
ブロック数 35個以下
ターン数 100ターン以内

黄色の枠が自分(Cool)のスタート位置です。すべての条件を同時に満たすとクリアです。アイテムの位置は毎回変わります(マップの半透明の表示は、出現位置の候補です)。

💡 考えるヒント

  • 5章・6章で学んだ遠方探査と「含まれているか」の判定を使って、右方向にアイテムがあるかどうかを一度だけ調べます。
  • 調べた結果(右へ進むべきか、左へ進むべきか)を、後からずっと使い続けたい場合、その結果をどこかに「覚えておく」仕組みが必要です。
  • このステージのツールボックスには、ピンク色の移動方向ブロックと、移動方向 に 〔 〕をセットブロックが最初から用意されています。この2つが変数のブロックです。片方が「箱に入れる」係、もう片方が「箱から取り出す」係です。どちらがどちらでしょうか。
  • 変数に名前を付けて値をセットし、「ずっと繰り返す」の中ではその変数の中身を使って移動する、という2段階の構成にできないか考えてみましょう。

まずは自分で変数ブロックを使って組んでみましょう。


解答例

解答例を見る
7-1 変数を活用しよう
7-1 変数を活用しよう

このステージでは「移動方向」という名前の変数を使います。まず、右方向に遠方探査(search)した結果の中に、アイテムが含まれているかどうかを調べます。含まれていれば変数「移動方向」に「右」を、含まれていなければ「左」をセットします。そして「ずっと繰り返す」ブロックの中では、判定のたびに条件を書き直すのではなく、「移動方向」変数の中身の方向へひたすら移動し続けます。

変数が読みやすさを生む仕組み

もし変数を使わずに書こうとすると、「ずっと繰り返す」の中で毎回「アイテムが右にあったかどうか」を判定し直す必要が出てきます。しかし、このステージでは最初の1回だけ判定すれば、あとはその結果(右へ進むか、左へ進むか)がターンをまたいでも変わりません。「一度決めた方針を、変数という名前の箱に入れておき、後からその箱の中身を何度も使い回す」というのが変数の基本的な使い方です。買い物リストをメモに書いておいて、後で何度も見返すのと同じ感覚です。変数に分かりやすい名前(「移動方向」など)を付けておくことで、後でプログラムを見返したときに「これは何のための値だったか」がすぐに分かる、というメリットもあります。

注意したいこと

  • 変数に値をセットするタイミングを間違える:「ずっと繰り返す」の中で毎回セットし直してしまうと、変数を使う意味が薄れてしまいます(判定のたびに条件が変わるステージなら、あえて繰り返しの中でセットし直すこともあります。目的に応じて判断しましょう)。
  • 変数名を後から見て分からなくなる:「a」や「x」のような名前より、「移動方向」のように何を表すかが分かる名前を付けたほうが、後で読み返すときに役立ちます。

関数のブロックは「定義」と「呼び出し」の2種類

7-2に進む前に、関数のブロックも見ておきましょう。ステージ7-2のツールボックスには、紫色のブロックが4つ用意されています。

図:ステージ7-2の関数ブロック。大きいほうが定義、小さいほうが呼び出し
図:ステージ7-2の関数ブロック。大きいほうが定義、小さいほうが呼び出し

大きくて中にすき間があるブロック(関数 アイテムゲット …返すと関数 ランダム移動)が、関数を定義するブロックです。このすき間に処理のブロックを入れて、中身を作ります。

小さいブロック(アイテムゲットとランダム移動)が、その関数を呼び出すブロックです。メインの処理には、こちらを置きます。

2つの定義ブロックをよく見ると、形が違うことに気づきます。アイテムゲットのほうには「返す」というくぼみが付いていて、結果を呼び出し元に返せます。ランダム移動のほうにはそれがなく、実行するだけです。この違いが、9章の冒頭で触れた「戻り値」のあるなしです。

7-2 関数を使ってみよう

課題:「アイテムを探して取る」処理と「ランダムに動く」処理を、それぞれ名前の付いた部品にまとめて、メインの処理をすっきりさせよう。

ステージ7-2のマップとクリア条件

ステージ7-2のマップ
ステージ7-2のマップ
クリア条件 内容
アイテム 10個ゲットする
ブロック数 実質、制限なし
ターン数 100ターン以内

黄色の枠が自分(Cool)のスタート位置です。すべての条件を同時に満たすとクリアです。

💡 考えるヒント

  • このステージのツールボックスには、紫色の関数ブロックが4つ用意されています。
  • 関数の中身にあたるブロックの塊も、アイテム発見・ランダム移動というラベル付きで用意されています。これらを定義ブロックの中にはめ込むのが、このステージの組み立てです。
  • 関数を定義するブロックは、メインの処理とは直接つながらない、独立した塊としてワークスペースに置かれることを覚えておきましょう。
  • メインの処理(「ずっと繰り返す」ブロック)では、関数の中身を全部書く代わりに、関数の名前が付いたブロックを呼び出すだけで済ませられないか考えてみましょう。

まず、それぞれの処理を1つの関数としてどう定義するか、自分で組んでみましょう。


解答例

解答例を見る

この解答例では「アイテムゲット」と「ランダム移動」という2つの関数を定義し、メインの処理からそれらを呼び出しています。まずメインの処理を見てみましょう。

図:メインの処理。ターンを待ち、アイテムが見つからなければランダム移動を呼び出す
図:メインの処理。ターンを待ち、アイテムが見つからなければランダム移動を呼び出す

メインの処理は「自分のターンを待つ→もしアイテムゲット関数の結果が『未発見』なら、ランダム移動関数を呼び出す」という、たった数個のブロックにまとまっています。実際の探索や移動の手順は、次の2つの関数の中に押し込められています。

図:アイテムゲット関数。上下左右のアイテムを順に確認し、取れたら結果を返す
図:アイテムゲット関数。上下左右のアイテムを順に確認し、取れたら結果を返す

「アイテムゲット」関数は、上下左右にアイテムがあるかどうかを順番に確認し、あれば取りに行って「ゲットだぜ」という結果を返します。どこにも見つからなければ「未発見」を返すので、メインの処理はその戻り値を見て次の行動を決められます。

図:ランダム移動関数。ブロックのない方向をリストに集め、その中から1つを選んで移動する
図:ランダム移動関数。ブロックのない方向をリストに集め、その中から1つを選んで移動する

「ランダム移動」関数は、ブロックのない方向をリストに集め、その中からランダムに1つを選んで移動します。ブロックのある方向を最初から候補から外しているので、壁に突っ込んで衝突する心配がありません。

関数が読みやすさを生む仕組み

関数を使わずに全部の処理を1本の流れで書くと、「アイテムを探す処理」と「ランダムに動く処理」が入り混じって、どこからどこまでが何のための処理か分かりにくくなります。関数を使うと、「アイテムゲット」「ランダム移動」という名前をつけた小さな部品に処理を切り分けられます。メインの処理を読むときは、部品の中身を気にせず「アイテムゲットを試して、ダメならランダム移動」という大きな流れだけを追えばよく、逆に部品(関数)の中身を直したいときは、その部品だけに集中して修正できます。これは、料理のレシピを「下ごしらえ」「炒める」「盛り付け」のように工程を分けて書くのと同じ考え方です。

注意したいこと

  • 関数を定義しただけで満足してしまう:関数はブロックを組んだだけでは実行されません。メインの処理の中で、その関数の名前が付いたブロックを呼び出して、はじめて中身が実行されます。
  • 関数の中で使っている変数と、外で使っている変数を混同する:関数の中だけで使う一時的な値と、プログラム全体で使い回す変数を区別できるようにしておくと、後の複雑なプログラムでも混乱しにくくなります。
  • 1つの関数に詰め込みすぎる:あれもこれもと1つの関数に処理を詰め込むと、結局読みにくくなってしまいます。「アイテムを探す」「ランダムに動く」のように、1つの関数には1つの役割だけを持たせるのがコツです。

演習問題

  1. 7-1のステージで、もし「アイテムが右になければ、さらに上を確認し、それもなければ左」という3択にしたい場合、変数「移動方向」をどう使えばよいか考えてみましょう。
  2. 「相手にブロックを設置する」処理(8章)を、関数として切り出すとしたら、関数にどんな名前を付け、どんな処理を中に入れますか。

付録2への案内:ステージ7は全3課題です。本文で扱った7-1・7-2に加えて、7-3「関数を使ってみよう2」の解答例を付録2「ステージ7 変数と関数」に掲載しています。7-3は、7-2の「その場で移動してしまう関数」を「進む方向だけを返す関数」に作り替えた発展形で、関数の役割をそろえるとメインの処理がどれだけ読みやすくなるかがよく分かる例です。

YouTubeチャンネル

U-15プロコン舞鶴のYouTubeチャンネルを開設しました。大会の情報などを発信しています。 チャンネルを見る