前回は、関数という物を作ってそして使う方法を見てきました。

第八回では、この関数から結果をもらう事について説明していきます。 JavaScriptの用語ではreturnの説明となります。

これまで(実は)出てきていた関数たち

突然ですが、実はこれまで、既に幾つかの関数が出てきていました。具体的には、

  1. MessageBox.show()
  2. MessageBox.yesNo()
  3. Math.randomInt()

の3つは関数です。 なんと、既に関数は使っていたのですね。

そしてこれらは実は、文字や数字を渡したり、結果をもらったりしてました。 第八回や第九回のテーマは、実は既にやっていた事なのです。

これまでぼやかして使っていたこれらの事のうち、第八回に関わる事を真面目に解説しなおしてみます。

MessageBoxやMathは、実は辞書だった!

さらに突然ですが、MessageBoxMathは、実は辞書です。MessageBoxという辞書に、showとかyesNoをキーとして関数が入っています。

百本ノックでやったテーブルで書くとこんな感じです。

MessageBox

キー 要素
show 何かの関数1
yesNo 何かの関数2

なんとなく第六回でやった辞書に見えてきませんか?見えてきません?そうですか(´・ω・`)

とにかく、MessageBoxは辞書なのです。 で、showとかyesNoはキーなのです。

辞書なので、MessageBox["show"]とやると中身が取り出せるのですが、 キーがローマ字の時はMessageBox.showと取り出す事も出来る、 なんていうヘンテコな機能がある事をこそっと第6回でやっています。

当時はなんだか分からなかったと思いますが、実はこのための布石だったのです(という事で6章の時点では意味が分からなかったかも。暇なら読み直してみてね!)。

つまり、以下の2つは同じものです。

  • MessageBox.show
  • MessageBox["show"]

だから、以下のコード

MessageBox.show("むぇーー");

は、実はこうも書けます。

MessageBox["show"]("むぇーー");

一応やってみましょう。

結果:

 
実行すると、MessageBox.show("むぇーー");と書くのと同じ結果になったと思います。

最近のJavaScriptでは特に、環境は関連する関数をグループに分けて、それぞれ辞書に入れて提供してくるのが一般的です。 例えばMessageBoxにはユーザーに何かを見せたり質問したりする関数が入っている、とか、 Mathには乱数とか計算にまつわる関数が入っている、とかそういう事ですね。

このシリーズでもその傾向に合わせて、関数は辞書に入れて提供しています。

なんで.でも要素が取り出せるのか?の勝手な予想
JavaScriptの辞書は、キーがローマ字っぽい時だけは.でも取り出せる、という機能があります。 これは無くても同じ事が["show"]とかで出来るので、不要な感じがしますよね。
なんでこんな中途半端な機能があるのか?
 
これは私の勝手な予想ですが、たぶん見た目をJavaというプログラミング言語に似せる為だと思います。 Javaは辞書とは全く別の仕組みで、MessageBox.show("むぇーー");というような書き方でメッセージを表示する言語です。
これと見た目の上では似た感じにする為、辞書から要素を取り出すのに、ローマ字っぽいキーの時は.でも取り出せるようにしよう、というヘンテコな機能がついたのだと思います。
 
勉強する側としてはあまり深く考えず、なんか大人の事情で変な機能になってしまったんだな、くらいに思っておけばいいと思います。
私も「当時のNetscape社の頭の硬い上司を説得する為に、 見た目はJava言語っぽいですよ〜と嘘をつかなきゃいけなかったので、この.でも取り出せる、とか良く分からない事があるんだなぁ」くらいに思ってますので。
実際の所は本当かどうかは知りませんけどね。

結果をもらう

Math.randomInt(5)や、MessageBox.yesNoなどは、結果を変数に受け取る事が出来ました。 例えば以下みたいなコードが第五回ではありました。

結果:

 
このコードで、0から4までのどれかの数字がdorekaに入ります。

そのうち、乱数を作って変数に入れる所、つまり以下のコード

var doreka = Math.randomInt(5);

は、実は関数から結果をもらうコードとなっています。 Math.randomIntの結果は、こうやって=の右に書く事でもらう事が出来るのです。

これが第八回のテーマ、結果をもらうです。

MessageBox.yesNoも同様です。

結果:

 
この例では、tumetaiという変数に結果を入れています。 MessageBox.yesNoからもらった結果です。

var tumetai = MessageBox.yesNo("こちんこちん?", "はい", "いいえ");

このように、関数を使うコードを=の右側に書く事で、結果をもらう事が出来ます。

関数を使う側と作る側の対応関係

これまでやってきたコードを元に、今回扱う内容である、結果をもらう方法を見てきました。
これらは関数を使う側の話です。

一方で、何かをもらう為には、くれる人が必要です。 Amazonで欲しい物リストを晒しても、くれる人が居ないともらえないですよね?

関数でも同様に、使う側がもらう為には、作る側が返す必要があります。 表にすると以下のようになります。

使う側 作る側
結果をもらう 結果を返す

つまり関数を作る側では、結果を返す必要があります。

この結果をもらう - 結果を返すという組みについて以下では解説していきますが、いつもそれが「使う側」の話か「作る側」の話か、注意して読んでいってください。

以下では改めて、最初から結果をもらうという事はどういう事かという話と、 それに対応する結果を返す方法を見ていきます。

結果を返し、返ってきた結果をもらう

関数は中身を実行したあと、結果を返す事が出来ます。 使う側は、返ってきた結果をもらって、その結果に応じて処理が行なえます。言葉にするとややこしいですが、コードはそんな難しくも無い。

もらう側はこれまで見てきた所ですが、ここで改めてちゃんと説明します。

結果を返すのは今回新しい所ですね。 関数から結果を返す方法もここで見ていきます。

結果をもらう

関数は、lucy();とか、naku();などという風にすると使う事が出来る、 という話を前回しました。

結果を受け取るには、この

lucy();

というコードを、以下のように変更します。

var kekka = lucy();

このように、関数を使うこれまでのコードの左に、var kekka = という風に書くと、 lucy()の結果をもらう事が出来ます。(なお、プログラム用語では受け取るといいます。ただ今回はちょっとした事情によりもらうで統一します)

このように関数を使う時に、必要ならその結果をもらう事が出来るのです。

課題:6が多めに出るイカサマサイコロを振って、結果をもらえ

こちらが、6の目が多めに出るikasama_saikoroという関数を用意しました。 この関数を使って、結果をもらってください。

ヒント: 関数を使うのは、ikasama_saikoro();という風にするのでした。

結果:

答え:
var kekka = ikasama_saikoro();

 
結果を受け取るコード自体はそれほど難しい事も無いんじゃないでしょうか。

なお、ikasama_saikoroのコードが何をやっているか、想像つきますか? returnはあとでやりますが、結果を返すという命令です。そしてif(num < 5)は「numが5より小さかったら」という意味になります。

さて、全部合わせるとどういう意味になると思いますか?(あとで簡単に解説してます)

関数から結果を返す

さて、関数から結果をもらう為には、関数を作る時に結果を返す必要があります。

結果を返すには、returnという物を使います。

関数の中で、例えば以下のように、

return 3;

とすると3を返し、また、以下のようにすると、

return "むぇーー";

"むぇーー"という文字を返します

つまり、awaという関数の中でreturnするとすると、以下のようなコードになります。

var awa = function() {
   return "むぇーー";
};

実際に実行してみましょう。

結果:

 
こうして、結果を返す関数を、returnを使って作る事が出来ます。

課題:”蕎麦充した”と返せ

ただ決まった文字を返すだけの関数を作ってみましょう。 返す文字は"蕎麦充した"にします。

"蕎麦充した"返すだけの関数を作って下さい。

結果:

答え:
var lucy = function() {
    return "蕎麦充した";
}

 
もう一つ同じような問題をやってみましょう。

課題:いつも6を返すサイコロを作れ

前問で、ただ決まった文字を返す関数を作りました。 ただ数字を返す関数も似たような物です。

いつも6を返す、イカサマサイコロを作ってみましょう。

結果:

答え:
var ikasama_saikoro = function() {
    return 6;
}

 
これでは決まった値を返すだけなのでありがたみが無いですね。ただ最初はそんなもんです。

returnすると、そこから先は実行されない

さて、ここまでreturnの説明をしてきましたが、もう一つ説明してない事があります。 それは、returnは結果を返すだけじゃなくて、そこで関数の実行が終わる、という事です。

例えば、以下のコードを実行しても、"むぇーー"とは表示されません。

結果:

 
関数awaの中で、MessageBox.show()の前にreturnしてしまっているので、関数awaのそこから先は実行されないのです。 ただ関数の実行が終わるだけで、"コケー"の部分は実行されます。

先程の課題で、6が多めに出るサイコロ、というのを私が作ってきました。こんなコードになっていました。

var ikasama_saikoro = function() {
    var num = Math.randomInt(12);
    if(num < 5) {
        return num+1;
    }
    return 6;
};

この時、numが0から4までだとifの中のreturn num+1;が実行されて、そこでこの関数が終わります。 numが5より大きい(5から11までのどれか)だと、このif文には入らずその下のreturn 6;が実行されます。

この手の話は、言葉にするとごちゃごちゃしますね。でもプログラムを理解するのはそんな難しくないと思います。 「こいつの日本語わけ分かんねーなぁ」と思っても、プログラムが分かれば先に進んでOKです。
日本語が不自由な可哀想な奴…とでも思っておいてください。ってほっといてください。私プログラマなんで別にいいんです。

このように、if文の途中で実行を打ち切りたい時などもreturnを使う事が出来ます。

また、returnは何も値を指定しない、ということも出来ます。 例えばreturn ;みたいな書き方です。 これはそこで関数を終わりにしたい、という時にやりますが、ひねくれたいい方をすれば「何も無いを返している」とも言えます。

この辺は実際のコードを動かしていけば分かる事なので、今説明読んで分からなくても、 あとで「ああ、この事を言いたかったのか」と分かれば良いと思います。

10本ノック

この時点では、簡単過ぎてなんでこんな事しているのか良く分からないと思います。

ただ、ここから一気に難しくなるので、その前に少し似たようなのをいくつかやって慣れておく方が良いかもしれません。 100本ノックならぬ10本ノックです。

全部同じ問題に見えるのでやる意味がわからん、という人は、10本ノック、という課題を飛ばして次の説明に進んでしまってもOKです。 ただ手の運動をして慣れておくと、このあとの解説に集中出来るかもしれません。

なお、10本無いですが人生とはそういうものです。

課題:【10本ノック】いつも3を返すサイコロを作れ

結果:

答え:
var ikasama_saikoro = function() {
    return 3;
}

課題:【10本ノック】いつも「こーしー」を返すlucy関数を作れ

結果:

答え:
var lucy = function() {
    return "こーしー";
}

この辺まで来るとやってる事は

  1. function () { で始める
  2. return でなにか返すものを返す
  3. }; で閉じる

だけなのが分かるでしょうか?もうちょっと慣れる為に続けてみます。

課題:【10本ノック】いつも「ダネー」を返すdaniki関数を作れ

結果:

答え:
var daniki = function() {
    return "ダネー";
}

課題:【10本ノック】いつも2を返すikasama_saikoro関数を作れ

結果:

答え:
var ikasama_saikoro = function() {
    return 2;
}

課題:【10本ノック】いつも「むぇ〜〜」を返すawa関数を作れ

結果:

答え:
var awa = function() {
    return "むぇ〜〜";
}

課題:【10本ノック】いつも4を返すikasama_saikoro関数を作れ

結果:

答え:
var ikasama_saikoro = function() {
    return 4;
}

関数の中を複雑にすると途端に難しく感じるようになるので、 まずは簡単な物をやってみました。 なんでこんな事をしているのかは置いといて、functionって書くのには慣れてきたでしょうか?

何故returnなんて物があるのか?

さて、ここまで返すというのはreturnで出来る、という事を見てきました。

第八回の内容は実質これだけなのですが、少しフィードバックを聞いた所、 これが何を意味しているのかというのが、ここまでの説明ではいまいち分かりにくいようです。

そこで、ここでは「なんで」returnなんて物を作ったのか、というその必要性について考えてみたいと思います。

何故関数なんて物があるのか?

そもそもにreturnの必要性は、関数で何をやりたいのか?という話になります。 何のために関数なんて物があるの?別にそんなの無しで普通にこれまで通りコード書いていけばいいじゃない!?と思っている事でしょう。

returnまで説明したので、この疑問について、それなりに考える事が出来るようになりました。

プログラムは、すぐ理解出来ないくらい複雑になる

人間の理解力には個人差があります。 結構複雑な物を考えられる人も居れば、ちょっと複雑になっちゃうだけでわからなくなっちゃう人も居ます。

ですが、どんなに理解力が凄い人でも、限界はあります。 プログラムがどんどん複雑になれば、やがて分からなくなるのです。 しかもわからなくなるくらい複雑にあるのは、結構すぐです。

これは極端な例じゃなくて、ちょっと実用的な物を作るとあっという間に複雑過ぎてわからなくなってしまう、 という事は広く知られています。 だいたいプログラムは2000行もあれば人間の限界は来ます。 一方、世の中のアプリなど、3万行〜10万行程度はそう珍しくもありません。 考えるのが得意かどうかの個人差なんてどうでもいいくらい、圧倒的に長い。

結局、個人差がどうであれ、あっという間に人類には理解出来ないくらい、プログラムは複雑になるのです。 これは初期のプログラムの中心的な問題で、結構長い事業界の人は困っていました。

そこでこの複雑になっていくプログラムを、なんとか理解出来るようにする方法は無いか?という事で考えられたのが関数という物です。

プログラムを分割して理解する

プログラムはすぐ複雑になってやべーよ、と人々が悩んでいた時に、ダイクストラさんという人が幾つかの作戦を考えつきました。

そのうちの一つが、大きなプログラムを分割して、幾つかのより小さな問題に分ける、という作戦です。 さらにそれらの問題の一つひとつをより小さな問題に分け、、、という事を繰り返して、 一個一個の問題が凄く簡単な位小さくなるまで分割して解けばいいんじゃないか、といいました。

このプログラムを分割する為の仕組みが関数です。

関数は、一つの複雑な大きな問題を、より小さな問題に分けて各個撃破する、というアイデアです。

複雑さとの戦い
プログラムがすぐ人間の限界を超えて複雑になってしまう、というのは、2005年くらいまでは良く問題になっていました。 Windows Vistaなどが全然リリースされなかったのは、この話題が表で良く話された出来事としては記憶に残っています。 もっと最近でも、みずほなどでも同じ話題は一部で話されています。こちらは日本の一部業界ローカルという感じですが。
複雑さに対する対処法もいろいろ提案されていて、関数もその一つに過ぎません。
 
ただ最近は、プログラムの複雑さの問題は、そこまで話題にはならなくなった気がします。 そこには、これ、っていう決定的な理由がある訳ではありません。 なんとなくみんな話をしなくなった。
ただ、そうはいっても皆がある程度共通に思っている、幾つかの理由はあると思います。
 
例えば、複雑な物を作れる程企業に体力が無くなった、とか、 複雑な物を作ってる間に流行りが変わってしまうくらい人々が飽きっぽくなった、とか、 そういう残念な理由は間違いなくあります。最近は新しく大きな物を作る、という事自体が随分減りました。
 
また、プログラム業界側が、複雑じゃなくやっていくのにうまくなった、という側面もあります。 業界的にはだいたいJavaのEJBあたりで複雑さのピークが来て(2003年あたり?)、 以後はもっと簡単に軽くやっていく方法は無いか?と探求していった、という部分があります。 良いスクリプト言語が豊富なライブラリとともに流行し、Map Reduceのような小さく問題を解く為の技術も生まれ、 一人一人が一度にやる事は小さくなってきています。 Unityなどもそういう物の一つと言えますね。
 
そういう訳で、複雑になりすぎて困る、という問題は、昨今ではだいぶ片付いた印象です。
ただ、それでもやっぱり関数などを使わずに書けば2000行程度で限界が来るのは昔と変わりません。 複雑さを解決する新しい方法が提案される事は随分減りましたが、これまで定番になった関数などは相変わらず重要で必須な物です。

タカビーなお嬢様とセバスチャン

関数というのは、アニメとかでたまに出てくる、金持ちでタカビーな感じのお嬢様キャラが似ています。 横にいつも執事のお爺さんがついていて、何か言いつけると「ははっ」とか言っていろいろ用意してくれる奴。

執事は何故か名前はだいたいセバスチャンですよね。 お願いマイメロディでもセバスチャンでした。お嬢様じゃなくて柊様でしたが。
きんぎょ注意報では田中山でしょうか(あれは執事じゃないか)。 以下、菅平ゆりかを念頭に話を進めます。(誰やねん)。

さて、ああいうお嬢様と執事のパターンでは、お嬢様は何か一言喋ります。
例えば

「サンドイッチ」

と言って手を出すと

「ははっ」

と言って持たせてくれる。 ある程度食べて喉が乾いたら、

「お茶」

と言って手を出すと

「ははっ」

と言ってお茶を持たせてくれる。

これは非常に関数的です。

お嬢様はタカビーなので、セバスチャンがそのサンドイッチをどこから持ってきたのか、とかはどうでもいいのです。 購買で並んで買ったりしているとかは気にしないのです。

ただ、サンドイッチは欲しい。

セバスチャンとしては、お嬢様が欲しがっている物を、ささっと差し出す訳です。 これは非常にreturn的です。

相手が欲しがっている物を予想して、相手がここに頂戴ね、と言っている場所に渡す。これがreturnです。
その為に財布の中に小銭は入っていたのか?とか、近くのコンビニはどこか? とかいろいろ考えて買いに行ったりしている訳ですが、 そこらへんのことは別にお嬢様に伝える必要は無い。

お嬢様に渡す必要があるのは何か?というとサンドイッチです。 ということで買ってくる為に必要な物は全部セバスチャンが使えば良いのですが、 サンドイッチだけは自分で食べてはいけません。 あくまで使ってる人に渡す必要があります。

さっと差し出す、これがreturnです。

この時に、お嬢様とセバスチャンを区別しないと、なんだか良くわからなくなる。 結局購買に行ってパンを買ってきて食べてる、と考えてしまうと、returnの意味が無い。

だからいつもお嬢様とセバスチャンは分けて考えないといけない。 で、お嬢様の気持ちで考える時は、セバスチャンはどうにかして必ずのぞみを叶えてくれる、 という前提で、自分のやりたいことを考える。

上のikasama_saikoroの話も一緒です。 お嬢様視点でいえば、

「イカサマサイコロ」

と言ったら、セバスチャンがどう実現するかはおいといて、サイコロの目で6が多いものが返ってくるのです。

で、セバスチャン側としては、財布の中に小銭は入ってたのか、ここから一番近いコンビニはどこか、 という事を考えたり、乱数で0から11まで作ってみて、0から4までならそれに対応したサイコロの目を返し、 それ以外なら全部6を返そう、とかをいろいろ考える訳ですが、お嬢様にそれらを教える必要は無い。

ただ結果の1とか6とかの数字だけをreturnしてやれば良い。

これがreturnです。

概念を実現する為の仕組み

関数とかreturnと、ここまで言ってる柊様とかセバスチャンは、なんか関係ないことのように感じられるかもしれません。 実際は関数は人間では無いし、関係無いじゃん、と。

でもそこら辺を真面目に考えないと、関数もそれ以前のコードもあまり区別が付きません。 例えば関数を使った以下のコード

var awa = function() {
    MessageBox.show("むぇーー");
};

awa();

と、関数を使ってない以下のコード

    MessageBox.show("むぇーー");

は何が違うのでしょうか?

関数awaの中身のMessageBox.show("むぇーー")とかは、 どちらのバージョンも全く一緒です。 だから実行されるコードだけを考えると、この2つの違いは良く分からない。

第六回までは、実行されるコードを「なんとなく」理解しておくだけでプログラムが分かるのですが、 関数だけはこのやり方が通じにくい。

関数は、概念を実現する為の仕組みなので、どう動くかだけを考えても違いが分からない。概念を頭の中で生み出してやる必要がある。 上のコードは、「awaという執事を作って、これに鳴け!と命令しているんだな」と意識的に考えてやる必要があるのです。 この仮想的な「awaという執事」という存在を、心の中で具体的に思い浮かべるのが関数のコツです。

「結局中のコードはMessageBox.show("むぇーー");じゃん」と思ってはいけません。
Citrusは本当は美少女なんだけど、陰キャ男の大学生ということにしておいてやって会話する、というようなものです。 本当は美少女じゃん、は言ってはいけない。
男の学生、そういうことにしておいてやる、これが関数を考える上での重要な所です。

そもそもに、returnなどの仕組みは、このように考えられる幻想を作りだすにはどういう機能が必要か?と考えて生まれた物です。

プログラムを「執事とそれに命令するお嬢様に分ける」という風に考えやすい仕組みを作るにはどうしたらいいか? ということを昔の人が考えた結果、

  1. 関数という物を作る
  2. 関数からは結果が一つ戻る
  3. 要望は引数で渡す

という結論になったという経緯があります。

なお3については第九回でやります。

プログラムを「お嬢様とセバスチャン」に分けて考える、という幻想が壊れないように決められたルールなので、 ちょっと最初のうちは怖いかもしれませんが、そういう風に本気で考えても大丈夫なようになっています。 空想上の概念を本当に存在しているかのように思ってプログラムを読む、これが大切です。

「俺の右手はイマジンブレーカーだから…」とか言ってはいけません。イマドキの子には通じません。

この「プログラムを執事とそれに命令するお嬢様に分ける」という前提に慣れることがreturnを理解するには大切です。

関数のいろいろ
結果は一つとか引数で渡す、がJavaScriptにおける関数の決まりですし、 これはだいたいの言語で現在そうなっていますが、ちょっとは例外もあります。
 
例えば昔は、サブルーチンという物がありました。 これは結果が無い関数のような物、と言えます。関数との間のやり取りは、returnのような仕組みを使わず、 適当に変数(グローバル変数という)でやっていました。
ただ、最近はやっぱりそういうのは幻想を崩して良く無いよね、と皆が思うようになり、サブルーチンはだいたい消えたと思います。
 
また、returnで処理が終わる、というのを嫌う人も居て、関数の出口は全て一つ(最後)という流派もあります。lisp系の言語はそうですね。
 
最近だと、関数の結果を複数返せる、というのは一般的になってきました。多値といって、 JavaScriptでも最近のバージョンではDestructuring assignmentという仕組みを用いて、似たようなことが出来ます。 ただ、これも複数の値を持った配列を返している、というような物なので、そんなにこれまでの関数と違う物という訳でもありません。
 
細かな所で多少の違いはありますが、現代では関数というのがだいたいは今回説明した物、 という結論になったとは言って良いんじゃないでしょうか。

関数と自作自演

関数は自作自演です。

まず「絵を描きました〜」と投稿します。

次にアカウントを切り替えて、「わー、素敵な絵ですね〜、凄いです~」とコメントをつけます。

こうしてちやほやされてる感じを演出するのです。 この時に、最初のアカウントからの書き込みは、ある程度裏垢からの書き込みを「想定」して、 やりやすいように書き込みします。

裏垢のコメントも、その後本垢から反応しやすい内容にしておいて、会話が自然になるようにします。

めんどくさいので同じアカウントでやろう、とかやってしまうと台無しです。 自分でやる時でも、別人のフリをするのです。

この適度に相手の事を考えて会話をしているフリをする、 でも結局やってるのはどっちも自分、これは非常に関数を使ったプログラミングっぽい。

こういう気分でコードを書く事が大切です。お嬢様の時のアカウントとセバスチャンの時のアカウントは別、 という事で、口調も片方では語尾にろっくをつけて、もう片方ではパオを付けたりします。アカウントを切り替える都度、語尾を変えるのです。

関数はコードを忘れる為にある

お嬢様とセバスチャン、と考える為には、コツのような物があります。

そのコツとは、関数を使う時には「関数の中身」を、「忘れる」事が大切なのです。 「考えない」と言ってもいいです。

お嬢様の立場の時にはセバスチャンのことは考えない。 あくまでお願いしたら物が出てくる自動販売機みたいな物と考える。 どうやってそれを実現するかは考えてはいけません。

ちょっと例を考えましょう。
もう見慣れた、こちんこちんって聞いて麦茶かこーしーか表示する、というコードです。

結果:

 
さて、これを関数にしたとします。

結果:

 
なんか複雑になった!という気もするかもしれませんが、良く見ると前回やったのと同じ内容です。

ぱっと見一つ前のコードとあんまり変わらなさそうですよね。
同じやん、というと同じなんですが、このコードを心の中で2つに分けるのです。 お嬢様の側と、セバスチャンの側です。

まずセバスチャン側は以下。

var lucy = function() {
    var tumetai = MessageBox.yesNo("こちんこちん?", "はい", "いいえ");
    if(tumetai == 1) {
       MessageBox.show("麦茶!");
    } else {
       MessageBox.show("こーしー");
    }
}

で、お嬢様側が以下。

lucy();

で、この2つのそれぞれを読む時に、心を切り替える、というのが関数の奥義です。 これが関数の難しさの、ほぼ全てです。

どう切り替えるか?というのをちょっと解説してみます。
まず作る側のコードを見て、何をやってるのか理解します。

作る時視点(セバスチャン視点)

var lucy = function() {
    var tumetai = MessageBox.yesNo("こちんこちん?", "はい", "いいえ");
    if(tumetai == 1) {
       MessageBox.show("麦茶!");
    } else {
       MessageBox.show("こーしー");
    }
}

まずこのコードを読んで、ふんふん、「こちんこちん?」って聞いて、「はい」だったら麦茶!って出して、「いいえ」だったらこーしーって出すんだな、と理解します。

ここまでは関数じゃない時とそんなに変わりません。

関数のコードを読む時にこれまでと違うのはここからです。

ここからさらに「これを一言でまとめるとなんて言えるか?」と考える事です。 例えば「lucyっぽいやりとりをする物」とまとめたとしましょう。

関数を使う時には、このまとめた物だけで考えて、そこより先のことは「考えない」というのが大切です。

やってみましょう。

使う側の視点(お嬢様視点)

使う側のコードは以下です。

lucy();

ふむふむ、これはlucyという関数を使うんだな、という事までは分かります。 ですが、使う側のコードだけではlucy()が何をするのかはわかりません。

本当は自分で書いたから知っているんですが、知らないフリをするのです。 我々は使う時には、関数が実際中で何をやっているのかは「あまり知らない」。

ただ、全然知らない訳でも無く、「lucyっぽいやりとりをする」って事だけは知っている、という設定にするのです。 キムラとレイチェルが別人、という設定にするような物です。

そこで使う側のコード、つまりこのコードは、

lucy();

「lucyっぽいやりとりをする関数を使っている」となり、つまり「lucyっぽいやりとりをやっている」ということになります。 lucyっぽいやりとりというのが何かは、使う側の視点では分からない、という事にしておくのです。

お嬢様が「lucyしろ!」って言ったら、セバスチャンが「ははっ」って言ってlucyするんです。 lucyするというのがなんなのかは細かいことはセバスチャンしか知らないのですが、 たぶんlucyっぽいことを表示するのです。

この、関数を使う時に中身を忘れる事で頭から追い出して、使う側のコードに集中する事で一度に考えないといけない量を減らす、というのが、関数にプログラムを分割するご利益となります。

中身を忘れやすい関数は良い関数

プログラムは、同じ事をするのに複数の書き方があります。 関数を作る時には、このいろいろな書き方のうち、「ここは忘れて概要だけにしても大丈夫だな」という度合いが高い切り口になるのが良い関数となり、 そういう風に考えて書いたコードが良いコードになります。

セバスチャンが何やるか考えずに、なるべく自分の事を考えられるように命令を出す。これがお嬢様ってもんです。

returnはやりとりをする為にある

以上プログラムをお嬢様とセバスチャンに分ける、という考えを説明しました。

この考えをもとに、returnというのはなんなのか?という今回の本題の話をすると、 returnはお嬢様の手に物を差し出す、という事になります。

例えば別に何も差し出してほしくない場合は、returnする必要はありません。 指をパチン、とならすと黒服グラサンがわらわらやってきて目の前のチンピラどもをやっつける、 という時には、何かを受け取る必要が無いのでreturnする必要はありません。

ただ、お茶が欲しいとかチョコレートが欲しい、という場合は受け取る必要があります。 この時は関数は「ははっ」と言ってreturnで差し出す必要があるのです。

このお嬢様とセバスチャンの間でやりとりする物、これがreturnで返す物です。

関数を使う時は、中身は考えない、という話をしてきました。 考えないけど「だいたいこんな感じのことをやってくれる」と考える。

この時に、「結論だけは教えて欲しい」ということが良くあります。

例えばイカサマサイコロの例を考えましょう。

こんなコードがあったといます。(何回か実行してみてください)

結果:

 
ぎゃー分からん!と思う前に、まずは関数を使う側だけを見ます。 難しいコードは「分割」して考えるのです。 コツは全部を一気に考えずに、まず使う側だけで予想するのです。

関数ikasama_saikoro()を使っているのは以下の部分になります。

var kekka = ikasama_saikoro();
MessageBox.show("結果は" + kekka + "です");

ここで、ikasama_saikoroの中身は考えません。 ただ、ぼんやりと、「6の目が出やすいサイコロの目を返す」とだけ思っておくのです。

そうすればここの部分は、ikasama_saikoroの中がどうなっているか分からなくても理解出来るはずです。 (なんか文字の連結がありますが、それは第二回を復習してください…)

この、関数の中身を考えない、というのが関数の奥義になります。

中で何やってるかはどうでもいいが、結果だけ欲しい

さて、この場合。 使う側として中を考えないのはいいのだけど、サイコロの目は欲しいのです。

このように「中で何をやっているかは知らんけど、結果だけ欲しい」ということは関数には良くあります。 これを実現する仕組みがreturnなのです。

returnはいつも関数を作る側でしか使えないのですが、使う側のためにやる物です。

たとえばイカサマサイコロは以下のコードでした。

var ikasama_saikoro = function() {
    var num = Math.randomInt(12);
    if(num < 5) {
        return num+1;
    }
    return 6;
};

この時、return 6とかreturn num+1とかは、使う側の為に用意してやる物な訳です。 使う側の視点だと、「なんだか知らないけど結果だけちょうだい!」と思っていて、 関数を作る側は、そのお望みに合せる。

そのお望みとは何か?というと「サイコロの目が欲しい」でした。 だからここではサイコロの目を返している訳ですね。 使う側がそれを欲しがっているから。

このようにreturnは、使っている側が欲しがっている物を考えて、それをささっと差し出す、という為に使う物です。

どうでしょう、returnが何か、なんとなくイメージが湧いてきたでしょうか?

分けて考える「練習」をする

説明としては以上で終わりなのですが、こういうのは「練習」が必要です。

そこで、これまでのコードを使って、この「お嬢様とセバスチャン」に分けて考える練習をしてみましょう。

こんなコードがあったとします(第四回参照)

結果:

 
プレーヤーにニワトリかどうか聞いて、ニワトリと答えたら"コケー"と、そうでなければ"むぇー"と表示するプログラムです。

これを関数を使うコードに直してみましょう。

先にお嬢様から考える

練習の為、ただ関数にするだけじゃなくて、順番を逆にして、先にお嬢様パートから考えてみます。 これは慣れるまで難しい!(内容的にも中級者になります…)

たとえばこんな感じです。

「まず、awaという関数があるとする。これが何かは知らないが、手を差し出して鳴き声、って言ったら、鳴き声を手に載せてくれる」

ここをどうするかは自由度があるのですが、今回はこう考えたとします。 で、このawaという関数があるかのように、まずコードを書いてしまう。

こんな感じでしょうか。

var nakigoe = awa();
MessageBox.show(nakigoe);

これは短いけど、なかなか難しいことをしています。

まだ存在してないけど、awaという関数があるかのように考える。 これは、「鳴き声!」と命令したら「ははっ」と鳴き声をどうにか持ってきてくれる、と思うことにする。

そうすると、

var nakigoe = awa();

と書いたら、用意された鳴き声がnakigoe変数にさっと渡される、と信じます。

で、このnakigoeを表示する。

MessageBox.show(nakigoe);

合わせるとこうなります。

var nakigoe = awa();
MessageBox.show(nakigoe);

このawaという関数がまだ無いのにあるかのように考えてコードを書く、というのは、想像力が必要な所です。 このawaというのはどういうことをしてくれるのかを考える。

この時に中身を細かくかんがえてはいけない。やって欲しいことだけを考える。 セバスチャンがいかに苦労しているかは考えてはいけないのです。何を自分にくれるのか、だけに集中する。 「こんなことをしてくれる関数があるとしよう!そしたらこうやってコードを書く」と、あったらいいなというい関数を勝手に決めるのです。

そして一通りお嬢様の視点でプログラムを書いたら、次はセバスチャンを作ります。

関数を後から作る

さて、お嬢様が何をして欲しいのかは最初に決めたので、そう振る舞うように関数を作ります。

まずawaという関数を考えるからこんな感じ。

var awa = function() {
};

次にこれが何をお嬢様に差し出すかを考えます。 ニワトリだったら"コケー"を、それ以外なら"むぇー"を差し出す、というのがこの関数のやることでしょうか。

だからreturn "むぇー";return "コケー";を、必要に応じてする関数です。

さて、必要に応じて、というのはどうしたらいいでしょうか?

ここでポイントになるのは、お嬢様は細かいことまでは考えてくれません。 だから、お嬢様が期待していることには答えつつ、実際にどこに買いに行くか、とかはセバスチャン側で勝手に考えてやらないといけません。

今回は、プレーヤーに「ニワトリ?」と聞いて、はいいいえかの結果に応じて、 "コケー""むぇー"を差し出すことにしましょう。

例えばこんな感じでしょうか。

var awa = function() {
    var niwatori = MessageBox.yesNo("あじゃはニワトリ?", "はい",  "いいえ");
    if(niwatori == 1) {
       return "コケー";
    } else {
       return "むぇー";
    }
};

さて、このように、関数を作る時には3つくらい考えている訳ですね。

  1. まずカラの関数を作る
  2. 何を差し出すかを決める
  3. 差し出す物をどう決めるか考える

この三段階は割とどの関数を作る時でも同じなので、新しい関数を作る時には参考にするといいかもしれません。

全部合わせる

さて、ここまで考えたお嬢様とセバスチャンを合わせてみましょう。

結果:

 
短いコードですが、こんなのスラスラ出来る訳無い、というレベルの難しさですね。

さて、プログラムには、どう考えたのか、というのが現れます。この書き方以外でも、いろいろ答えはありうる。 例えば以下の書き方でも全部同じ意味になります。

結果:

 
これは、お嬢様は受け取りもせず、ただ全部やっといて、と命令するパターンです。

これだと問題があまり「分割」されてなくて全部セバスチャンがやってるので、 セバスチャンを作る所が元の問題より簡単になってない、という問題はありますが、挙動は同じです。

もっとお嬢様にいろいろ働かせることも出来ます。 質問して、さらに結果を表示する所はお嬢様がやる、という働き者のパターンも考えられます。 例えば以下みたいなコードです。

var situmon = MessageBox.yesNo("あじゃはニワトリ?", "はい",  "いいえ");
var nakigoe = awa(situmon);
MessageBox.show(nakigoe);

これは第九回でやるargumentsが必要になるので理解はできないはずですが、 こういう書き方もありえるんだな、くらいに思っておいてください。

これを実現するなら以下みたいなコードになります。

結果:

 
このように、お嬢様が何を期待するかはある程度自由に決めて良いのです。 自由と言われても困っちゃう、という場合は、「一番自分にとって全体が簡単になる」ように考えるのが良いでしょう。

課題: こちんこちん?って聞いて、麦茶かこーしーを返す関数を作れ

さて、自分でも書いてみましょう。これは難しい…ということで、問題の後ろに、いつもよりちょっと多くヒントを出します。 また、一発では分からないと思うので、似たような課題を幾つかあとに付けます。

関数lucyの中でMessageBox.yesNoを使ってプレーヤーに「こちんこちん?」と質問し、 結果に応じて返す文字を"麦茶!""こーしー"か変えてください。

yesとnoのラベルは「はい」と「いいえ」にしておきますか。

ヒント: 第四回の、「課題: こちんこちんと言えば?」が参考になるかも。

結果:

答え:
var lucy = function() {
    var tumetai = MessageBox.yesNo("こちんこちん?", "はい", "いいえ");
    if(tumetai == 1) {
        return "麦茶!";
    } else {
        return "こーしー";
    }
}

 
これもなかなか手強い。
この課題などは、関数どうこう、というより、これまでやった事が多いので思い出すのが大変、って感じだと思いますが。

少しヒントとして、考え方の説明をしておきます。

まず、先程のawaの例と似ています。わからなくなったらawaの例を見直しましょう。「全部合わせる」の最初の例がオススメです。

以下、順番に考えていく手順を説明していきます。

何はともあれお嬢様パート

まずお嬢様パートだけを見て何をしているかを「考える」。

お嬢様パートは以下ですよね。

// 以下はいじらないでね。
var kekka = lucy();
MessageBox.show(kekka);

lucy()と命令すると、セバスチャンが「ははっ」と言って何かを返す。 で、それを表示しています。

という事は、このlucyは「表示する何か」を返す物になります。

さて、そもそも今回の課題は何を表示する物だったのでしょうか? いつもの2つの言葉のどちらかなんでしょうね。(ここ、実際に2つの言葉を自分で考えてみてください)

次にセバスチャン

セバスチャンの方では、3つの事をやるのでした。

  1. まずカラの関数を作る
  2. 何を差し出すかを決める
  3. 差し出す物をどう決めるか考える

1は問題文に既にあります。

2は先程考えた物です。お嬢様は何を期待していたんでしたっけ? それをreturnする事になります。

で3は、そのお嬢様に渡す物をどうやって用意するかを考えるのです。 プレーヤーにこちんこちんか聞いて、その答えに応じて差し出す物を変えるんです

以上を踏まえると、この課題の答えのようになります。

この課題はラストダンジョンっぽさがありますね。

同じような課題をもう一つやってみましょう。

課題: ニワトリですか?って聞いて答える奴

やりとり自体はもはやおなじみですね。 関数はコケーむぇーを返す事にしましょう。

質問は「ニワトリですか?」にしておきますか。(なんでもいいです)。

これは上の課題とほとんど同じなのでノーヒントで。

結果:

答え:
var awa = function() {
    var niwatori = MessageBox.yesNo("ニワトリですか?", "はい", "いいえ");
    if(niwatori == 1) {
        return "コケー";
    } else {
        return "むぇー";
    }
}

 
これもなかなか手強いですね。

こういうのは数をこなすと分かってくると思います。 少し同じような問題を何問か解いてみましょう。

課題: ねんがんのアイスソードをてにいれたぞ!する

ねんがんのアイスソードをてにいれたぞ!と質問(?)して、 そうかんけいないね殺してでもうばいとるのどちらか(そうかんけいないね、をyesとします)を選ばせて、

  • そうかんけいないねが選ばれたら...を(ドット3つ)
  • 殺してでもうばいとるが選ばれたらな、なにをする、きさまらー!

返す関数、nenganを作れ。

ヒント。文字の値は違うけど前の問題と似ている。 前半は以下のMessageBox.yesNoですね。

MessageBox.yesNo("ねんがんのアイスソードをてにいれたぞ!", "そうかんけいないね", "殺してでもうばいとる");
結果:

答え:
var nengan = function() {
    // ubauの名前はなんでもいいです。
    var ubau = MessageBox.yesNo("ねんがんのアイスソードをてにいれたぞ!", "そうかんけいないね", "殺してでもうばいとる");
    if(ubau == 1) {
        return "...";
    } else {
        return "な、なにをする、きさまらー!";
    }
}

課題: 剣か素手で攻撃

何で攻撃する?と質問して、素手のどちらかを選ばせて、

  • が選ばれたら20を(今回は数字で。つまり「”」でくくらない)
  • 素手が選ばれたら5

返す関数、makeDamageを作れ。これまでずっとreturnは文字でしたが、今回は数字を返す事にします。(意味が分からなければ気にしなくてもいいです、文字を返しても正解になります)

なお英語の説明をしておくと、Damageはダメージの事で、makeは作るという意味です。 ダメージ計算の関数ですね。

結果:

答え:
var makeDamage = function() {
    // bukiの名前はなんでもいいです。
    var buki = MessageBox.yesNo("何で攻撃する?", "剣", "素手");
    if(buki == 1) {
        return 20; // return "20";では無い
    } else {
        return 5;
    }
}

課題: 斧か棍棒で攻撃

何で攻撃する?と質問して、棍棒のどちらかを選ばせて、

  • が選ばれたら30
  • 棍棒が選ばれたら10

返す関数、makeDamageを作れ。

結果:

答え:
var makeDamage = function() {
    // bukiの名前はなんでもいいです。
    var buki = MessageBox.yesNo("何で攻撃する?", "斧", "棍棒");
    if(buki == 1) {
        return 30; // return "30";では無い
    } else {
        return 10;
    }
}

次は確率でクリティカルを出す問題を何問かやってみましょう。

課題: 1/2の確率でクリティカル!

1/2の確率でクリティカルを出すプログラムをしてみましょう。

1/2の確率で クリティカル!30のダメージを、1/2の確率で10のダメージを返す関数、 makeDamageを作れ。

ヒント: 今回はyesNoとかは使いません。Math.randomInt(2)を使って、0か1のどっちかだったらクリティカル扱いする(どっちでもいい)。Math.randomIntについては、第5回の「乱数でランダム」あたりを見直すと良いかも。

結果:

答え:
var makeDamage = function() {
    // docchiの名前はなんでもいいです。
    var docchi = Math.randomInt(2);
    if(docchi == 1) {
        return "クリティカル!30のダメージ";
    } else {
        return "10のダメージ";
    }
}

ようするに100円玉を投げて、表が出たらクリティカル、とする訳ですね。 この時、裏が出たらクリティカル、にしても出やすさは一緒なので、if文は1でも0でもどっちの条件でも良い。

なかなか難しいので似たようなのをもっとやりましょう。

課題: 5回に一回の確率でクリティカル!

二回に一回は多すぎる、という事で、もうちょっと減らしましょう。 数学的には20%の確率でクリティカル、算数で挫折した我ら的には「5回に一回の割合」でクリティカルを出す事にします。

5回に1回の確率で クリティカル!30のダメージを、それ以外では10のダメージを返す関数、 makeDamageを作れ。

ヒント: Math.randomInt(5)を使って、どれかの数字ならクリティカル扱いにする。 クリティカルにする数字はどれでもいい。

結果:

答え:
var makeDamage = function() {
    // docchiの名前はなんでもいいです。
    var docchi = Math.randomInt(5);

    // 0でも1でも2でも3でもいいが、ここでは4にした。
    if(docchi == 4) {
        return "クリティカル!30のダメージ";
    } else {
        return "10のダメージ";
    }
}

ようするに5面のサイコロをふって、3が出たらクリティカル!とか決める訳ですね。 この時3が出たらクリティカルにするか、4が出たらクリティカルにするかはどっちでも出やすさは一緒という事です。

このように、「XX回に1回の割合で何かをする」という時は、XX面のサイコロを振ってどれかの目が出たら〜というプログラムを書けばいい訳です。

なかなか難しいですね。もうひとつ似たようなのをやってみましょう。

課題: 10回に1回の確率でクリティカル!

5回に一回は生ぬるい、という事でもっと減らしましょう。10回に一回にします。

10回に1回の確率で クリティカル!30のダメージを、それ以外では10のダメージを返す関数、 makeDamageを作れ。

結果:

答え:
var makeDamage = function() {
    // docchiの名前はなんでもいいです。
    var docchi = Math.randomInt(10);

    // なんでもいいけどここでは1にした。前回と同じ4でもいいのだがなんでもいいというのを示す為あえて変えた。
    if(docchi == 1) {
        return "クリティカル!30のダメージ";
    } else {
        return "10のダメージ";
    }
}

10回に一回だと、本当に出るか確認するために「実行」ボタンを何度も押すのも大変ですね。(私は7回目でクリティカルが出た)。

なお、どうでも良い事ですが、このページの採点システムは200回実行して10回に1回くらいになっているかを確認しています。 すごく運が悪い人は正解のコードを書いても不正解になる事があります。

ここまでの知識をあわせると、yesNoで剣か素手か選ばせて、さらに5回に1回クリティカル、とかも作れるはずです。 (課題を評価する私が大変なのでやりませんが)

関数の作り方にちょっと慣れてきたら、今度は関数を作る側と使う側の頭を切り替える練習という事で、 あえて変な関数に合わせたコードを書く、というのをやってみましょう。

課題: ニワトリですか?って聞いて答える奴、無能な執事バージョン

次はまた同じような事をやるのですが、あえて関数の方は難しくしてあります。(良くないコードですね)。 執事が無能なので、お嬢様の方がちょっと頭を使ってやる必要がある。 無能な老いぼれなんだけど、いい奴なんですよ。

という事で、関数の方はいじらないで、使う側を正しく直して、上と同じ事をするプログラムにしてください。 パズルみたいな物としてお嬢様側のコードを考えてみてください。

結果:

答え:
var kekka = awa();
if(kekka == 100) {
    MessageBox.show("コケー");
} else {
    MessageBox.show("むぇー");
}

 
500の方でifしてもいいです。(そちらでも「正解」になるようにしてあるので興味があればやってみてください)。 勉強の為に、あえて変なコードになるような問題にしてみました。

課題:るーしーの奴、別バージョン

さて、るーしーも似たような事やってみましょう。

まず関数のコードを読んで、こいつが何を差し出すのかを考える。 で、それが分かったら、使う側のコードを書く訳です。

結果:

答え:
var kekka = lucy();
MessageBox.show(kekka);

 
答えのコード自体は短いのですが、スラスラっと出てくるには少し修行が必要でしょうね。 という事でもっとやっていきましょう。

課題:るーしーの奴、無能な執事バージョン

無能な執事のパターンです。 またヘンテコな関数に対して、使う側で工夫してどうにか目的を達成しましょう。

結果:

答え:
var kekka = lucy();
if(kekka == 1234) {
    MessageBox.show("麦茶!");
} else {
    MessageBox.show("こーしー");
}

 
無能な執事の時には、この老いぼれでも出来そうな事を考えてやって、 優しく命令してやりましょう。菅平ゆりかさんも根はいい奴なのです(だから誰?)。

イカサマサイコロを真面目に考える

本題とは関係無いのですが、読んでる人が気になってそうなので、これも真面目に説明しておきましょう。 第八回の内容とはあまり関係無いので、分からなくても別に構いませんが、 レベル上げの一貫として、いろいろコードを見ていきます。新しい要素は別段出てきません。

例えば、1から6までのサイコロで、6がちょっと多めに出る物を作るとします。 第五回の内容を元に、何も考えずに作ると、以下のようになります。

結果:

 
なんかおんなじようなのがたくさん並ぶと、目がチカチカして良くわからなくなりますね。(なりません?)

まず、最初の所で、以下のようにしています。

var ransuu = Math.randomInt(12);

これで、ransuuには0から11までの数字が入ります。

その後のコードで、ransuuが0から4までならそれぞれの目を表示し、5より上は全部6と表示します。 なんで一つずれているかというと乱数は0から始まり、サイコロは1の目から始まるからです。

これを、以下では何段階か簡単にしていきます。

第五回までの内容の変形

ちょっと頭を使うと、同じ事を以下のようにも書けます。

結果:

 
5, 6, 7, 8, 9, 10, 11の時は全部同じ内容なので、この場合はelse一発で書けます。

さて、さらにこのメッセージだけを変数にして、最後にMessageBox.showするように直す事も出来ます。

結果:

 
ifの外にvar saikoronome;と書かなくてはいけない理由などはあまり真面目に解説してこなかったので、分からなくてもOKです。ここはこういう物だと現時点では思っておいてください。
で、それ以外の部分は理屈は分かるはずです。

さて、ここまででも大分短くなりましたが、この内容はさらに0から4までは1ずつずれるだけだ、という事実を考えると、もっと短く書けます。

例えば以下みたいなコードでも良いはずです。

結果:

 
if(ransuu < 5)というのは初めて出てきましたが、似たようなのはツクールでもあると思います。 「ransuuが5より小さかったら」という意味です。

ここまで、全部第五回!

ここまでの説明、ずいぶん難しい話だな、と思うかもしれませんが、ここまではなんと、第五回の内容です。 それが証拠に、functionという文字は一切出てきていない。

ただ、新しい要素が出てきてないから全部分かるか、っていうとそんな事も無いはずです。 個々の要素を説明したからといって、それを組み合わせた事が全部分かる、という程、世の中は甘くない。 これはプログラムどうこう、という問題では無いですが。

結局、組み合わせた時の難しさは、こういう実際の難しさにぶつかっていって、「あー」とか「うー」とか言いながら学んでいく事になります。

さて、ポエムはこの位にして、このコードをさらに関数にしてみましょう。

第八回の内容を使ってさらに変更

これを関数にすると、以下のようになります。

結果:

 
一つ前のバージョンと見比べてみると、function()をつけて最後にreturnをつけた、位のちょっとした違いです。

さて、これで最初の方に課題で挙げたコードとほぼ同じ物になりましたが、ちょっとだけ違います。 この関数をもうちょっと短く出来るようですね。

関数にしたら、いちいちsaikoronomeなんて変数に入れずに、返す物が決まった所でreturnしてしまっても良い、という事に気づくと、 さらに短く出来ます。
たとえば、以下のように変えられます。

結果:

 
この関数はほとんど最初に挙げたイカサマサイコロと同じコードになりました。
実はさらにちょっとだけ最初に挙げたコードと違いますが、ここから先はどちらでも良いか、というレベルの話なので解説はしません。 興味があったら見比べてみてください。

こんなの分かるかー!と思ったら

ここまでの説明をふんふんなるほど、別に大した話じゃないな、と思ったらそれで良いのですが、 最初のif-elseがぶわーっとあるコードから最後のコードまでたどり着くのは結構大変と思います。

実際プログラムの入門者に最初のコードを見せて、「関数を使って短くしろ」と言ったら、 最後のコードはなかなか出てこない。 このレベルの作業は、さすがにまだしばらくは出来なくても良いかな、と思います。

ただ、こういう感じで変形していく、というのを見るのは勉強にはなるので、ここでは勉強の為に軽く実演してみました。

また、自分でも同じ事をやるのは難しいとは思いますが、 最後のコードを見せられた時に、それを理解するのは、それよりはもうちょっと簡単と思います。 ゲームを作るのは難しくても、それをプレーする事は出来ますよね。 それと同じで、コードを直すのは難しくても、出来たコードを理解するのは比較的簡単です。

という事で、最後の結果だけを理解するのは頑張ってみてもいいかな、という気はします。

もっと言えば、最後の結果が理解出来なくても、第八回の内容としては致命的という訳ではありません。

ikasama_saikoroを自分で作るのは難しくても、お嬢様の立場で使う事さえ出来れば良いのです。 それだけでも、かなりいろいろな事は出来ます。
つまり、以下のようにやれば

var kekka = ikasama_saikoro();

kekkaには1から6までのどれかの数字が入って、しかも6が多めなんだろう、という事さえ分かれば、このJS入門のシリーズには十分なレベルかもしれません。

なんだか分からないが使えればいいか、というのも時には大切です。 気持ち悪いかもしれませんが、えいって飲み込むのです。

課題:1から6までの数字をランダムに返すサイコロを作れ

せっかくここまでやったので、サイコロを作るというのをやってみましょう。

今回はイカサマじゃなくて、ちゃんと1から6までランダムに結果を返す関数を作りましょう。 サイコロ自体のヒントとしては、第五回の「課題: 6面サイコロを作れ」のあたりを参考にすると良いでしょう。

あと、第五回では変数名でsaikoroとしてましたが、今回は既に関数の名前がsaikoroなので違う名前の方が無難です(rannsuuとかにしましょうか)。

結果:

答え:
var saikoro = function() {
    var ransuu = Math.randomInt(6);
    return ransuu+1;
    // 分かるなら return Math.randomInt(6)+1;でもいいです。
}

 
答えは短くても、ちょっとこの問題は難しいですね。 この辺まで来ると普通のプログラマという感じ。

せっかくなので、もっと違う事をいろいろやってみますか。

課題:蕎麦充せよ。

るーしーはしゅるしゅるするだけとは限りません。 そうです。蕎麦充する事もあるのです。

そこでここでは、ランダムに、

  1. 蕎麦充した
  2. しゅるしゅるした

と表示するプログラムを作ってください。 ただし、関数はこっちが作ったlucy関数を使う事。

二番目のメッセージは「こーしーを」ってつけなかったのに注意して下さい。これは私の気分の問題で、意味はありません。

この問題もラストダンジョン感あります。

結果:

答え:
var kekka = lucy();
if(kekka == "こーしー") {
    MessageBox.show("しゅるしゅるした");
} else {
    MessageBox.show("蕎麦充した");
}

 
これも難しいですね。関数を作る所を見る事で、この関数が何をするものかをまず推測し、 そこからこの関数を使うコードを書く必要があります。

ラストダンジョンなので、たまにオメガとか神龍とかハニワとか、ラスボスよりも強い倒せ無さそうな敵も出てくるのです。 倒すとたぶん、なんか強い武器落とします。

コードを読んで考える、という練習の為に、すでにあるコードからいじる場所を探す練習もしてみましょう。

課題: コードを書き換えて、武器を「剣と素手」から「斧と棍棒」に改造しよう

剣か素手で攻撃するコードがあります。 まずコードを読んで理解し、

  • 素手

の二種類を、

  • 棍棒

の二種類に変更しましょう。

ダメージ表記の所も書き換えましょう。 ダメージの数字自体は斧の時に20, 棍棒の時に5のままでOKです。

結果:

答え:
var makeDamage = function() {
    var buki = MessageBox.yesNo("何で攻撃する?", "斧", "棍棒");
    if(buki == 1) {
        "斧で攻撃、20のダメージ";
    }
    return "棍棒で攻撃、5のダメージ";
}

課題: コードを書き換えて、クリティカルの出る割合を2回に1回に増やそう!

10回に1回の割合でクリティカルの出るコードがあります。 このコードを読んで理解し、クリティカルの割合を2回に1回出るように改造しましょう。

ちなみにクリティカルは英語でcriticalと書きます。

結果:

答え:
var makeDamage = function() {
    var saikoro = Math.randomInt(10);

    if(saikoro < 5) {
        return 1;
    } else {
        return 0;
    }
}

ちなみに解き方は何種類かあります。「正解です。」って出れば回答例と違うやり方でもOK。

結果を返す、もらう、まとめ

第八回では、結果をもらうという方法と、 その結果を返すという事について扱いました。

関数を使う時

  • 関数を使う時に結果がもらえます
  • 結果をもらうには、var kekka = lucy();などのように、イコールで変数にもらいます。

関数を作る時

  • 関数を作る時に結果を返す事が出来ます。
  • 結果はreturn "むぇー";などのように、returnで返します。returnは関数を作る時だけ出来る事です。
  • returnすると関数はそこまでで実行を終えます

長い内容なのにまとめると短いですね…

また、タカビーなお嬢様とセバスチャン、という考え方もやりました。これは次回も使っていきます。

第八回は難しいですねぇ。 説明も長いですし、課題も難しい。 ここらへんはこのシリーズの最難関でしょうね。