LoginSignup
31
29

More than 5 years have passed since last update.

ガチャのサンプルコード

Last updated at Posted at 2014-12-27

ガチャが世に出てきてかなり経つけど、ソースコードって出回ってないような気がするので、書いてみた。
配列からランダムに1件取得するメソッド(Utility.php)はガチャのロジックを比較してみたを参照。

単純にリストからランダムで引かせるだけじゃなくて「Xグレードの確率 X倍アップ!」とか言いやすいように、最初にグレードを決めてから対象のガチャを引くようにしています。
あとModelは記載していませんので、自前の環境に合わせて補完してください。

ソース

ガチャ本体

Gacha.php
require_once 'Utility.php';
class Gacha
{
    /**
     * ガチャをひく
     * @param int ガチャID
     * @param int 引く枚数
     * @return array (カードID => 枚数)
     */
    public static function doGacha($gachaId, $number = 1)
    {
        // どのグレードを何回引けばいいか取得
        $gradeList = self::getGachaGrade($gachaId, $number);

        // グレードに対応するガチャを引く
        $result = [];
        foreach ($gradeList as $gradeId => $number) {
            $cardList = self::getCard($gradeId, $number);
            foreach ($cardList as $cardId => $cardNumber) {
                if (isset($result[$cardId])) {
                    $result[$cardId] += $cardNumber;
                } else {
                    $result[$cardId] = $cardNumber;
                }
            }
        }
        return $result;
    }

    /**
     * 当選グレードを決める
     * @param int $gachaId ガチャID
     * @param int $number 引く回数
     * @return array [グレードID => 回数]
     */
    private static function getGachaGrade($gachaId, $number = 1)
    {
        // 指定ガチャIDのグレード一覧を取得
        // 配列で返却される['id' => グレードID, 'rate' => 確率]
        $gradeList = GachaGradeModel::findByGachaId($gachaId);

        // 引くグレードIDと回数を取得
        $result = [];
        for ($i = 0 ; $i < $number ; $i++) {
            // ランダムでグレードを取得
            $grade = Utility::getRandomData($gradeList);
            if (isset($result[$grade['id']])) {
                $result[$grade['id']]++;
            } else {
                $result[$grade['id']] = 1;
            }
        }
        return $result;
    }

    /**
     * ガチャの中身を引く
     * @param int $gradeId ガチャグレードID
     * @param int $number 引く回数
     * @return array [カードID => 枚数]
     */
    private static function getCard($gradeId, $number = 1)
    {
        // ガチャの中身一覧を取得
        // 配列で返却される['card_id' => カードID, 'rate' => 確率]
        $contentsList = GachaContentsModel::findByGradeId($gradeId);

        // 引くカードと枚数を取得
        $result = [];
        for ($i = 0 ; $i < $number ; $i++) {
            // 中身からランダムに1枚取得
            $contents = Utility::getRandomData($contentsList);

            if (isset($result[$contents['card_id']])) {
                $result[$contents['card_id']]++;
            } else {
                $result[$contents['card_id']] = 1;
            }
        }
        return $result;
    }
}

配列からランダムに取得するメソッド

Utility.php
class Utility
{
    /**
     * 配列の中から確率を使いランダムで1件取得する
     * @param array データ配列
     * @param string 確率を表す連想配列名(デフォルトは"rate")
     */
    public static function getRandomData(array $array, $keyName = 'rate')
    {
        // 確率の合計値を求める
        $max = 0;
        foreach ($array as $record) {
            $max += $record[$keyName];
        }

        // 合計値までのランダム値を求める
        $rate = mt_rand(0, $max-1);

        // ランダムの値がどれにあたるか調べる
        foreach ($array as $record) {
            $max -= $record[$keyName];
            if ($max <= $rate) {
                return $record;
            }
        }
        throw new Exception('ここには来ないはず');
    }
}

DB

-- ガチャ本体
CREATE TABLE gacha (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255));
-- ガチャに入っているグレード
CREATE TABLE gacha_grade (
  id INT AUTO_INCREMENT PRIMARY KEY,
  gacha_id INT,
  name VARCHAR(255),
  rate INT);
-- グレードに対する中身
CREATE TABLE gacha_contents (
  id INT AUTO_INCREMENT PRIMARY KEY,
  gacha_grade_id INT,
  card_id INT,
  rate INT);

実行用コード

$result = Gacha::doGacha(1, 10000); // ガチャID:1を10000回引く
ksort($result);
foreach ($result as $cardId => $number) {
    echo 'CardID:' . $cardId . '/' . $number .PHP_EOL;
}
31
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
29