カナデKanade

14. 小さなプログラムを作る

ここまで学んだことを集めて、成績表、数当て、やることリストを一から作ってみましょう。

この章で学ぶこと

  • 作りたいものを小さな部品に分ける方法
  • 部品を1つずつ作って実行しながら、少しずつ育てる方法
  • 3つの小さなプログラム: 成績表、数当て、やることリスト

プログラムは一度に作りません

最初から最後まで一気に書く人はほとんどいません。たいていはこう作ります。

  1. 何を作るかを言葉で書いてみる。
  2. それを小さな部品に分ける。
  3. いちばん簡単な部品から作って、すぐに実行してみる。
  4. うまくいったら、次の部品をつなげる。

部品ごとに実行すれば、エラーが出ても今直した数行だけを見ればいいので、見つけやすくなります。この章の例も、段階ごとに実行ボタンを押しながらついてきてください。


1. 成績表を作る

作るもの: 生徒たちの点数を見て、それぞれの評価とクラスの平均、1位を教えてくれるプログラムです。

部品に分ける

  • 点数を入れておく → 辞書(7章)
  • 点数で評価を決める → 条件文(5章)+ 関数(9章)
  • 生徒ごとに出力する → 繰り返し文(8章)
  • 平均と1位を求める → 繰り返しながら合計といちばん大きい値を覚えておく

ステップ1: 評価の関数

いちばん小さな部品から作ります。点数を受け取って、評価の文字を返す関数です。作ったら、いくつかの点数で試してみましょう。

〈評価〉を作ろう(『点数』):
    もし(『点数』が90以上だ)なら:
        「A」を返そう
    もしくは(『点数』が80以上だ)なら:
        「B」を返そう
    もしくは(『点数』が70以上だ)なら:
        「C」を返そう
    「D」を返そう

(〈評価〉(95))を出力しよう
(〈評価〉(80))を出力しよう
(〈評価〉(42))を出力しよう

A、B、Dが出れば成功です。境目にある値(80のように、ちょうど基準の点数)を必ず入れてみてください。間違いがいちばん隠れやすい所です。

最後の「D」を返そうの前にそれ以外なら:がなくても大丈夫です。前で返そうに出会うとその場で関数が終わるので、ここまで来たということは70点未満ということです。

ステップ2: 生徒ごとに出力する

今度は点数を辞書に入れて、生徒ごとに繰り返しながらステップ1の関数を使います。

〈評価〉を作ろう(『点数』):
    もし(『点数』が90以上だ)なら:
        「A」を返そう
    もしくは(『点数』が80以上だ)なら:
        「B」を返そう
    もしくは(『点数』が70以上だ)なら:
        「C」を返そう
    「D」を返そう

『成績』を{「あおい」: 92, 「そら」: 78, 「はな」: 85, 「りく」: 64}にしよう

『成績』の『名前』ごとに繰り返そう:
    『点数』を『成績』の『名前』にしよう
    枠「{『名前』}: {『点数』}点 ({〈評価〉(『点数』)})」を出力しよう

ステップ3: 平均と1位

繰り返しながら、2つのことを覚えておきます。

  • 『合計』: 点数をどんどん足していきます。回り終えたら人数で割れば平均です。
  • 『最高点』と『一位』: 今まで見た点数より大きければ入れ替えておきます。
〈評価〉を作ろう(『点数』):
    もし(『点数』が90以上だ)なら:
        「A」を返そう
    もしくは(『点数』が80以上だ)なら:
        「B」を返そう
    もしくは(『点数』が70以上だ)なら:
        「C」を返そう
    「D」を返そう

『成績』を{「あおい」: 92, 「そら」: 78, 「はな」: 85, 「りく」: 64}にしよう

『合計』を0にしよう
『人数』を0にしよう
『最高点』を0にしよう
『一位』を「」にしよう

「===== 成績表 =====」を出力しよう
『成績』の『名前』ごとに繰り返そう:
    『点数』を『成績』の『名前』にしよう
    枠「{『名前』}: {『点数』}点 ({〈評価〉(『点数』)})」を出力しよう

    『合計』に『点数』を足そう
    『人数』に1を足そう
    もし(『点数』が『最高点』より大きい)なら:
        『最高点』を『点数』にしよう
        『一位』を『名前』にしよう

「==================」を出力しよう
枠「クラスの平均: {『合計』 / 『人数』}点」を出力しよう
枠「1位: {『一位』} ({『最高点』}点)」を出力しよう

『人数』を別に数えるのは、辞書には『長さ』がないからです(7章)。

もっとやってみる: 生徒をもう1人入れてみてください。コードを1つも直さなくても、成績表が自動で長くなります。これは、繰り返し文と関数に分けて作ったおかげです。


2. 数当てゲーム

作るもの: コンピューターが1から100までの数を1つ決めると、ユーザーが当たるまで予想します。外れるたびに「もっと大きいです」/「もっと小さいです」と教え、当たったら何回で当てたかを教えます。

部品に分ける

  • 答えを決める → 【乱数】の〈整数〉(11章)
  • 予想を受け取る → 入力してもらおう(2章)
  • 比べて教える → 条件文
  • 当たるまで続ける → 間繰り返そう(8章)
  • 回数を数える → 繰り返すたびに1を足す

ステップ1: 入力なしでルールから

入力を受け取ると、実行するたびに自分で打たなければならないので、試すのが面倒です。そこで答えを固定して、予想もリストにあらかじめ書いておき、ルールから確かめます。

『答え』を42にしよう
『予想たち』を【50, 25, 37, 43, 40, 42】にしよう
『回数』を0にしよう

『予想たち』の『予想』ごとに繰り返そう:
    『回数』に1を足そう
    もし(『予想』が『答え』より小さい)なら:
        枠「{『予想』}: もっと大きいです!」を出力しよう
    もしくは(『予想』が『答え』より大きい)なら:
        枠「{『予想』}: もっと小さいです!」を出力しよう
    それ以外なら:
        枠「{『予想』}: 正解!{『回数』}回で当てました。」を出力しよう
        繰り返しを終わろう

『予想たち』の数字を変えながら、「もっと大きいです」と「もっと小さいです」が正しく出るか確かめてみてください。ルールが合っていれば、あとは本当の入力に変えるだけです。

ステップ2: 本当のゲーム

変わった所は3つです。

  • 答えを〈整数〉(1, 100)で選びます。
  • リストの代わりに間繰り返そうで、当たるまで回ります。『当たった』が偽の間、続けます。
  • 予想を【数字】で入力してもらおうで受け取ります。
【乱数】から〈整数〉を持ってこよう

『答え』を〈整数〉(1, 100)にしよう
『回数』を0にしよう
『当たった』を偽にしよう

「1から100までの数を1つ決めました。当ててみてください!」を出力しよう

(『当たった』が偽と同じだ)間繰り返そう:
    「予想: 」を続けて出力しよう
    『予想』を【数字】で入力してもらおう
    『回数』に1を足そう

    もし(『予想』が『答え』より小さい)なら:
        「もっと大きいです!」を出力しよう
    もしくは(『予想』が『答え』より大きい)なら:
        「もっと小さいです!」を出力しよう
    それ以外なら:
        枠「正解!{『回数』}回で当てました。」を出力しよう
        『当たった』を真にしよう

実行ボタンを押すと、結果の欄に入力欄ができます。半分ずつに分けながら(50 → 25か75 → …)予想すれば、7回以内に必ず当てられます。

ステップ3: 丈夫にする

今は、数字の代わりに文字を入れるとプログラムがエラーで止まります。10章の安全網で囲めば、もう一度尋ねられます。1から100の外の数もはじいてみましょう。

【乱数】から〈整数〉を持ってこよう

『答え』を〈整数〉(1, 100)にしよう
『回数』を0にしよう
『当たった』を偽にしよう

「1から100までの数を1つ決めました。当ててみてください!」を出力しよう

(『当たった』が偽と同じだ)間繰り返そう:
    「予想: 」を続けて出力しよう
    『予想』を0にしよう
    とりあえずやってみよう:
        『予想』を【数字】で入力してもらおう
    発生したら:
        「数字で入力してください。」を出力しよう

    もし(『予想』が1より小さい)または(『予想』が100より大きい)なら:
        「1から100までの数だけです。」を出力しよう
    それ以外なら:
        『回数』に1を足そう
        もし(『予想』が『答え』より小さい)なら:
            「もっと大きいです!」を出力しよう
        もしくは(『予想』が『答え』より大きい)なら:
            「もっと小さいです!」を出力しよう
        それ以外なら:
            枠「正解!{『回数』}回で当てました。」を出力しよう
            『当たった』を真にしよう

『予想』を安全網の前で先に0にしておいたことに注目してください。文字を入れて入力に失敗すると、『予想』は0のまま残るので、「1から100までの数だけです。」へ進みます。発生したら:のまとまりの中で初めて作った名札は、そのまとまりが終わると消えてしまうので、外で使う名札は外で先に作っておくのが安全です。間違った入力は『回数』に数えません。


3. やることリスト

作るもの: やることを追加して、終わったことに印を付けて、リストを見せるプログラムです。

部品に分ける

  • やること1つ = 「内容」と「終わったかどうか」を一緒に入れた辞書
  • やること全体 = その辞書を入れたリスト
  • 追加する/終わらせる/見せる = それぞれ関数1つずつ

ステップ1: データの形を決める

やること1つは、こんな形です。

『やること』を{「内容」: 「買い物」, 「完了」: 偽}にしよう
(『やること』の「内容」)を出力しよう
(『やること』の「完了」)を出力しよう

こんな辞書をリストにいくつも入れれば、やることリストになります。何をどんな形で入れるかを先に決めておくと、残りのコードが楽になります。

ステップ2: 3つの関数

『リスト』を【】にしよう

〈追加する〉を作ろう(『内容』):
    『リスト』に{「内容」: 『内容』, 「完了」: 偽}を追加しよう
    枠「追加しました: {『内容』}」を出力しよう

〈終わらせる〉を作ろう(『番号』):
    もし(『番号』が1より小さい)または(『番号』が『リスト』の『長さ』より大きい)なら:
        枠「{『番号』}番のやることはありません。」を出力しよう
        返そう
    『やること』を『リスト』の『番号』番目にしよう
    『やること』の「完了」を真にしよう
    枠「終わりました: {『やること』の「内容」}」を出力しよう

〈見せる〉を作ろう():
    もし(『リスト』の『長さ』が0と同じだ)なら:
        「やることはありません。」を出力しよう
        返そう
    『番号』を1にしよう
    『リスト』の『やること』ごとに繰り返そう:
        『印』を「[ ]」にしよう
        もし(『やること』の「完了」)なら:
            『印』を「[v]」にしよう
        枠「{『番号』}. {『印』} {『やること』の「内容」}」を出力しよう
        『番号』に1を足そう

〈見せる〉()を実行しよう
〈追加する〉(「買い物」)を実行しよう
〈追加する〉(「宿題」)を実行しよう
〈追加する〉(「部屋の掃除」)を実行しよう
〈終わらせる〉(2)を実行しよう
〈終わらせる〉(9)を実行しよう
〈見せる〉()を実行しよう

注目してほしい所:

  • 関数の中で、外の『リスト』を読んだり変えたりできます(9章)。
  • 『やること』を『リスト』の『番号』番目にしてから『やること』の「完了」を変えると、リストの中のその辞書も変わります。 辞書はコピーされず、同じものを一緒に指しているからです(7章)。
  • 返そうだけを書くと、何も返さずにその場で関数を終えます。間違った番号のときに、それ以上進まないように使いました。

ステップ3: 命令で動かす

今度は、ユーザーが追加 牛乳を買う、完了 1、見る、終わりのような命令を入力するようにします。命令の文字を〈分割〉(「 」)で分けると、最初の単語が命令です(4章)。関数はステップ2と同じです。

『リスト』を【】にしよう

〈追加する〉を作ろう(『内容』):
    『リスト』に{「内容」: 『内容』, 「完了」: 偽}を追加しよう
    枠「追加しました: {『内容』}」を出力しよう

〈終わらせる〉を作ろう(『番号』):
    もし(『番号』が1より小さい)または(『番号』が『リスト』の『長さ』より大きい)なら:
        枠「{『番号』}番のやることはありません。」を出力しよう
        返そう
    『やること』を『リスト』の『番号』番目にしよう
    『やること』の「完了」を真にしよう
    枠「終わりました: {『やること』の「内容」}」を出力しよう

〈見せる〉を作ろう():
    もし(『リスト』の『長さ』が0と同じだ)なら:
        「やることはありません。」を出力しよう
        返そう
    『番号』を1にしよう
    『リスト』の『やること』ごとに繰り返そう:
        『印』を「[ ]」にしよう
        もし(『やること』の「完了」)なら:
            『印』を「[v]」にしよう
        枠「{『番号』}. {『印』} {『やること』の「内容」}」を出力しよう
        『番号』に1を足そう

「命令: 追加 (内容) / 完了 (番号) / 見る / 終わり」を出力しよう
『続ける』を真にしよう

(『続ける』が真と同じだ)間繰り返そう:
    「> 」を続けて出力しよう
    『入力』を入力してもらおう
    『単語たち』を『入力』の〈分割〉(「 」)にしよう
    『命令』を『単語たち』の1番目にしよう
    『残り』を『入力』の〈切り取り〉(『命令』の『長さ』 + 2, 『入力』の『長さ』)にしよう

    もし(『命令』が「追加」と同じだ)なら:
        〈追加する〉(『残り』)を実行しよう
    もしくは(『命令』が「完了」と同じだ)なら:
        とりあえずやってみよう:
            〈終わらせる〉(〈数字に〉(『残り』))を実行しよう
        発生したら:
            「番号は数字で書いてください。」を出力しよう
    もしくは(『命令』が「見る」と同じだ)なら:
        〈見せる〉()を実行しよう
    もしくは(『命令』が「終わり」と同じだ)なら:
        「さようなら!」を出力しよう
        『続ける』を偽にしよう
    それ以外なら:
        「知らない命令です。」を出力しよう

『残り』は、命令の後ろの文字すべてです。追加 牛乳を買うなら、「追加」(2文字)の次のスペース1つを飛ばして3文字目から最後まで、つまり牛乳を買うになります。〈分割〉で分けた単語をもう一度つなげなくていいので便利です。


行き詰まったときに試す方法

  • 途中の値を出力する: おかしいと思う名札を、その場で出力しようで表示してみてください。思っていた値と違う所が、問題の始まった所です。
  • もっと小さくする: コードの一部を消したり(参考)でふさいだりして(行の前に(参考)を付けると、その行は実行されません)、問題が残るいちばん小さな形を探します。
  • 入力を固定する: 数当てのステップ1のように、入力の代わりに決まった値で試せば、同じ状況を何度でも見直せます。
  • エラーメッセージを読む: 何行目か、どんな種類かを教えてくれます。種類ごとの意味は付録. よく出会うエラーにあります。

まとめ

段階 すること
言葉で書く 何を作るかを1、2文で
部品に分ける データを何に入れるか、どんな関数が必要か
小さく始める いちばん簡単な部品から、作るたびに実行
入力はあとで 決まった値でルールを確かめてから、入力に変える
丈夫にする 間違った入力を安全網ともしではじく

練習問題

1. 成績表に最下位(いちばん低い点数)も出力してみましょう。最初の値を何にすればいいか考えてみてください。

答えの例

最低点の最初の値は、どの点数よりも大きくなければなりません。点数は100点までなので、101から始めればいいんです。

『成績』を{「あおい」: 92, 「そら」: 78, 「はな」: 85, 「りく」: 64}にしよう

『最低点』を101にしよう
『最下位』を「」にしよう

『成績』の『名前』ごとに繰り返そう:
    もし(『成績』の『名前』が『最低点』より小さい)なら:
        『最低点』を『成績』の『名前』にしよう
        『最下位』を『名前』にしよう

枠「いちばん低い点数: {『最下位』} ({『最低点』}点)」を出力しよう

2. 数当てのステップ1のコードに、「10回で当てられなければ終わり」というルールを足してみましょう。予想のリストを【1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 42】にして、10回目で失敗!答えは42です。が出ればOKです。

答えの例
『答え』を42にしよう
『予想たち』を【1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 42】にしよう
『回数』を0にしよう

『予想たち』の『予想』ごとに繰り返そう:
    『回数』に1を足そう
    もし(『予想』が『答え』と同じだ)なら:
        枠「正解!{『回数』}回で当てました。」を出力しよう
        繰り返しを終わろう
    もし(『回数』が10と同じだ)なら:
        枠「失敗!答えは{『答え』}です。」を出力しよう
        繰り返しを終わろう
    もし(『予想』が『答え』より小さい)なら:
        枠「{『予想』}: もっと大きいです!」を出力しよう
    それ以外なら:
        枠「{『予想』}: もっと小さいです!」を出力しよう

正解の確認を先にしないと、10回目に当てた場合も「正解!」になりません。

3. やることリストに、残りのやることの数を数える〈残りの数〉関数を作ってみましょう。ステップ2の例の最後で呼ぶと2が出るはずです。

答えの例
『リスト』を【{「内容」: 「買い物」, 「完了」: 偽}, {「内容」: 「宿題」, 「完了」: 真}, {「内容」: 「部屋の掃除」, 「完了」: 偽}】にしよう

〈残りの数〉を作ろう():
    『数』を0にしよう
    『リスト』の『やること』ごとに繰り返そう:
        もし(『やること』の「完了」が偽と同じだ)なら:
            『数』に1を足そう
    『数』を返そう

(〈残りの数〉())を出力しよう

ここまで来たら、カナデでかなり多くのものが作れます。似たものをいくつも扱うプログラムが大きくなってきたら、オブジェクト指向がコードの整理に役立ちます。ファイルを読み書きしたり、実行ファイルにまとめたりしたいなら、Hanaランタイムを見てください。

プレイグラウンド
結果
コードを書いて「実行」ボタンを押してください。