この記事では、ドラクエ1のふっかつのじゅもんの仕組みを完全解説しています。
全て読めばプログラムを組んだりできるように、順を追って丁寧に説明しました。
需要があるかどうかは分かりませんが、参考になればうれしいです。
Python を使ったサンプルプログラムも用意しています。より詳細に知りたい場合は参考にしてもらえればと思います。
サンプルプログラム(Google Colaboratory):ドラクエ1ふっかつのじゅもん
参考サイト(元ネタ)はこちらです。
[ネタ]復活の呪文を解析してみたよ
じゅもんを解析した日記や、C言語やTypeScriptでのソースコードを公開されています。
▼YouTube動画できました!じっくり学習したい人はどうぞ!
ドラクエ1に存在するステータス
ドラクエ1は普通にプレイすると10~20時間くらいかかる、そこそこやりごたえのあるゲームですが、使用できるデータ量は64KBと非常に少なかったです。なので、レベルは経験値から計算する、HPはレベルから計算する…などといったように、保存しておくべきステータスをなるべく削減するという工夫がなされていました。
よって、主人公の状態を決めるステータスも数が絞られ、下の項目に示す分しかありません。
- 名前(6bit×4文字)
- 経験値(16bit)
- 所持金(16bit)
- ぶき(3bit)
- よろい(3bit)
- たて(2bit)
- アイテム(4bit×8)
- やくそうの数(4bit)
- かぎの数(4bit)
- りゅうのうろこを装備したか(1bit)
- せんしのゆびわを装備したか(1bit)
- しのくびかざりを装備したか(1bit)
- ドラゴンを倒したか(1bit)
- ゴーレムを倒したか(1bit)
- パターン(3bit)
bitというのは二進数に直したとき何桁になるか、ということです。例えばやくそうの数なら0~6個のどれかですが、6は二進数で110なので、000~110でやくそうの数は表現できます。つまり、3ケタぶんの二進数があれば足りるということです。なので3bitになっています。
合計すると全部で112bitあり、ここから8bitのチェックコードというのを計算するので、全データをずらーっと並べると120bitになります。つまり120個の1または0が並んでいるというイメージです。これがふっかつのじゅもんで表されている全情報になります。
それぞれの項目を一つずつ確認します。
名前
ゲームスタート時に入力する名前です。最大でひらがな4文字で、一文字当たり6bitなので計6×4=24bitの情報量となります。
文字に割り当たっている番号は次のようになっています。
3文字以下の場合は「空白」用の二進数(111111)が挿入されます。上の図で言うと「空白」は63番に当たります。例えば「ろと 」は二文字分のデータではなく、空白も一文字6bit分の扱いなので、結局、四文字分のデータ量24bitとなります。
また、0~9番には「0」から「9」の文字が割り当たっています。本来は名前に数字を使うことはできないはずですが、ふっかつのじゅもんを調整することで、数字をつけることもできちゃいます。(例えば、「ふるいけやかわずとびこむみずのおとばしや」では、「4ひえた」という名前になります。)
経験値
ステータスのEに書かれている値(EXP)です。0~65535の値を取り、二進数では16桁で表せます。
レベルは経験値から計算されます。
所持金
いわゆるゴールドで、ステータスのGに書かれている値です。
0~65535の値を取り、16bitです。
ぶき
装備している武器です。0~7の8種類あります。
- なし
- たけざお
- こんぼう
- どうのつるぎ
- てつのおの
- はがねのつるぎ
- ほのおのつるぎ
- ロトのつるぎ
それぞれの番号を2進数になおした値が3bitであらわされます。例えば、てつのおのは4番なので100です。
よろい
装備しているよろいです。ぶきと同様、0~7の8種類あります。
- なし
- ぬののふく
- かわのふく
- くさりかたびら
- てつのよろい
- はがねのよろい
- まほうのよろい
- ロトのよろい
たて
たてです。こちらは、0~3の4種類しかありません。
- なし
- かわのたて
- てつのたて
- みかがみのたて
なんで「たて」の最強装備だけ「ロトのたて」じゃなくて「みかがみのたて」なんでしょうね。
アイテム
アイテムは全14種類あり、8つ持つことができます。
なので、4bit分のデータが8種類あり、合計32bitであらわせます。
アイテムの種類は次の通り。
- なし
- たいまつ
- せいすい
- キメラのつばさ
- りゅうのうろこ
- ようせいのふえ
- せんしのゆびわ
- ロトのしるし
- おうじょのあい
- のろいのベルト
- ぎんのたてごと
- しのくびかざり
- たいようのいし
- あまぐものつえ
- にじのしずく
重要アイテムが多いので、普段使いするアイテムはそんなに種類がない印象です。
「のろいのベルト」と「しのくびかざり」は、どちらも装備する(つかう)と呪いがかかってラダトーム城に入れなくなります。
やくそうの数
やくそうはアイテムと別枠で所持できます。0~6個まで持てるので、3bitの2進数であらわせますが、先頭に0をつけて4bitで表します。
かぎの数
かぎもやくそうと同じく、アイテムと別枠になっています。0~6個まで持て、その数を4bitで表します。
各種フラグ
イベントをクリアしたかどうかを表すフラグが5つ存在します。
- りゅうのうろこを装備したか(1bit)
- せんしのゆびわを装備したか(1bit)
- しのくびかざりを装備したか(1bit)
- ドラゴンを倒したか(1bit)
- ゴーレムを倒したか(1bit)
上の3つは、装備したことがあれば1、装備したことがなければ0。
下の2つは、倒していれば1、倒していなければ0。
であらわされます。
装備がなぜフラグ扱いなのかというと、例えばりゅうのうろこは一度でも装備すれば、永久的に守備力が2ポイント上昇するという仕様だからです。一度装備すると外せませんし、2個以上使っても意味はありません。よって「装備したか」「装備してないか」の2択しかないので、フラグで管理されています。
詳しい説明などはドラゴンクエスト大辞典などを参照。
パターン
通常プレイでは気にすることはないと思いますが、パターンという項目もあります。
実は、同じステータスでも、8パターンの異なるふっかつのじゅもんを聞くことができます。
それが、このパターンという項目の数字によって決まります。
0~7までの8種類あるので、3bitです。
チェックコード
これが何者なのかはあとで示します。とりあえず8bitです。
最初は暫定的にすべて0としておきます。(00000000)
ドラクエ1ふっかつのじゅもんの仕組み
上の節で、ふっかつのじゅもんに組み込まれているステータスを確認しました。
すべての値はコンピュータ上で2進数として保存されていますので、これからは各項目が2進数であらわされていると思ってください。
ここからふっかつのじゅもんができるまでのザックリした流れを示します。非常に複雑です。
- Step1ふっかつのじゅもんのベースをつくる
000000000011110100010001…01101000(120bit)
- Step2チェックコードを計算
ふっかつのじゅもんのベースから、チェックコード(8bit)を計算
- Step3チェックコードを置き換える
先頭8bitを、計算したチェックコードに置き換えます。
111011110011110100010001…01101000(120bit) - Step4並べ替える
順番を並び替える
- Step54と一つ前のコードを足す
じゅもんを複雑にします。
- Step6ひらがなになおして完成
対応表で2進数からひらがなに変換し、完成!
何言ってるかわからないと思いますので、それぞれをもう少し詳しく見てみましょう。
Step1 ふっかつのじゅもんのベースをつくる
「経験値」「ゴールド」「アイテム」などの情報すべてを一列に並べます。全部で120bitの長い2進数となるはずです。
〈イメージ〉
000000000011110100010001…01101000
これを、ここでは「ふっかつのじゅもんのベース」と呼びます。
並べ方は次の通り。下に書かれているものをすべて2進数になおして、上から下まで並べると、120bitの2進数になるはずです。
分かりやすいように、8bitごとに区切って書いていきます。つまり、一行が8bit分に対応します。
後ろの()の中にbit数を記載しています。
チェックコード(8bit)
経験値の後ろ半分(8bit)
パターンの3bit目 + しのくびかざり装備した? + 名前の3文字目(1bit + 1bit + 6bit)
4つ目のアイテム + 3つ目のアイテム(4bit + 4bit)
ゴールドの後ろ半分(8bit)
名前の1文字目 + ゴーレム倒した? + パターンの2bit目(6bit + 1bit + 1bit)
8つ目のアイテム + 7つ目のアイテム(4bit + 4bit)
パターンの1bit目 + ドラゴン倒した? + 名前の4文字目(1bit + 1bit + 6bit)
ぶき + よろい + たて(3bit + 3bit + 2bit)
ゴールドの前半分(8bit)
かぎの数 + やくそうの数(4bit + 4bit)
6つ目のアイテム + 5つ目のアイテム(4bit + 4bit)
経験値の前半分(8bit)
りゅうのうろこ装備した? + 名前の2文字目 + せんしのゆびわ装備した?(1bit + 6bit + 1bit)
2つ目のアイテム + 1つ目のアイテム(4bit + 4bit)
つまり、さっきの〈イメージ〉の2進数を使えば、(8bitごとにスペースを入れました)
00000000 00111101 00010001 00001101 … 01101000
となり、
最初の「00000000」はチェックコード
次の8bit「00111101」は経験値の後ろ半分
その次の8bit「00010001」は、0がパターンの3bit目、0がしのくびかざりを装備したかのフラグ、001101が名前の3文字目
などのように対応しています。分かりにくくてすみません。
(パターンの3bit目というのは、もしパターンが001だった場合、左から数えて3番目の1のことです)
ちなみに、チェックコードは次のステップで計算するので、今の段階では 00000000 とします。
でき上がった2進数は。「チェックコード、経験値、パターン、しのくびかざり…」というように、ぐちゃぐちゃに並んでいます。このように並び替えることで、解読されにくいじゅもんを作ることができるんですね。しかし、アイテムは必ず2連続で配置されてるなど、若干の規則性も見られます。
Step2 チェックコードを計算
Step1でつくった120bitの2進数「ふっかつのじゅもんのベース」を使って、「チェックコード」というものを計算します。
チェックコードというのは、じゅもんが有効かどうかを確認するための数字です。120bitすべてを使って計算されるので、例えばやくそうの数が1個→2個になったりするだけで、チェックコードは全然違う数字になります。なので、ほとんどステータスが同じであっても、全く異なるじゅもんが生成されるのです。
厳密に言うと、ここで計算されるチェックコードは CRC-16-CCITT、生成多項式は 0x1021 らしいです。これはどういうものかというと、ふっかつのじゅもんのベース
000000000011110100010001…01101000
を生成多項式「0x1021(2進数でいうと、0001 0000 0010 0001)」でわり算し、その余りをチェックコードとする計算方式です。
実際のプログラミングするときは、下のように組むみたいです。
参考サイトのほうを引用すると、
//yoshi389111(2022)「[ネタ]復活の呪文を解析してみたよ」,<https://qiita.com/yoshi389111/items/29ade2f62483e9c095d9>(参照2022-10-11) より引用。
int cd = 0x8000;
for (int i = 0; i < 15 * 8; i++) {
if (cd & 0x8000) {
cd = (cd << 1) ^ 0x1021;
} else {
cd <<= 1;
}
printf("0x%.2x\n", cd & 0xff);
}
と書くことで、チェックコードを計算できるようです。最終的にcdに代入される値の下8ケタがチェックコードになります。
ちなみに、<<という記号は「シフト演算子」(2進数を左や右に一つずらす)、^は「XOR演算」を表す記号です。
Step3 チェックコードを置き換える
ふっかつのじゅもんのベース
000000000011110100010001…01101000
の先頭8bitを、Step2で計算したチェックコードに置き換えます。
チェックコードが11101111になった場合は、
111011110011110100010001…01101000
とします。
Step4 並び替える
ふっかつのじゅもんの2進数を並び替えます。
まず、120bitを、24bitずつ区切って、5つのかたまりを作ります。
111011110011110100010001…01101000(120bit)
↓
24bit
24bit
24bit
24bit
24bit
5つに分けたかたまりのそれぞれの内部で、数字の並べ替えを行います。
左の24bitのかたまりについてみていきます。
111011110011110100010001(24bit)
24bitを、さらに8bitずつ、三つのかたまりに分け、
11101111 00111101 00010001
左と右を入れ替えます。
00010001 00111101 11101111
一旦くっつけた後、今度は6bitずつ分けて、
000100 010011 110111 101111
後ろのものから順に並べます。
101111 110111 010011 000100
これで一つ目のかたまりは入れ替え完了です。
あとは、残りの4つのかたまりについても同じ操作を行います。
101111 110111 010011 000100 … 011010(120bit)
Step5 4と一つ前のコードを足す
Step4で並べ替えた120bitの2進数が並び替えられて、最終的に6bit×20の2進数になったはずです。
101111 110111 010011 000100 … 011010(120bit)
分かれた6bitが、最終的なじゅもんのひらがな一文字分に対応します。
20個に区切れたので、ひらがな20文字分ということですが、これはふっかつのじゅもんが20文字であることとつながります。
では、その6bitをそれぞれひらがなに変換したら終わりか…?というと、そうでもありません。最後に「4と一つ前のコードを足す」ということをします。と言われても、何のことかさっぱりだと思います。なかなか言葉で説明するのが難しいんですよね。なので、例をみて理解してください。
まず、一番左の6bit(つまり、じゅもんのひらがな一文字目に対応)に 000100(4)を足します。今回の場合でいえば、一文字目に対応する6bitは 101111 なので、
(一文字目) = 101111 + 000100 = 110011
が、最終的なじゅもんのひらがな一文字目に変換されます。さらに、ここで計算された 110011 を覚えておきます。
次の6bit(7bit目から12bit目)は 110111 です。これはじゅもんのひらがな二文字目に対応しますが、これには000100と、一文字目の2進数を足します。つまり、
(二文字目) = 110111 + 000100 + 110011 = 101110(7ケタ目は無視)
が、じゅもんの二文字目に変換されます。
同じように三文字目は、また次のとなりの6bitに000100と二文字目の2進数を足して、010011 + 000100 + 101110 を計算します。
このように、6bitをとって、「000100」と「一つ前の文字の2進数」を足す、という操作を繰り返します。
四文字目以降の2進数についても、まったく同じように操作をくり返します。
Step6 ひらがなになおして完成
Step5までで、6bitの2進数(110011など)が20個できたはずです。これらの6bitひとつひとつを、下の対応表を使ってひらがなになおします。
例えば、一文字目はStep5で計算した値をみると 110011 でした。上の対応表は10進数で番号が示されていますので、110011 を10進数になおすと「51」です。つまり、51番の「ず」がじゅもんの一文字目だということです。
この調子で、すべての2進数をひらがなになおしたら、晴れてじゅもんの完成です!
ちなみに、この2進数⇔ひらがなの対応表は、名前の方ででてきた対応表と異なるものになっています。
名前の場合は、「0、1」などの数字や「っ、ゃ、ゅ、ょ」などが使える一方、「が」「ば」などの濁点付きのひらがなは使用できませんでした。逆に、ふっかつのじゅもんでは数字などが使えない代わりに、濁点付きのひらがなが使われています。なので、名前のときは「あ」は10番だったのに、じゅもんのときは「あ」は0番に対応する、などのズレが生じています。
おわりに
以上が、ふっかつのじゅもんの仕組みです。
実装するなど、より深い仕組みまで知りたい場合は、冒頭でも示したPythonのサンプルプログラムや、元ネタのサイトなども確認してみてください。
コメント