#内容
ガチャのデータ設計を考えてみます。
##ガチャに必要なデータ要素
ここまでガチャのデータとして、IDと重みの値のみで実践してきましたが、
# 抽選対象のアイテムIDと重みのdictionary
item_dic = {"id_1":1,"id_2":5,"id_3":14,"id_4":30,"id_5":50}
実際にガチャを作る場合に必要な要素を列挙してみます。
- ID
- 重み(weight)
- レア度(rarity)
- アイテム名(item_name)
表にすると以下のようになります
gacha_items
id | weight | rarity | item_name |
---|---|---|---|
1 | 1 | 5 | UR_HOGE |
2 | 1 | 5 | UR_FUGA |
3 | 9 | 4 | SSR_HOGE |
4 | 9 | 4 | SSR_FUGA |
5 | 20 | 3 | SR_HOGE |
6 | 20 | 3 | SR_FUGA |
7 | 30 | 2 | R_HOGE |
8 | 30 | 2 | R_FUGA |
9 | 40 | 1 | N_HOGE |
10 | 40 | 1 | N_FUGA |
- weightは小さい方が、当選確率が低い
- rarityは高いほうが、希少度が高い意味付け
レア度と、その名称の対応表は以下のようになります。
ratiry_names
id | rarity_name |
---|---|
5 | UR |
4 | SSR |
3 | SR |
2 | R |
1 | N |
gacha_items = {
1: {"weight":1, "rarity":5, "item_name":"UR_HOGE"},
2: {"weight":1, "rarity":5, "item_name":"UR_FUGA"},
3: {"weight":9, "rarity":4, "item_name":"SSR_HOGE"},
4: {"weight":9, "rarity":4, "item_name":"SSR_FUGA"},
5: {"weight":20,"rarity":3, "item_name":"SR_HOGE"},
6: {"weight":20,"rarity":3, "item_name":"SR_FUGA"},
7: {"weight":30,"rarity":2, "item_name":"R_HOGE"},
8: {"weight":30,"rarity":2, "item_name":"R_FUGA"},
9: {"weight":40,"rarity":1, "item_name":"N_HOGE"},
10:{"weight":40,"rarity":1, "item_name":"N_FUGA"}
}
rarity_names = {5: "UR", 4: "SSR", 3: "SR", 2: "R", 1: "N"}
各々のディクショナリの説明
- gacha_itemsは、idをキーとして、重みなどの情報を保持
- rarity_namesは、レア度(id)に対応したレア名を保持
おまけのレアリティを指定したガチャ
おまけについて、レアリティ以上の指定ができるガチャを作成してみます。
(@shiracamusさんのソースを流用します)
gacha.py
import random
def gacha(gacha_items: dict, times: int=1) -> list:
# 抽選に必要な、IDと重みの辞書を作成
lots = {key: info["weight"] for key, info in gacha_items.items()}
return random.choices(tuple(lots), weights=lots.values(), k=times)
def gacha_omake(gacha_items: dict, times: int, omake_rarity: int) -> list:
# おまけの対象をレアリティ制限で辞書を作成
omake = {key: info for key, info in gacha_items.items() if info["rarity"] >= omake_rarity}
ids = gacha(gacha_items, times)
omake and ids.extend(gacha(omake))
return ids
def main():
# ガチャアイテム情報
gacha_items = {
1: {"weight": 1, "rarity": 5, "item_name": "UR_HOGE"},
2: {"weight": 1, "rarity": 5, "item_name": "UR_FUGA"},
3: {"weight": 9, "rarity": 4, "item_name": "SSR_HOGE"},
4: {"weight": 9, "rarity": 4, "item_name": "SSR_FUGA"},
5: {"weight": 20, "rarity": 3, "item_name": "SR_HOGE"},
6: {"weight": 20, "rarity": 3, "item_name": "SR_FUGA"},
7: {"weight": 30, "rarity": 2, "item_name": "R_HOGE"},
8: {"weight": 30, "rarity": 2, "item_name": "R_FUGA"},
9: {"weight": 40, "rarity": 1, "item_name": "N_HOGE"},
10: {"weight": 40, "rarity": 1, "item_name": "N_FUGA"}
}
# レアリティ名
rarity_names = {5: "UR", 4: "SSR", 3: "SR", 2: "R", 1: "N"}
# 抽選回数
times = 10
# おまけレアリティ(以上)
omake_rarity = 3
# 抽選してidのリストを取得
ids = gacha_omake(gacha_items, times, omake_rarity)
# 結果出力
for id in ids:
print("ID:%d, %s, %s" % (id, rarity_names[gacha_items[id]["rarity"]], gacha_items[id]["item_name"]))
if __name__ == '__main__':
main()
実行結果
ID:8, R, R_FUGA
ID:7, R, R_HOGE
ID:5, SR, SR_HOGE
ID:5, SR, SR_HOGE
ID:5, SR, SR_HOGE
ID:3, SSR, SSR_HOGE
ID:5, SR, SR_HOGE
ID:10, N, N_FUGA
ID:5, SR, SR_HOGE
ID:9, N, N_HOGE
ID:5, SR, SR_HOGE
考察
前回との違いを考察してみます。
(pythonで書くガチャ-おまけ付きレアリティ確定-)
- 結果表示用に情報が付加されている
- おまけ対象をレアリティ値にて制御している
ガチャに必要最低限な情報は、IDと確率(重み)ですが、
その他に、これらの情報を付加したことにより、実際のガチャに近い挙動と結果を得ることが出来ました。
重要な事は処理を実現するために**データの定義(データ設計)**を行い、それに応じたロジックを記述しているということです。
ガチャそのものはシンプルなロジックです。
しかし、実サービスにおいてはガチャ運用に対応できるデータ設計が必要となり、データ設計が全てと言っても過言ではありません。
(実際にはこれらのデータをDBに格納して運用することになります)