social-game-kit 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 65571e588b48927227617f828d9f137a8266e8d84f2720ae4025efa5b20f97c1
4
- data.tar.gz: 15473e8e6a643022c099bfc04cceb8f3c19486395ea6a3f31b98ae44d301571a
3
+ metadata.gz: 4e79f7963dc2c44320694859eddb15f1db44ce3c29bff1cc1f6ba36436dbeeb0
4
+ data.tar.gz: d0007d4a08edf989d0a9e95e6df4222722adf83ff0b56abecae1118fb9ed2f70
5
5
  SHA512:
6
- metadata.gz: b681aed93bc74186fb42e9a27a745ef720c21522aba4733c7852ff46dcc5649574fbf6ea555da85364beac0795ca372a5d37ac0383eaba6ab10ba6b13c59f3b0
7
- data.tar.gz: 21e9ea9293a84a29eb1ad2dcc7a9757caf1b8d04181c38b3f8d1fe2b8d71e7829f6d9e92c55bc7b4b46b785f6cf013a08da75dc26e8df1957bfa404c0ad79bdf
6
+ metadata.gz: 906cf1ec805dd5f47db11677d21c34b575cf783f64738d4aecabdf2da99b0d5c2cbcef8caecb8d7a6a829d7fee054742ac48ee5c97db5b4736ae1fc7d9a687e3
7
+ data.tar.gz: 829e48ebdb65d71afde7a6609d65173aea83711e404033d22ef0256e5543cefdf71c835dd74dbfe652a3b952b0322e9b04bc1c1fc7a48bed358752dbbd5612bc
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.1.0] - 2025-11-29
4
+
5
+ - Add PitySystem: 100連で天井(確定URが出る)機能
6
+ - Add MultipleDraw: 10連ガチャをシンプルにラップするクラス
7
+
3
8
  ## [0.1.0] - 2025-11-02
4
9
 
5
- - Initial release
10
+ - Initial release: Gacha engine with weighted random selection
data/README.md CHANGED
@@ -35,13 +35,13 @@ bundle install
35
35
  ### 基本的な使用方法
36
36
 
37
37
  ```ruby
38
- require 'sgk'
38
+ require 'ssg'
39
39
 
40
40
  # カードマスタデータ(ActiveRecordモデル)から抽選
41
41
  cards = GachaCard.all
42
42
 
43
43
  # エンジンの初期化
44
- engine = SGK::Gacha::Engine.new(cards)
44
+ engine = SSG::Gacha::Engine.new(cards)
45
45
 
46
46
  # 単発抽選
47
47
  card = engine.draw
@@ -76,7 +76,7 @@ end
76
76
  # app/controllers/gacha_controller.rb
77
77
  class GachaController < ApplicationController
78
78
  def draw
79
- engine = SGK::Gacha::Engine.new(GachaCard.all)
79
+ engine = SSG::Gacha::Engine.new(GachaCard.all)
80
80
  @result = engine.draw
81
81
 
82
82
  # ユーザーにカードを付与する処理など
@@ -87,7 +87,7 @@ class GachaController < ApplicationController
87
87
 
88
88
  def draw_multiple
89
89
  count = params[:count].to_i.clamp(1, 10) # 最大10連
90
- engine = SGK::Gacha::Engine.new(GachaCard.all)
90
+ engine = SSG::Gacha::Engine.new(GachaCard.all)
91
91
  @results = engine.draw_multiple(count)
92
92
 
93
93
  current_user.gacha_cards.push(*@results)
@@ -98,7 +98,7 @@ class GachaController < ApplicationController
98
98
  end
99
99
 
100
100
  def probabilities
101
- engine = SGK::Gacha::Engine.new(GachaCard.all)
101
+ engine = SSG::Gacha::Engine.new(GachaCard.all)
102
102
 
103
103
  render json: engine.probabilities
104
104
  end
@@ -159,14 +159,14 @@ GachaCard.create!([
159
159
 
160
160
  ## APIリファレンス
161
161
 
162
- ### SGK::Gacha::Engine
162
+ ### SSG::Gacha::Engine
163
163
 
164
164
  #### `initialize(card_relation)`
165
165
 
166
166
  ActiveRecord::Relationを受け取ります。
167
167
 
168
168
  ```ruby
169
- engine = SGK::Gacha::Engine.new(GachaCard.all)
169
+ engine = SSG::Gacha::Engine.new(GachaCard.all)
170
170
  ```
171
171
 
172
172
  #### `draw`
@@ -194,7 +194,7 @@ probs = engine.probabilities
194
194
  # => {1=>70.0, 2=>25.0, 3=>4.0, 4=>1.0}
195
195
  ```
196
196
 
197
- ### SGK::Gacha::Result
197
+ ### SSG::Gacha::Result
198
198
 
199
199
  ガチャ結果をラップするクラスです。
200
200
 
@@ -2,11 +2,7 @@
2
2
 
3
3
  module SGK
4
4
  module Gacha
5
- # Gacha engine that implements weighted random card selection.
6
- #
7
- # This engine takes an ActiveRecord relation of cards and provides methods
8
- # to draw cards based on their weights, supporting both single draws and
9
- # multiple draws in one operation.
5
+ # 重み付きガチャエンジン
10
6
  class Engine
11
7
  def initialize(card_relation)
12
8
  @cards = card_relation.to_a
@@ -26,16 +22,14 @@ module SGK
26
22
  end
27
23
 
28
24
  # NOTE: 浮動小数点誤差を考慮して最後のカードを返す実装だが、重み付き抽選の特性上起こる可能性はほとんどない。
29
- # Returns the last card as a fallback for floating-point precision errors,
30
- # though this scenario is highly unlikely given the nature of weighted random selection.
31
25
  @cards.last
32
26
  end
33
27
 
34
- # Draw multiple cards in a single operation (e.g., 10-draw gacha).
28
+ # 単一操作で複数のカードを抽選する(例:10連ガチャ)。
35
29
  #
36
- # @param count [Integer] Number of cards to draw
37
- # @return [Array<Object>] Array of drawn cards
38
- # @raise [ArgumentError] If count is not positive
30
+ # @param count [Integer] 抽選するカードの枚数
31
+ # @return [Array<Object>] 抽選されたカードの配列
32
+ # @raise [ArgumentError] countが正の値でない場合
39
33
  def draw_multiple(count)
40
34
  raise ArgumentError, "Draw count must be positive" unless count.positive?
41
35
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SGK
4
+ module Gacha
5
+ # 10連ガチャ
6
+ #
7
+ # 使用例:
8
+ # engine = SGK::Gacha::Engine.new(GachaCard.all)
9
+ # drawer = SGK::Gacha::MultipleDraw.new(engine, draw_count: 10)
10
+ # results = drawer.execute
11
+ class MultipleDraw
12
+ DEFAULT_DRAW_COUNT = 10
13
+
14
+ attr_reader :engine, :draw_count
15
+
16
+ # 初期化
17
+ #
18
+ # @param engine [SGK::Gacha::Engine] 使用するガチャエンジン
19
+ # @param draw_count [Integer] 抽選するカードの枚数(デフォルト: 10)
20
+ # @raise [ArgumentError] engineが無効、またはdraw_countが正の値でない場合
21
+ def initialize(engine, draw_count: DEFAULT_DRAW_COUNT)
22
+ raise ArgumentError, "Engine must be a SGK::Gacha::Engine instance" unless engine.is_a?(Engine)
23
+ raise ArgumentError, "Draw count must be positive" unless draw_count.positive?
24
+
25
+ @engine = engine
26
+ @draw_count = draw_count
27
+ end
28
+
29
+ # 複数抽選を実行する
30
+ #
31
+ # @return [Array<Object>] 抽選されたカードの配列
32
+ def execute
33
+ @engine.draw_multiple(@draw_count)
34
+ end
35
+
36
+ # executeのエイリアス
37
+ alias draw execute
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SGK
4
+ module Gacha
5
+ # 100回連続でUR(Ultra Rare)カードが出なかった場合、次回の抽選でURカードを保証する
6
+
7
+ # 使用例:
8
+ # engine = SGK::Gacha::Engine.new(GachaCard.all)
9
+ # pity = SGK::Gacha::PitySystem.new(engine, guarantee_limit: 100, guaranteed_rarity: :ultra_rare)
10
+ #
11
+ # result = pity.draw(current_pity_count: user_current_pity)
12
+ class PitySystem
13
+ attr_reader :engine, :guarantee_limit, :guaranteed_rarity
14
+
15
+ # 初期化
16
+ #
17
+ # @param engine [SGK::Gacha::Engine] 抽選に使用するガチャエンジン
18
+ # @param guarantee_limit [Integer] 保証レアが出るまでの抽選回数(デフォルト: 100)
19
+ # @param guaranteed_rarity [Symbol, String] 保証するレアリティ(デフォルト: :ultra_rare)
20
+ # @raise [ArgumentError] guarantee_limitが正の値でない場合
21
+ def initialize(engine, guarantee_limit: 100, guaranteed_rarity: :ultra_rare)
22
+ raise ArgumentError, "Engine must be a SGK::Gacha::Engine instance" unless engine.is_a?(Engine)
23
+ raise ArgumentError, "Guarantee limit must be positive" unless guarantee_limit.positive?
24
+
25
+ @engine = engine
26
+ @guarantee_limit = guarantee_limit
27
+ @guaranteed_rarity = guaranteed_rarity.to_sym
28
+ end
29
+
30
+ # カード抽選
31
+ #
32
+ # @param current_pity_count [Integer] 最後の保証カードからの抽選回数
33
+ # @return [Object] 抽選されたカード(pity_count >= guarantee_limitの場合は保証UR)
34
+ # @raise [ArgumentError] current_pity_countが負の値の場合
35
+ def draw(current_pity_count: 0)
36
+ raise ArgumentError, "Pity count must be non-negative" unless current_pity_count >= 0
37
+
38
+ # 保証カードを返す
39
+ if current_pity_count >= @guarantee_limit
40
+ return draw_guaranteed_card
41
+ end
42
+
43
+ # それ以外の場合は通常の抽選を実行
44
+ @engine.draw
45
+ end
46
+
47
+ # 複数のカードを抽選する
48
+ #
49
+ # @param count [Integer] 抽選するカードの枚数
50
+ # @param current_pity_count [Integer] 最後の保証カードからの抽選回数
51
+ # @return [Array<Object>] 保証カードの抽選カードの配列
52
+ # @raise [ArgumentError] countが正の値でない、またはpity_countが負の値の場合
53
+ def draw_multiple(count, current_pity_count: 0)
54
+ raise ArgumentError, "Draw count must be positive" unless count.positive?
55
+ raise ArgumentError, "Pity count must be non-negative" unless current_pity_count >= 0
56
+
57
+ results = []
58
+ current_count = current_pity_count
59
+
60
+ count.times do
61
+ card = draw(current_pity_count: current_count)
62
+ results << card
63
+
64
+ # 保証カードを引いた場合は抽選回数をリセット、それ以外はカウントを増やしていく
65
+ if is_guaranteed_card?(card)
66
+ current_count = 0
67
+ else
68
+ current_count += 1
69
+ end
70
+ end
71
+
72
+ results
73
+ end
74
+
75
+ # 次の保証までの残り回数と保証回数を取得する
76
+ #
77
+ # @param current_pity_count [Integer] 最後の保証カードからの抽選回数
78
+ # @return [Hash] 次の保証までの残り回数と保証回数
79
+ # @example
80
+ # pity.next_guarantee_info(current_pity_count: 75)
81
+ # # => { pity_count: 75, remaining: 25, guaranteed_at: 100 }
82
+ def next_guarantee_info(current_pity_count: 0)
83
+ raise ArgumentError, "Pity count must be non-negative" unless current_pity_count >= 0
84
+
85
+ {
86
+ current_pity_count: current_pity_count,
87
+ remaining: [@guarantee_limit - current_pity_count, 0].max,
88
+ guaranteed_at: @guarantee_limit
89
+ }
90
+ end
91
+
92
+ private
93
+
94
+ # 保証カード(UR)を抽選する
95
+ #
96
+ # @return [Object] 保証されたカード
97
+ # @raise [ArgumentError] 保証カードが利用できない場合
98
+ def draw_guaranteed_card
99
+ guaranteed_cards = @engine.instance_variable_get(:@cards).select do |card|
100
+ card.respond_to?(:rarity) && card.rarity.to_sym == @guaranteed_rarity
101
+ end
102
+
103
+ raise ArgumentError, "No cards with rarity #{@guaranteed_rarity} found" if guaranteed_cards.empty?
104
+
105
+ # 保証カードからランダムにカードを返す
106
+ guaranteed_cards.sample
107
+ end
108
+
109
+ # カードが保証レアリティのカードかどうかをチェックする
110
+ #
111
+ # @param card [Object] 保証レアリティのカードかどうかをチェックするカード
112
+ # @return [Boolean] カードが保証レアリティのカードかどうか
113
+ def is_guaranteed_card?(card)
114
+ card.respond_to?(:rarity) && card.rarity.to_sym == @guaranteed_rarity
115
+ end
116
+ end
117
+ end
118
+ end
@@ -2,11 +2,8 @@
2
2
 
3
3
  module SGK
4
4
  module Gacha
5
- # Represents the result of a gacha draw.
5
+ # ガチャ抽選の結果を表す。
6
6
  #
7
- # This class wraps a card object and provides convenient accessors
8
- # for common card properties. It can be serialized to a hash for
9
- # logging or API responses.
10
7
  class Result
11
8
  attr_reader :card
12
9
 
@@ -22,9 +19,7 @@ module SGK
22
19
  @card.rarity
23
20
  end
24
21
 
25
- # Convert the result to a hash for JSON serialization.
26
- #
27
- # @return [Hash] A hash containing card_id, name, and rarity
22
+ # JSON変換用メソッド
28
23
  def json_format
29
24
  {
30
25
  card_id: @card.id,
data/lib/sgk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SGK
4
- VERSION = "0.1.0"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/sgk.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require_relative "sgk/version"
4
4
  require_relative "sgk/gacha/engine"
5
5
  require_relative "sgk/gacha/result"
6
+ require_relative "sgk/gacha/pity_system"
7
+ require_relative "sgk/gacha/multiple_draw"
6
8
 
7
9
  module SGK
8
10
  class Error < StandardError; end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: social-game-kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sugawara_nagisa
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-11-02 00:00:00.000000000 Z
10
+ date: 2025-11-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activerecord
@@ -53,6 +53,8 @@ files:
53
53
  - Rakefile
54
54
  - lib/sgk.rb
55
55
  - lib/sgk/gacha/engine.rb
56
+ - lib/sgk/gacha/multiple_draw.rb
57
+ - lib/sgk/gacha/pity_system.rb
56
58
  - lib/sgk/gacha/result.rb
57
59
  - lib/sgk/version.rb
58
60
  - sig/ssg.rbs