トリプレットビート パック開封シミュレーターを作ってみた

シミュレータ実行結果サンプル
シミュレータ実行サンプル

トリプレットビートでシールド戦が行われるので
やっぱりパック開封シミュレーターを使って開封→構築→対戦の練習がしたいなーと思って作成しました。
note投稿は初なので、読みづらい・分かりづらいなどはご容赦ください。

※トリプレットビート向けで開封シミュレータを作成しましたが、レイジングサーフでも使用するため、トリプレット用はURLを変更しました。

【シミュレーターとして成立させるための条件】

  • シールド戦は1箱を半分だけ使って楽しむ対戦形式

  • 1箱に含まれるカードはある程度規則性があり、完全ランダムではない

  • 確率は公開されていない

  • 複雑な操作は不要

などなど…。
というわけで、ある程度の情報を参考にしつつ、ちゃんとそれっぽい状態で排出されるシステムの構築を目指すことに。


【1箱の仕様について】

プログラムに落とし込むために、条件をもとに基本仕様を検討
※今回必要なレアリティは C, U, R, RR, AR, SR, SAR, UR
※1箱の枚数は1パック5枚×30パックの150枚

  1. C :1箱に90枚封入。主にたねポケモンや1進化のポケモン。

  2. U :1箱に45枚封入。主に進化ポケモンやトレーナーズ。

  3. R :1箱に5,6枚封入(稀に4枚なども?)。

  4. RR :1箱に4,5枚封入。ポケモンex。

  5. AR :1箱に3枚封入(稀に2,4枚なども?)。

  6. SR :1箱に1,2枚封入。

  7. SAR:1箱に0,1枚封入。

  8. UR :1箱に0,1枚封入。

レアリティにより、封入数がある程度決まっているものと誤差が発生するものが存在するので、稀なケースは今回のシミュレーターとしては排除で。

不確定な枠は、検討する上で足枷になるので確定枠から封入を検討していく

【プログラムの準備】

全カードのマスタデータとなるデータを生成。
全カードのNo.、名前、レアリティ、画像パスなど。
用意したマスターデータをもとに各レアリティごとに配列を構成。

【抽選ロジックと抽選順】

  1. SR枠:1枚確定すること前提で1枚を抽選。抽選対象は「SR」「SAR」「UR」の枠から1枚を抽選。

  2. SR枠(2枚箱対応)

    1. 上記1が「SR」だった場合、2枚枠の抽選を実施。ただし、抽選対象は「R」を含めた「SR」「SAR」「UR」で抽選を実施。

      • 2枚箱の場合「R」枠が削られるケースが多いので、抽選対象に「R」を含める(抽選結果が「R」の場合は1枚箱)

    2. 上記1が「SR」以外だった場合、SAR/URの2枚箱は聞かないので「R」から1枚抽選

  3. AR枠:3枚確定すること前提で抽選。念のため抽選結果を更にシャッフル。

  4. R/RR枠:①R6/RR5・②R7/RR4 などのケースが発生している模様なので、まずはどちらを採用するか抽選を実施(少ない集計だが②のほうが確率高そうなので①25% ②75%くらいの条件で抽選)

    1. RR枠:上記結果の枚数で抽選を実施。

    2. R枠:SR2枚箱のケースを考慮し、上記結果-1枚の枚数で抽選を実施。

    3. どちらも抽選結果を更にシャッフル。

  5. U枠

    1. 1枚は確定しているようなのでまずは抽選。

    2. 2,3枚目分としてUの配列を2倍にして配列を構築。その状態でシャッフルを実施。

    3. 45枚から1枚確定している枚数を引き、残りは上記2で抽選シャッフルしたものを上から採用していく。

    4. 確定した45枚を更にシャッフル。

  6. C枠:基本はU枠と同じようなロジックで抽選を実施してシャッフル。

これで基本的な1箱分(5枚×30パック)の抽選完了。これで折り返し。
ここから更に、シールド戦のパック抽選を行うために、全カードをパックに梱包させる必要がある。

【パックへの梱包】

1箱30パックのうちの15パックを使ってシールド戦を行うため、一旦抽選されたカードすべてを梱包したほうが、シミュレーターとしての精度があがると思うので梱包用のプログラムを作成する。

【パック内の仕様】

パック内のレアリティは以下のパターンが存在する。

  • C,C,C,SR以上,U :1,2パック

  • C,C,C,AR,U :3パック

  • C,C,C,RR,U :4,5パック

  • C,C,C,R,U :6,7パック

  • C,C,C,U,U :15パック

基本的にこの5パターン。SR2枚箱の場合はさらに、箱の右側左側にそれぞれSR以上が分散されることが多いので、それも考慮する必要がある。

各レアリティごとに抽選された配列を、パック内レアリティパターンの配列に対して1枚ずつ設定していく。
SR以上2枚箱の場合、このタイミングでどちらか1パックだけを抽選しておく。そして、それ以外の28パックをシャッフル。最後にパックの先頭にSR以上が含まれるパックを挿入する(パックの位置は今回関係ないので先頭にする)。
SR以上1枚箱の場合、SR以上パックを含んだ30パックすべてをシャッフルする。

これでパックへの梱包がすべて完了!
あとは用意されたパックの配列を、上から15パック分展開し、排出結果として画面に表示できれば完了となります。


【プログラム内で利用している関数など】

ちなみに今回はPHP7.2の環境で実行しています。理由は特にないです。

array, if, foreach, for, count, isset:基本ですね。forは厳密に枚数分回すとき、foreachは配列を回すときなどで使い分け
unset:要らなくなった大きめの配列変数のクリア、未排出カードのリスト出力で使用
in_array:SR以上の抽選時、SRだったら2枚箱用抽選をするために使用
array_merge:SR以上のレアリティをまとめるとき、U,Cを複数枚抽選するときなどに使用
array_shift:パック梱包するために、レアリティごとの配列から1枚ずつ取り出して設定するために使用
array_unshift:SR以上パックを配列の頭に設定するときに使用
shuffle:配列状態で抽選をする際に使用(PHP7.1からメルセンヌツイスタ乱数生成器によるランダム化されているため抽選として使うには十分と判断)
mt_rand:レアリティ内のカード抽選などで使用
array_sum:重み付けした抽選で使用(R/RR枠抽選など)
ksort:画面に出力する際、カードNo.順で表示させるために使用

今回は画面に表示したら終わりのシステムなので、JavaScriptによる制御系はほぼ無し。未排出カードのリストを表示させる部分のみ。
HTMLは普通にdivやimgタグのような基本的なもののみ。
画像が多いため、imgタグに loading="lazy" を付与して多少なりとも負荷を軽減。
CSS系は見やすくするためだけくらいで凝ったものはなし。

以上です!
本当は同じ「C」の枠でも進化前後で、進化後が進化前のカードより多くはならない~などの制御も必要みたいですが、それは15パックの運がなかったということでご愛嬌…。

とってもざっくりですが、はじめの抽選周りと梱包あたりの実装イメージが付けばサクッと作れる?はず?
設計から一旦それっぽく動くものができるまで4時間掛からずといったところでしょうか。
連絡先とか一切載せていないですが、興味があればTwitterなどで探してみてください。
気が向いたら連絡先書いておきます。


作るのにたった4時間ではあるけれど、どうせならお小遣い稼ぎくらいはしたいので、シミュレーターに広告とかアフィリエイトとかシレッと追加するかもです。
今回は開封シミュレーターについて書きましたが、他にも一人回し用のプレイシミュレータとかも作っていたりするので、そちらもご興味あれば。
ちゃんとしたチュートリアルは作っていないのでとってもわかりにくいとは思いますが、気が向いたら更新していきます。


この記事が気に入ったらサポートをしてみませんか?