こんにちは。50代プロ研の Ted です。
新入生の皆さんは、明日からいよいよ授業開始ということで期待に心がぴょんぴょんしていることと思います。当サークルは明日から4月末までの毎週水曜日と金曜日の 18:30 から西早稲田キャンパスの 52号館にて説明会を開催します。新歓専用ページはこちら。
さて、今回の投稿のタイトルの紅茶を淹れてみようということで、紅茶のレシピでも紹介しようかと思います。また、そのレシピを擬似コードで書いてみることもしてみます。「なんでわざわざ紅茶のレシピ?」って思われるかもしれません。紅茶は私の趣味のだからなのですが、実は料理のレシピは普段の生活の中にあるアルゴリズムの代表例のひとつなので、プログラミングを全くやったことない人にとっては理解しやすい導入になるからです。
アルゴリズムはあることを実現するためには何をどう処理すればいいかを記述したものです。料理のレシピには必ず、ある料理を作るには「どんな食材をどのように調理すればよいのか。」が書かれていますよね。これはまさにアルゴリズム一種と言えます。コンピューターに読ませるプログラムのコードはアルゴリズムによって構成されていることもあって、料理のレシピを考える際の思考とプログラミングをする際の思考は似通っています。料理のレシピは身近に存在するもので、親しみやすい、そして想像しやすいので、導入に比較的適していると言えるんですね。この投稿では、書いてある内容をわかりやすくしたいことと、これから簡潔でバグの少ないプログラムを書くために必要な知識の紹介も兼ねて擬似コードを用いて料理のレシピを書いていくことにします。
ちなみに、紅茶を淹れるという行為はそう簡単な作業ではありません。なにせ適切な調理器具を適切なタイミングで扱い紅茶の葉をティーポットの中で踊らせなければいけません。それに加えて、個人的にはどうでもいいのですが、人々はミルクティーを作る際にティーカップにはミルクが先かお茶が先かでよく揉めます。これもまたこの投稿で触れなければならない内容でしょう。では、始めていきます。
レシピ
参考にしたのは、2003年に英国王立化学会(The Royal Society of Chemistry)が発表した "How to make a Perfect Cup of Tea"と国際標準化機構が定めた ISO 3103 の2つの文献です。
- 新鮮な軟水を適量やかん、もしくは電気ケトル(以下、ケトル)にいれて、沸騰させる。厳密には沸騰する直前、液体中の溶存酸素量が少なくなっていない状態が望ましい。熱湯の小さかった泡が大きくなり始め水面を揺らし始めたくらいがちょうどいい。温度は95度くらいです。
- セラミックのティーポットに約コップ1/4(50ml)の水をいれ、電子レンジでそれを最大出力で1分間。
- ティーポットから2.で温度の上がった水を捨てる。
- 熱湯100mlあたり、約2.5g の茶葉をティーポットにいれる。このときちょうどケトルの熱湯の準備が完了しているのが望ましい。
- ティーポットにケトルのお湯をいれる。
- ティーポットにポットカバーを被せて3分待つ。
- ティーカップ、もしくはマグ。どちらもセラミックのが望ましい、なければ自分好みのもので。
- ティーカップにお茶を淹れます。ミルクティーを作りたいのなら、カップには先にミルクをいれる。後からお茶。
- 砂糖を適量。お好みで。
- 熱くてお茶をすすっちゃうリスクを避けるため、お茶が60-65度のときに飲みましょう。
上記のレシピで"適量"等の曖昧な単語を使いましたが、このような表現はコンピューターを用いるプログラミングの現場では避けなければなりません。私たち人間は経験や知識から思考し"適量"のその量を導き出すことができます。一方、コンピューターはたとえデータベースで過去の事象を記録し参照することができるとしても、人間のように"思考"をすることはできません。コンピューターは予め書かれたコードに則ってデータを処理しているにすぎません。よって、コンピューターに指示する際にはできるだけ明確にしなければならないのです。それを踏まえて、この紅茶のレシピを擬似コードで書いてみることにします。
擬似コード
そもそもこれってなにって話ですね。擬似コードはアルゴリズムを自然言語に近い形で、基本的なプログラミングの構文を知ってさえいれば読めるように書かれたものです。特定の言語に依存せず、特に文法 など、書き方の正式なルールがありません。ようは読みやすいプログラミングのコードもどきってことです。書きやすいので、実践において複雑なプログラムを作らなければならないときは一度擬似コードで何回か書いたりして該当するデータの適切な処理の仕方を明確にすると、すっきりしたバグの少ないコードが書けます。
プログラミングの構文を知らないと、よほど肌の合う人にしか書いてあることが理解しにくいですが、こんなもんかとなんとなく見てもらえば結構です。この投稿のメインは紅茶です。レシピの順番毎にひとつひとつコードにしていきましょう。
- ただ「水」を沸騰させるだけじゃダメですね。新鮮な軟水を95度まで熱する作業であります。工程 4. のために、何ml なのかも知る必要があります。ここでは、「水」っていうのは、新鮮さ、硬さ、温度、量の4つの情報が必要なわけです。本来こういった場合は、クラスを使ってまとめて条件にあったオブジェクトの水を記述するのが適切だと思われますが、ここでは簡略化のためその都度必要な情報は
Input
するものとしましょう。
INPUT 200ml_fresh_soft_water
boiling_water = Kettle(200ml_fresh_soft_water)
Kettle(water)
water を95度にします
RETURN 95度になったwater
以上が 1. の工程です。まず、1行目で新鮮な軟水を登場させ、2行目でそれをケトルに入れ熱湯にしました。今回のケトルは特別仕様でして95度の熱湯を作り出します。Kettle(water)
の形は関数と呼ばれていて、数学で使ってたやつと同じようなもんです。英語で関数は function と言いますが、f(x) の f は名前で x は変数。この変数をプログラミングの世界では引数なんて呼びます。これが Kettle の関数の場合は water となっているわけですね。それで、数学では y=f(x) なんて書きましたが、どんな値を y 、上記のコードでは boiling_water
に割り当てるかは、Return
で指定します。
2. 50ml の水を電子レンジでばーって1分やります。
INPUT 50ml_water, teapot
teapot = Microwave(Place(teapot, 50ml_water), 60, 1000)
Place(A, B)
A の中にB を入れて、ひとつのものとする
RETURN "ひとつになったもの"
Microwave(もの、時間、ワット数)
ものを時間の間ワット数で温める。
RETURN 温かい
電子レンジの最高出力は1000w としました。時間の単位は秒です。これでいま teapot は温かいものとなりました。
3. ティーポットからお湯を捨てる。
teapot = remove(teapot, 50ml_water)
remove(C, D)
C から D を除く
RETURN 除かれた後残ったもの
これは先ほど Place()
で teapot
に入った 50ml の水を remove()
という関数で取り除いただけです。
4. 熱湯 100ml あたり、2.5g の茶葉を水のなくなったティーポットにいれる。ケトルの準備とティーポットの準備の両方ともできているかの確認は次の工程で書くことにします。
INPUT 200
v = 200
Mass_of _looseleaf_tea = (v/100)*2.5
looseleaf_tea = Bag_of_looseleaf_tea(Mass_of_looseleaf_tea)
teapot = Place(teapot, looseleaf_tea)
Bag_of_looseleaf_tea(mass)
RETURN mass の重さだけの茶葉
ここでは、新鮮な軟水が200mlなので、それに基づき茶葉がどのくらいの重量にならなければならないのかを計算し、Bag_of_looseleaf_tea(mass)
関数で茶葉を取り出しています。その後、teapot
に茶葉を入れた状態にしています。
5. ティーポットにケトルのお湯をいれます。この時に、きちんとケトルとティーポットは共に熱い状態でなければなりません。どちらかが熱くない場合また温めなければならないので。ここで使われている、NOT()
というのは否定なので、温かくないときという意味になります。
IF ケトルが温かい AND ティーポットが温かい THEN
Place(teapot, boiling_water)
ELSE IF NOT(ケトルが温かい) AND ティーポットが温かい Then
工程 1. のみをやり直し
ELSE IF ケトルが温かい AND NOT(ティーポットが温かい) Then
茶葉を remove() して、工程 2. 3. 4. をやり直し
ELSE
工程 1. から全てやり直し
END IF
6. ポットカバーをティーポットに被せます。広義には中にいれるとも言えますね。これで3分待てば、boiling_water
は紅茶になりますので、それも記述します。
INPUT tea_cosy, Time
teapot = Place(tea_cosy, teapot)
teapot = teaTimer(teapot, 180)
teaTimer(ティーポット, 時間)
IF 時間 <= 0 Then
RETURN 中身が tea になったティーポット
ELSE
RETURN teaTimer(ティーポット, 時間 - 1)
END IF
このteaTimer()
という関数は再帰呼び出しをする関数で、自分自身を条件によってはまた呼び出しています。ここでは、毎回再帰するたびに時間が 1 減っていき、1以下のときにティーポットの中身は美味しい紅茶になったよということで、再帰をやめています。まさにタイマーです。
7. ティーカップ、もしくはマグ。ここでは、ティーカップを使いましょう。特に理由はありません。
INPUT tea_cup
8. お茶を淹れます。ミルクティーを作りたいなら、ミルクをとってきて先にティーカップにいれなければいけません。この確認もしましょう。
IF ミルクティーが飲みたい Then
INPUT milk_container
tea_cup = Pour(tea_cup, milk, milk_container)
tea_cup = Pour(tea_cup, tea, teapot)
ELSE
tea_cup = Pour(tea_cup, tea, teapot)
END IF
Pour(Receiver, Content, Container)
Return Receiver に Content を Container からいれる。
コードは原則上から下へ読まれるのでこのように書けば先にミルクをいれることが実現できます。
9. 砂糖をまた入れたければいれるということなのでそれを実装します。なんとなくまた if
を使うのもつまらないので、case
もここで使ってみます。case
はひとつの変数で様々な条件分岐が可能なときに使うのが適切です。
INPUT sugar_preference, sugar
sugar_preference = お茶を飲む人に聞いてみる("砂糖をいれますか。yes/no で答えてください。")
SELECT CASE of sugar_preference
CASE y, yes
Pour(tea_cup, sugar, sugar_box)
others
EXIT
END SELECT
ここでは、一度 sugar_preference
で砂糖が欲しいかどうかを聞いて、砂糖が欲しいと答えた場合に砂糖をティーカップにいれています。他の場合は EXIT
を使用し、case
文を即終了させています。
まだバラバラのモジュールをまとめてひとつにしたりと作業はできますが、とりあえずこの辺で擬似コードがどんなものなのか、コードを書く流れはどんな感じなのかがわかったと思うので、以上にしたいと思います。
このレシピを参考にしてぜひ紅茶淹れてみてください。きっと美味しいです。ちなみに、私が好きなお茶は Earl Grey と English Rose ってやつです。English Rose にはイギリス版の大和撫子みたいな意味もあるんですよ。私は単純にこのお茶の味が好きなだけですけどね。では、長くなりましたが読んでいただきありがとうございました。