概要
スマホのゲームなどでよく見かける「ガチャ」の仕組みです。
レジェンドキャラなどを低確率にしたかったりする場合に確率を含めています。
利用時はコードで抽出してください。(SQLでも頑張ったら抽出できるかもしれません)
設計詳細
ER図
erDiagram
Gachas ||--o{ GachaItems: "has many"
Gachas {
int id PK
string name
}
GachaItems {
int id PK
int gacha_id
string item_name
int rate
}
SQL
CREATE TABLE gachas (
id bigint unsigned NOT NULL AUTO_INCREMENT,
name varchar(255),
PRIMARY KEY (id)
);
CREATE TABLE gacha_items (
id bigint unsigned NOT NULL AUTO_INCREMENT,
gacha_id bigint unsigned NOT NULL,
item_name varchar(255),
PRIMARY KEY (id)
);
使い方
以下のようなロジック(PHP)で取得します。
GachaItems
のリストを取得- 確率の合計値を求める
- 合計値-1の乱数を取得
- 乱数の示す場所を返す
public function getGachaItems($gachaId)
{
$data = GachaItem::where('gacha_id', $gachaId)->get(); // 1. GachaItemからデータ取得
// 2. 確率の合計値を求める
$max = 0;
foreach ($data as $record) {
$max += $record['rate'];
}
// 3. 合計値-1の乱数を取得
// 0から始まるので合計値から1を引いた数までの乱数を取得
$rate = mt_rand(0, $max-1);
// 4. 乱数の示す場所を返す
foreach ($data as $record) {
$max -= $record['rate'];
if ($max <= $rate) {
return $record['id'];
}
}
throw new Exception('ここには来ないはず!');
}
PHP手順2の合計を求める部分が毎回入るので、この部分が気になる場合は以下の対応が考えられますが、デメリットもあるため、プロジェクトに合った判断をしてください。
- 合計値が100などの固定値になるようにする
- 計算が面倒なので運用コストが上がる
Gachas
にrate_sum
のような合計値カラムを追加- 合計カラムの更新忘れが心配
- SQLで求める
- DB負荷が増える
- 求めた合計値をキャッシュする
- 更新時にキャッシュクリア忘れが心配
コメント