技教えシステム_解説記事3
技教えシステム_解説記事3
解説記事3:システムの理論解説
はじめに
どうも空気です。
前回に引き続きいよいよ三回目となるこの記事では、いよいよ二進数値として保存した真偽データ群を実際のシステム上でどのように使用するのか、その方法を説明していきたいと思います。
まず、今我々は何を作ろうとしているのか
さて、いきなり質問です。
まず、今我々は何を作ろうとしているのか。
皆さんはここまでの記事をお読みいただいた上で、この質問に的確に答えられるでしょうか。
なんや?突然そんな質問をして。教え技システムを作ろうとしているんちゃうんか?
全くその通りです。
ですが、その考えはいささか大雑把すぎるのです。
教え技システムといっても、システムはその中身を機能によっていくつかの部分に分解することができます。
教える技を選択する部分、覚えるキャラを選択する部分、選択したキャラが選択した技を覚えられるか判定する部分、実際に習得する部分……
できる限り大枠で分けても4つの機能に分解されるのは分かるでしょうか。
そして今、二進数による可否データを用いて作ろうとしているのは上のどの部分か、これを頭に入れておくことが大切です。
私は以前の記事で、キャラクターに個性を持たせるため習得できる技に制限をかけるとお話ししました。
我々が今、2進数可否データを用いてやろうとしていることは、この習得技の制限動作、すなわち「選択したキャラが選択した技を覚えられるか判定する部分」です。
もし、すべてのキャラが全ての技を自由に習得できるゲームを作る場合は、今から説明するシステムは全て不要なものです。
この記事で私がお話しするのは、あくまで「選択したキャラが選択した技を覚えられるか判定する部分」の構成だということを念頭に置いたうえで、続きの話をお読みください。
システムの概念
さて、まずはシステムがどんなものかを考えるのに先立ち、システムは何を目的として、どんなデータを操作するのかということを理解しましょう。
下の図をご覧ください。今、我々が作ろうとしているものについて、その大まかな概念図を用意しました。
ここで、キャラ固有番号とはあらかじめキャラに重複のないように割り当てた番号、技固有番号とはあらかじめ技に重複のないように割り当てた番号を意味します。
具体的には技はスキル欄のs011と言った数値の下二桁を切り出して割り当てると都合がいいでしょう。
キャラに関してはスキルと同じようにc001のような下二桁を切り出して当てはめたいところですが、ビットゲームメーカーの仕様により、下二桁の先頭が0となる値は後々不都合が生じてしまいます。(たとえばc001の下二桁を切り出すと01となりますが、これは好ましくない)。
ですので、下二桁を切り出したのち、それに10を加えた値を固有番号とするのが無難かと思われます。(c001なら切り出した下二桁01に10を加えた11を固有番号とする。C012なら同様に22が固有番号になる)
さて、上の概念図が意味するところは、blackboxの中身は一旦脇に置き、blackboxにキャラ固有番号と技固有番号を入れるとblackboxは受け取った固有番号のキャラが受け取った固有番号の技を覚えられるかどうかという結果を出力するということです。
とても単純な話ですね。
固有番号から可否データを取り出そう!
では、次はこの単純なシステムを構成するblackboxの中身を見ていきましょう。
用意するのは入力するためのキャラ固有番号、技固有番号、そして習得可否二進数を格納した可否変数です。
これらを使って入力されたキャラが入力された技を覚えるかどうか、その結果を出力するには……その方法を具体例を通して考えていきます。
下の図をご覧ください。これは実際に私が投稿した技教えサンプルにおける、「つるぎのまい」という技の習得可否を示したものです。
(前回までの記事とキャラクターの並びが逆になっていますが、投稿したシステムの仕様に準拠したほうがよいと判断したため入れ替えました。オーガポン(一番右の緑色のキャラクター)が二進数最小位、ケフカ(一番左の紫のキャラクター)が二進数最大位として可否データは作成しております)
技教えサンプル中で「つるぎのまい」はs015のスキルですから、技固有番号は15になっています。
また、「つるぎのまい可否」という「つるぎのまい」の習得可否を記録する変数には
100000111001(2)がデフォルトで格納されています。
100000111001(2) = 2105になりますから、「つるぎのまい可否」には2105が格納されていることになります。
では、ここでシステムの動作を確認するため、カイリュー(左から6番目の黄色いムーミンみたいなやつ。通称マルスケデブ)が「つるぎのまい」を覚えようとする場合の動作を追ってみましょう。(技教えサンプル内ではなぜか名前が韓国語になっていますが気にしないでください)
カイリューはc006にあたるキャラなので、そのキャラ固有番号は16です。
また、「つるぎのまい」はs015にあたる技なので、技固有番号は15になります。
そして、今我々はカイリューが「つるぎのまい」を覚えるかどうか調べるため、
「つるぎのまい可否」という変数の値2105を与えられました。
では、この三つの情報からカイリューが「つるぎのまい」を覚えるかどうか判別しましょう!
…………
……
…
できるかボケ!!アホ!!(矢野先生波感)
二進数可否データを用いる最大の弊害
以前投稿した記事で私は二進数データを用いる最大のメリットはデータ枠の圧縮だといいました。
しかし同時にこのデータ枠の圧縮というのはシステムを複雑化させる最大の弊害となってしまうのです。
では、なぜシステムが複雑になるのか。その答えは、目的のデータを取り出すために一回り多くの手間がかかることが避けられないからです。
二進数データそのものへは直接アクセスできますが、その内部の個別習得可否データへは直接アクセスできない。可否変数に格納されている数値を、特定の法則によって変形することで初めて所望のキャラの習得可否データを取り出すことができる。
そのためには何段階かの処理が必要で、その処理を実装するためにシステムを複雑化する結果となってしまうのです。
先ほどのカイリューが「つるぎのまい」を覚える場合を例に見てみましょう。
二進数可否データにおいてカイリューが「つるぎのまい」を覚えるかどうかは、低位から6桁目に格納されています。
この6桁目の値が1ならカイリューは「つるぎのまい」を覚える、0なら覚えない。
二進数データにはこのように情報が記録されます。
先ほどの表をもう一度見てみましょう。
表中の低位から6桁目(右から6桁目)の値は1です。つまり、カイリューは「つるぎのまい」を覚えることができます。
システムはカイリューが「つるぎのまい」を覚えるという判断をするためにこの低位から6桁目の「1」という値を的確に取り出す必要があるのです。
いま、システムが処理を行うための情報として持っているのは覚える技は「つるぎのまい」であるという技固有番号の数値15と、技を覚えるのはカイリューであるというキャラ固有番号16です。
この二つの値を使って可否変数から所望の位の値をとりだすにはどうしたらいいのでしょうか。
それには現在保持している二つの値に加え、もう一つの値を用意する必要があるのです。
キャラ固有位値の導入経緯
今まで、我々はキャラ個別番号と技個別番号の二つの変数を用いてシステムを動かすことを考えていました。
ですが、この二つの変数だけでシステムを完結させるにはいささか不都合があります。そこで、先述したキャラ固有位値の概念を新たに導入しようというわけです。
新しい変数を導入する前に、まずはシステムの概要がどんなものだったか改めて振り返ってみましょう。
下の図をご覧ください。図は以前にも示したシステム概念図を、blackboxの中身を多少詳細にした上で再び示したものです。
Blackboxの中身は主に二つの処理で構成されています。最初が技固有番号を利用した選択技の可否変数取得、その後取得した可否変数から対応キャラの可否格納桁の値を抽出し1か0かを判別するという構成です。
最初の可否変数の取得はその構造もシンプルです。技固有番号を教え技として設定するすべての技に連番で割り当て、そしてその順で変数枠の連番を確保しておけばいいのです。
スキルの固有番号をスキル欄番号の下二桁と一致するように定めた上で図のように可否変数を設定しておけば、適当な仮変数1に[20 + スキル固有番号]の値を格納しその後適当な仮変数2に「変数番目の変数を代入:仮変数1番目の変数」を行うことで仮変数2に可否変数が取得できます。
さて、blackboxの中身について最初のブロックの問題は容易く解決しました。しかし、問題はこの後です。
取得した仮変数から、カイリューの可否データを格納している桁の値をとりださなければいけません。
さて、先ほどもお話ししたように、今我々の手元にあるのは技固有番号、キャラ固有番号、可否変数の三つです。
このうち、技固有番号は今は関係ありません。すでに技に対応する可否変数をとりだすことに成功したため用済みです。
いま、我々がしようとしているのはとりだした「つるぎのまい」の可否変数から、カイリューが覚えるかどうかを記録した桁をとりだすことです。
ですが、この目的を達成するにあたり我々が今持っているカイリューの固有番号16はあまりにも不適当です。
いや、キャラにはそれぞれ前から連番ふってるんやろ?ほなら、二進数の桁を前から数えて連番の数と合致する奴をとればいいやんけ。
こう思う方もいらっしゃるでしょう。しかし、この処理は非常に複雑です。なぜなら、ビットゲームメーカーにはべき乗が存在しないから。
ゆえに連番参照で処理をしようとすると不要なループ処理が入り込み、全体構造がますますややこしくなってしまいます。
この複雑化への対策として固有位値を導入するのです
固有位値の導入
まず、固有位値とはどんな概念か、説明するより視覚的に見てもらった方が早いと思うので表を用意しました。
固有番号と併記しましたので一度ご覧ください。
どうでしょう?ざっくりと雰囲気は掴んでいただけたでしょうか。
固有位値とは端的に言えばキャラごとに与えた2のべき乗の値。
式的に表すと固有番号をn、固有位値をmとしたとき m = 2n-11で表されることが分かるかと思います。
そしてこの固有位値は可否変数から選択キャラの可否データを抽出する際に非常に強力な効果を発揮します。
それは、可否変数においてあるキャラのデータが1の時、その1はキャラの固有位値に一致しているからです。
このことが固有位値という新たな概念を導入することで享受できる最大の利便性なのです。
実際に抽出計算をしてみよう!
物は試しと言いますし、まずは実際の計算をして如何に固有位値が便利かを確認してみましょう。
ここまでの説明で出てきた「つるぎのまい」の可否変数とカイリューの固有位値はそれぞれ、
「つるぎのまい」の可否変数:100000111001(2) = 2105
カイリューの固有位値:32
です。この情報を用いて、カイリューが「つるぎのまい」を習得できるかどうかのデータを取り出します。
で、肝心の方法ですが、それは…
- 固有位値×2
- 可否変数を二倍された固有位値で割った剰余を取得
- 剰余を固有位値で割った商を取得、これがカイリューの習得可否データ!!
以上になります。
……詳しく見てみましょう。
まず、「つるぎのまい」の可否変数100000111001(2) = 2105、これを2のべき乗ごとに分解して多項式形式で表すと、
2105 = 2048 + 32 + 16 + 8 + 1
で表されます。下の表を見ていただくと、数値の意味をより深く理解していただけると思います。
表上の可否変数値と固有位値の関係性は、先述した可否変数の1の値が固有位値に一致するという話にも適っていますね。
さて、では続いては2105という値からカイリューの可否データを取り出していきます。
- 固有位値×2
カイリューの固有位値は32なので二倍すると64になります。
- 可否変数を二倍した固有位値で割った剰余を取得
2105÷ 64 = 32 余り 57 ∴剰余は57
- 剰余を固有位値で割った商をとる
57 ÷ 32 = 1 余り 25 ∴商は1
はい、出ました。答えは1、つまりカイリューは「つるぎのまい」を覚えることができます。
もう少し一般的な説明
さて、先ほどのクソ雑計算を見て、そんなんでええんかと思った方もいらっしゃるでしょう。(受験生はむしろ当然やろなにこの程度で記事にしとるんやクソ野郎くらいに思おうね。そう思えなかった受験生の君は素因数分解と等比数列を今すぐ基礎からやり直せ。)
ここではもう少し話を深堀し、先ほどの計算で的確に1が取り出せる理由を説明しようと思います。
(1)の部分は説明するまでもないので、(2)のところからお話しします。
(2)で可否変数を二倍した固有位値で割った剰余をとる理由
これはすなわち、カイリューより固有位値が大きいキャラの可否データの除去です。
一度表を見てみましょう。
先述したように、二進数表記の可否変数においてある桁に1が存在することは、可否変数に対応するキャラの固有位値成分が存在することです。
例えば、可否変数が111111111111(2)であれば、その十進数上の値は各キャラの固有位値をすべて足し合わせた4095になります。
では本筋に戻り、なぜ固有位値の二倍で可否変数を割った剰余をとれば、カイリューより固有位値が大きいキャラの可否データを除去できるのか。
それはカイリューより固有位値が大きいキャラの固有位値が、すべてカイリューの固有位値の二倍で割り切れるからです。
64,128,256,……、これらは全てカイリューの固有位値の二倍こと64で割り切れます。(固有位値は2のべき乗で定めているので当然っちゃ当然ですが)。
そして反対に、固有位値がカイリュー以下のキャラの固有位値は全員分足し合わせても63です。つまり、カイリュー以下の固有位値のキャラが「つるぎのまい」を覚えようが覚えまいが、この剰余算出の計算において影響を与えることは全くありません。
カイリュー以下のキャラの習得可否に応じてではありますが、剰余計算では0~63の整数のいずれかを得ることができます。
これが可否変数をカイリューの固有位値の二倍で割った剰余を算出する理由です。
(3)で得られた剰余をカイリューの固有位値で割る理由
さて、先ほど算出した剰余ですが、これはカイリューが「つるぎのまい」を覚えるかどうかによってその値の分布が完全に二分されます。
では、ここで一つ質問です。
カイリューより固有位値が小さいキャラの固有位値をすべて足し合わせるといくらになるでしょうか?
その答えは31です。
そうです、この31という数値を見ればわかるように先ほど0から63に分布すると述べた剰余の値は、カイリューの固有位値が32ですから、カイリューが「つるぎのまい」を覚えるなら32~63に、覚えないなら0~31に分布しているはずなのです。
さて、ここまで説明すればなぜ剰余をカイリューの固有位値で割った商をとるかはもうお分かりでしょう。
得られた剰余は0~63、つまりカイリューの固有位値32で割った時の商は0もしくは1しかありえず、さらにカイリューの「つるぎのまい」の習得可否に応じて分布範囲が32で二分されるため、カイリュー以下の固有位値のキャラの習得可否に関わらず、カイリューが覚えるなら1が、覚えないなら0が答えとして出てくるからなのです。
概念図の修正
ここまで解説してきたとおり、可否変数から選択キャラが技を習得するかどうかを抽出するために、新たに固有位値の概念を導入することにしました。
そうすると一度ここまで想定してきた概念図に修正を加える必要があります。といっても、それほど大きなものではありません。入力変数を固有番号から固有位値へと変更するだけのものです。
先ほど、私が提示した概念図は上のようなものです。この図では入力としてキャラ固有番号と技固有番号を利用していますね。
修正はキャラ固有番号をキャラ固有位値に変えるだけですから、変更後の概念図は下のようになります。
まとめ
今回の記事は先の二つに比べてもかなり長くなってしまったので、簡単にまとめます。
- 二進数データを使って行うのは選択したキャラが選択した技を習得可能か判断する処理。
- 可否変数はキャラ固有番号から直接習得可否データを取りだすことが困難なので、固有位値を利用して値を抽出する。
- 可否変数は技を覚えたいキャラの固有位値の二倍で割った剰余で高位桁を除去し、さらに固有位値で割った商をとることで習得可否データを取り出すことができる
以上、本記事で解説した主要な事項です。
結びに
さて、大変長い説明になってしまいましたが、ここまでお読みいただいた読者の皆様、厚く感謝申し上げます。
次の記事では今回の記事で説明した理論を踏まえ、システム全体の構成を実際のイベントを持ちいて解説していきたいと思います。
どうぞ、次回の記事もよろしくお願い申し上げます。