プログラミング初心者の野球部に関数とは何かを説明する。

2023/08/02に公開

こんにちは!
今日も昨日の振り返りを行っていきたいと思います!

昨日やったこと

昨日も引き続きMDNというサイトのチュートリアルを進めました。
その中の「バカ話ジェネレーター」というプログラムにを実装しながら、「関数」と「if文」についての理解ができた気がしているので、ここに言語化しておこうと思います。

https://developer.mozilla.org/ja/docs/Learn/JavaScript/First_steps/Silly_story_generator

こんな感じのゲームです。

https://twitter.com/YangYooji3942/status/1686637364545036288

まず、「バカ話ジェネレーター」でで実装した機能は以下の3つでした。

  1. 元の文の3箇所に対して、単語がランダムに変わるようにする。
  2. 名前を入力した場合、文中の名前が入力した名前に変わるようにする
  3. UKのラジオボタンにチェックを入れた場合、重さと気温の単位を変化させる

この機能を実装するにあたり、例の「関数」と「if文」を使いました。
「関数」と「if文」はProgateなどをやっていても必ず出てくるもので、プログラミングにおいて基本中の基本ですが、初学者にとって最初のハードルとなる部分だと思います。
私も数をやることによってなんとなくの理解はしていましたが、野球に例えることによって自分なりにスッキリしました。

「関数」を野球で考える

まずは関数です。
関数とは?とググると以下のような検索結果が返ってきます。

プログラミングの「関数」とは、与えられた値をもとに、定められた独自の処理を実行し、その結果を返す命令のことです。

野球部にはちょっとわかりづらいので、これを野球のエンドランという作戦に当てはめて考えてみましょう。

監督からエンドランのサインが出た時、実は自然にエンドラン関数を私たちは実行しているのです。
一体どういうことでしょうか?

まず、「与えられた値」というのは、「何球目に実行するのか」ということです。
監督からのサインで考えると、大抵の場合次の球で実行するということになるでしょう。
しかし、あらかじめ「2球目にやる」とか「3球目にやる」とかを指定できるのです。
与えられた値のことを「引数」と言います。

次に「定められた独自の処理」というのは、エンドランという作戦そのもののことです。
具体的には下記の処理が行われています。

1. "スタートする" → ランナーはピッチャーの投球と同時にスタートする
2. ”スイングする” → バッターはストライクボール関係なしに絶対に振る
3. ”ゴロを打つ” → バッターはバットにボールを当ててゴロを打つ

なんとなくイメージが掴めたでしょうか?

少しコード的な解釈に寄せると、私たちが監督からエンドラン作戦のサインが出た時に、バッターやランナーが作戦通りの動きをできるのは、以下の2つのステップによるものです。

  1. 予めエンドラン作戦というものがどういうものかを知っている。
  2. 「エンドラン作戦」というサインが出る。

このステップの1つ目のステップを「関数の定義」、そして2つ目のステップを「関数の呼び出し」と言います。

試合中にエンドラン作戦を実行するというのが、関数の呼び出しです。
そして、試合中にエンドラン作戦が実行するために、試合前のミーティングなどで「エンドランとは何かをみんなが知っている状態にすること」が関数の定義にあたります。

「関数」とか「定義」というワードは野球をしていて中々使いませんが、同じ意味のことはすでにやっていたのです。

コードにしてみる

それでは実際にコードに当てはめてみましょう。
まずは関数の定義からです。
エンドランはこんな感じのコードになるでしょう。

function エンドラン(〇〇球目) {
    const エンドラン作戦 = スタートする(スイングする * ゴロを打つ);
    return 〇〇球目 に エンドラン作戦;
};

1行目の"function ~"という部分で、関数の命名を行っています。
今回の場合は「エンドラン」という名前の関数を命名しました。

エンドランの後の()の中には「引数」という値が入ります。
これは上で紹介した「与えられた値」に該当するものです。
例えば"エンドラン (2)"となっていれば、「2球目」を意味します。

2行目の"const エンドラン作戦 = スタートする(スイングする * ゴロを打つ);"は、
エンドラン作戦がどういうものかを定義しています。
()の中の処理はバッターの処理です。バッターはバットを振ってゴロを打ちます。
それに加えて、スタートするというランナーの処理が加わることで、エンドラン作戦が完成します。

3行目のreturn 〇〇球目 に エンドラン作戦;は、
引数の数値の球数でエンドラン作戦を実行するということを意味しています。

これで試合前のミーティングが完了したので、試合中にエンドラン作戦を実行する準備ができました。

それでは実際に関数を呼び出してみましょう。
関数を実行するには、

関数名(引数);

としますので、例えば3球目にエンドラン作戦を実行したい場合は、

エンドラン(3);

とすれば良いです。
1度定義しておけば、簡単に呼び出せるというのが関数の良いところです。
野球の試合中でも、「次の球でランナーは走って、バッターはボールでもストライクでも全部振って、さらに絶対にゴロを転がせよ!」とはいちいち指示できませんよね。
これらのプレーを「エンドラン」という関数として定義しているから、試合中に監督のサインで簡単に呼び出せるのです。

今回の教材の関数を見てみる

これを踏まえて、今回勉強した「バカ話ジェネレーター」内で使われている関数を見てみましょう。
下記がそのコードです。

// 配列の中からランダムな値を取得
function randomValueFromArray(array){
  const random = Math.floor(Math.random()*array.length);
  return array[random];
}

### 1行ずつみてみる

1行目

function randomValueFromArray(array){

ここでは、"randomValueFromArray"という名前の関数名が宣言されています。
エンドラン作戦の例で言うと、「この作戦を”エンドラン”と名付けます」と言う部分ですね。
引数には"array"と言う変数が設定されています。

2行目

const random = Math.floor(Math.random()*array.length);

ここではこの後実行される"random"と言う処理がどういったものなのか?ということを説明しています。
エンドランの例で言うと、「”エンドラン作戦"とは、”ランナーが走って、バッターが打ってゴロを打つ”作戦です」と言う部分ですね。

このコードが示している"Math.floor(Math.random()*array.length)"について、
”Math.floor"と、
"(Math.random() * array.length)"に分けてみてみましょう。

"(Math.random() * array.length)"について

まずは()の中の"(Math.random() * array.length)"についてです。
エンドランの例ではバッターの動きに当たるところですね。
この中身も、
"Math.random()” と、
”*”と、
 ”array.length"の3つに分けることができます。

まず、"Math.random()”は、「0以上1未満の乱数を生成する」と言う処理です。

次に、 ”array.length"は、"array"と".length"に分かれます。
"array"とは、1行目で出てきた引数です。
".length"は配列の中身の長さを測る処理です。
つまり、引数の"array"は配列であることが期待されています。

配列については、下記の記事を参考にしてください。

https://qiita.com/ren0826jam/items/98a0198c01f105e6cb67

そして、"*"はそれらの数値を掛け算すると言う処理です。
例えば、"Math.random()”が0.5で、”array.length"が3なら、”1.5”という値が作られます。

”Math.floor"について

続いて、”Math.floor"ですが、これは少数を切り捨てると言う処理です。
つまり、先ほどの1.5という数値を”1”に変換する処理を行います。

この関係性はエンドラン作戦のスタートして、振ってゴロを打つと同じですよね?

3行目

そして、最後の行です。

return array[random];

これは引数である”array"配列の[random]番目の値を返します。という意味です。
例えば、先ほど"random"では”1"という値が生成されましたので、その場合は「
"array"配列の中の2番目(0からカウントする為)の値を返す」という意味になります。

ここでもう一度全体を見てみる

// 配列の中からランダムな値を取得
function randomValueFromArray(array){
  const random = Math.floor(Math.random()*array.length);
  return array[random];
}

つまりこのコードの意味は、「引数"array"の配列の中からランダムで値を取り出す」という処理を"randomValurFromArray"という関数名で定義しました。」というものです。

これで試合前のミーティングは終わりました。
では実際にどのように使われているのでしょうか?

実際にどう使われているのか?

このコード内では下記のような使われ方をしています。

これは引数として渡される配列を定義している部分です。

// ランダムで変化する文章の配列
const insertX = [
  "Willy the Goblin",
  "Big Daddy",
  "Father Christmas"
];

const insertY = [
  "the soup kitchen",
  "Disneyland",
  "the White House"
];

const insertZ = [
  "spontaneously combusted",
  "melted into a puddle on the sidewalk",
  "turned into a slug and crawled away"
];

そして、これが"randomValueFromArray"関数が呼び出されている部分です。

// 文章をランダムで置換する処理
let newStory = storyText;
const xItem = randomValueFromArray(insertX);
const yItem = randomValueFromArray(insertY);
const zItem = randomValueFromArray(insertZ);

newStory = newStory.replace(/:insertx:/g, xItem);
newStory = newStory.replace(/:inserty:/g, yItem);
newStory = newStory.replace(/:insertz:/g, zItem);

例えば3行目だと、”insertX"配列の中からランダムで値を選択して、”xItem”という変数に格納しています。ここが監督からサインが出るところにあたります。

そして、その後の6行目にて、"xItem"を”newStory"内の、":insertx:"という部分に置き換える処理を行って、バカ話が生成されるという仕組みになっています。

この処理が3回繰り返されていますが、これを関数を使わずに実装しようとするとかなりコードが長くなってしまうので、やはり関数は非常に便利なものだと言えます。

想像を遥かに超える長文になってしまった

ダラダラと文が長くなってしまいました。まだまだ理解が浅いのかと思います。
このままif文についても書き進めると今日が終わってしまうので、今日はここまでにして明日に書くことにします。
プログラミング初学者の野球部の皆様、なんとなくイメージはできたでしょうか?

これからもプログラミング初心者の野球部の方(=わたし)に向けて記事を更新していきますので、よろしくお願い致します。
では、今日も学習を進めます!

Discussion