[SQL Server] ガチャ(GACHA)システムを作ろう!

inno
2016-08-18 18:01 1177 0
今回のガチャシステムは100個アイテムを入れて置いてその中で1等は1つ!
この100個のアイテムが全部消費されたらリセットされる仕組みになっています。

一般的なガチャシステムは1%(1/100)の確率で1等が出るようにしても運が良ければ連続で1等に当たる可能性がありますが、
今回は100個の内1等が出た場合、残りのアイテムが全部消費されない限り1等がでません。
実際に作ってみた方が理解しやすいと思いますので、下記のとおりテーブルから作って確認してみましょう。

各アイテムの配分を設定値を保存するdbo.tGachaItem テーブルを作成及びテストデータを登録しましょう。
今回は分かりやすく1等を1%(1/100)確率で当たるように設定したいと思います。

CREATE TABLE dbo.tGachaItem
(
ItemID varchar(50)
,ItemName nvarchar(50)
,ItemRate float
)

INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('Item1', '1等', 1)
INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('Item2', '2等', 4)
INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('Item3', '3等', 10)
INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('Item4', '4等', 15)
INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('Item5', '5等', 20)
INSERT INTO dbo.tGachaItem (ItemID, ItemName, ItemRate) VALUES ('-', 'はずれ', 50)

次はガチャテーブルを作りましょう。
このテーブルには「dbo.tGachaItem」テーブルに設定した配分を元に作成したガチャデータが保存されます。

CREATE TABLE dbo.tGacha(
[Idx] [int] PRIMARY KEY NOT NULL,
[ItemID] [varchar] (50) NOT NULL,
[IsUse] [bit] NOT NULL,
[RegDate] [datetime] NOT NULL,
[UseDate] [datetime] NULL
) ON [PRIMARY]


ALTER TABLE dbo.tGacha ADD  CONSTRAINT [DF_tGacha_RegDate]  DEFAULT (GETDATE()) FOR [RegDate]

ALTER TABLE dbo.tGacha ADD  CONSTRAINT [DF_tGacha_IsUse]  DEFAULT (0) FOR [IsUse]

「dbo.tGachaItem」テーブルに設定した配分を元に「dbo.tGacha」に下記のSQLを利用してガチャデータを登録しましょう。

DECLARE @MaxItemRate int
SELECT @MaxItemRate = MAX(ItemRate) FROM dbo.tGachaItem

CREATE TABLE #TempNum
(
Idx int
)

DECLARE @i int
SET @i = 1

WHILE (@i <= @MaxItemRate)
BEGIN
INSERT INTO #TempNum (Idx) VALUES(@i)
SET @i = @i + 1
END


-- #### 既存データ削除
TRUNCATE TABLE dbo.tGacha

-- #### [dbo.tComDayを利用する場合] 設定した配分でガチャを作る。
INSERT INTO dbo.tGacha (Idx, ItemID)
SELECT ROW_NUMBER() OVER (ORDER BY A.ItemRate, A.ItemID)
, ItemID
From dbo.tGachaItem A
, #TempNum B
WHERE A.ItemRate  >= B.Idx


DROP TABLE #TempNum

これでガチャの準備が完了しました。
ユーザーがガチャを回した時にランダムでアイテムを選択し結果を知らせるSQLは下記のとおりです。
一括で実行してみてください。

DECLARE @Idx int
DECLARE @ItemID varchar(50)
DECLARE @ItemName nvarchar(50)

SELECT @Idx = A.Idx
, @ItemID = A.ItemID
, @ItemName = B.ItemName
FROM
(
SELECT TOP 1 Idx, ItemID
FROM dbo.tGacha WITH (NOLOCK) 
WHERE IsUse = 0 
ORDER BY NEWID()
) A JOIN dbo.tGachaItem B WITH (NOLOCK)
ON A.ItemID = B.ItemID


-- #### 有効なデータがない場合、初期化して再度発行する。
IF @Idx IS NULL
BEGIN

-- #### データを初期化
UPDATE dbo.tGacha SET IsUse = 0, UseDate = null
SELECT @Idx = A.Idx
, @ItemID = A.ItemID
, @ItemName = B.ItemName
FROM
(
SELECT TOP 1 Idx, ItemID
FROM dbo.tGacha WITH (NOLOCK) 
WHERE IsUse = 0 
ORDER BY NEWID()
) A JOIN dbo.tGachaItem B WITH (NOLOCK)
ON A.ItemID = B.ItemID

END

-- #### 取得したデータを使用済み(無効化)にする。
UPDATE dbo.tGacha SET IsUse = 1, UseDate = getdate() WHERE Idx = @Idx

-- データ確認
SELECT @Idx, @ItemID, @ItemName

SQLの内容を把握しておいた方がいいと思いますので、
テストしてみながら仕様を把握して置きましょう。
このSQLがガチャシステムの正解のSQLではありませんが、
参考ができればと思います。

コメント