「ガチャ」のDB設計 – グレード確率

データベース設計 設計例

本記事はDB設計の提案を記載します。
この設計はあくまで一例です。
これを雛形として、ご自分の構築したいシステムに合わせてご利用ください。

概要

スマホのゲームなどでよく見かける「ガチャ」の仕組みです。
ガチャの中身をグレード毎に分けて登録し、グレードのみに確率があるものです。
恐らく一番実用的なのではないでしょうか。

例えばグレードと確率がレジェンド3%、レア17%、コモン80%のような確率にしたい。
そして、それぞれのグレードには複数種類のアイテムがあり、グレード内は同一確率で良い。
といった具合です。

設計詳細

ガチャ、グレード、中身の3テーブルがあります。
グレードに確率があり、中身は等しい確率で出るので確率は存在しないイメージです。
同じレア度でも新旧のアイテムなどで確率を変更したい場合は、新アイテムと旧アイテムのグレードで分けるといった使い方になります。

ER図

erDiagram Gachas ||--o{ GachaGrades: "has many" GachaGrades ||--o{ GachaItems : "has many" Items ||--o{ GachaItems : "has many" Gachas { int id PK string name } GachaGrades { int id PK int gacha_id FK string name int rate } GachaItems { int id PK int gacha_grade_id FK int item_id FK } Items { int id PK string name }

使い方

PHPのLaravelでの取得例を記載してみます。

1. グレードの決定

まずガチャのグレードを決めます。
グレードIDを取得します。

public function getGrade($gachaId)
{
    $grades = GachaGrade::where('gacha_id', $gachaId)->get(); // GachaGradesからデータ取得
    
    // 確率の合計値を求める
    $max = 0;
    foreach ($grades as $record) {
        $max += $record['rate'];
    }
    // $gradesが配列の場合は以下でもOK
    // $max = array_sum(array_column('rate'));
    
    // 0から始まるので合計値から1を引いた数までの乱数を取得
    $rate = mt_rand(0, $max-1);
    
    // 乱数がどこに当たるか調べていく
    foreach ($data as $record) {
        $max -= $record['rate'];
        if ($max <= $rate) {
            return $record['id'];
        }
    }
    throw new Exception('ここには来ないはず!');
}

2. 指定したグレードのアイテムを取得

次に、決定したガチャグレードのアイテムからランダムで取得します。

public function getItem($gradeId)
{
    // 指定グレードのアイテムを全て取得
    return GachaItem::where('gacha_grade_id', $gradeId)
      ->inRandomOrder() // ORDER BY RANDOM()
      ->first(); // LIMIT 1
}

ランダムで取得の方法は色々あるので、DB・Webサーバーなどどこに負荷をかけるかを考えながら実装してみてください。

コメント

タイトルとURLをコピーしました