sorare-rewards 1.0.2 → 1.1.3.beta0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 503bd2bc5d9b16f6c2ba4e9209c14920dc000730dc3466eea88534abe97187c2
4
- data.tar.gz: c03342737d6af15c514932029928fb26acd255700811e8bd9de53f62f7a5a91e
3
+ metadata.gz: bcb36662a381adcf213a5ab17ad97ae1d57f862f84e274679657a05d096476cb
4
+ data.tar.gz: 1d38e28d7fc1912cf14ae3dfa48546f1aa87b427e5025ac8e2896dd3dce6a117
5
5
  SHA512:
6
- metadata.gz: 496c0f02f3c3735895c314d5f680a36fd3a2965a63d196f209efdd6cefcb6c9eaf5a8f5995c90a27ad36963cd68eb071f5467abf998738b856ca1a389dba87c6
7
- data.tar.gz: 5386e7e1e7f95c9b703882e5623c0aeec9ce71b4d9d46e85f807601e2f918b76c095dbac01f26ccfacd2262a0384d4f83ec22857810629e5b29ff274bc6a2d66
6
+ metadata.gz: e66851acb6b951557c607e2ebf24552ea5b16d63d3faf260f344175bf674758dc5efe7549b96c6fa164f1bdfc263066234b0e09f79a66ccbbb1c5f7dc0df903e
7
+ data.tar.gz: 6a2a8979952b7446ac9470b360fae8e7c2d8c53dd4db4442da9e60472090c2bae881fcf625e9c5da5a19d8bcff9c0356f80c2acb3a1586b074bdeb87f2e0689c
data/Gemfile.lock CHANGED
@@ -1,30 +1,30 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sorare-rewards (1.0.2)
5
- activesupport (~> 6.1)
6
- interactor (~> 3.0)
4
+ sorare-rewards (1.1.3.beta0)
5
+ activesupport (~> 6.1.4)
6
+ interactor (~> 3.1.2)
7
7
  json (~> 2)
8
8
  net-http (~> 0.1.1)
9
- yaml (~> 0.1.1)
9
+ yaml (~> 0.2.0)
10
10
 
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- activesupport (6.1.3.2)
14
+ activesupport (6.1.4.1)
15
15
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
16
  i18n (>= 1.6, < 2)
17
17
  minitest (>= 5.1)
18
18
  tzinfo (~> 2.0)
19
19
  zeitwerk (~> 2.3)
20
20
  ast (2.4.2)
21
- concurrent-ruby (1.1.8)
21
+ concurrent-ruby (1.1.9)
22
22
  diff-lcs (1.4.4)
23
23
  i18n (1.8.10)
24
24
  concurrent-ruby (~> 1.0)
25
25
  interactor (3.1.2)
26
26
  io-wait (0.1.0)
27
- json (2.5.1)
27
+ json (2.6.0)
28
28
  minitest (5.14.4)
29
29
  net-http (0.1.1)
30
30
  net-protocol
@@ -32,9 +32,9 @@ GEM
32
32
  net-protocol (0.1.1)
33
33
  io-wait
34
34
  timeout
35
- ostruct (0.2.0)
36
- parallel (1.20.1)
37
- parser (3.0.1.0)
35
+ ostruct (0.4.0)
36
+ parallel (1.21.0)
37
+ parser (3.0.2.0)
38
38
  ast (~> 2.4.1)
39
39
  rainbow (3.0.0)
40
40
  rake (12.3.3)
@@ -53,42 +53,41 @@ GEM
53
53
  diff-lcs (>= 1.2.0, < 2.0)
54
54
  rspec-support (~> 3.10.0)
55
55
  rspec-support (3.10.2)
56
- rubocop (1.12.1)
56
+ rubocop (1.22.1)
57
57
  parallel (~> 1.10)
58
58
  parser (>= 3.0.0.0)
59
59
  rainbow (>= 2.2.2, < 4.0)
60
60
  regexp_parser (>= 1.8, < 3.0)
61
61
  rexml
62
- rubocop-ast (>= 1.2.0, < 2.0)
62
+ rubocop-ast (>= 1.12.0, < 2.0)
63
63
  ruby-progressbar (~> 1.7)
64
64
  unicode-display_width (>= 1.4.0, < 3.0)
65
- rubocop-ast (1.4.1)
66
- parser (>= 2.7.1.5)
67
- rubocop-rake (0.5.1)
68
- rubocop
69
- rubocop-rspec (2.2.0)
65
+ rubocop-ast (1.12.0)
66
+ parser (>= 3.0.1.1)
67
+ rubocop-rake (0.6.0)
70
68
  rubocop (~> 1.0)
71
- rubocop-ast (>= 1.1.0)
69
+ rubocop-rspec (2.5.0)
70
+ rubocop (~> 1.19)
72
71
  ruby-progressbar (1.11.0)
73
- timeout (0.1.1)
72
+ timeout (0.2.0)
74
73
  tzinfo (2.0.4)
75
74
  concurrent-ruby (~> 1.0)
76
- unicode-display_width (2.0.0)
75
+ unicode-display_width (2.1.0)
77
76
  uri (0.10.1)
78
- yaml (0.1.1)
79
- zeitwerk (2.4.2)
77
+ yaml (0.2.0)
78
+ zeitwerk (2.5.0)
80
79
 
81
80
  PLATFORMS
82
81
  ruby
83
82
 
84
83
  DEPENDENCIES
85
- ostruct (~> 0.2.0)
84
+ ostruct (~> 0.4.0)
86
85
  rake (~> 12.0)
87
86
  rspec (~> 3.10)
88
- rubocop (~> 1.12.1)
89
- rubocop-rake (~> 0.5.1)
90
- rubocop-rspec (~> 2.2.0)
87
+ rubocop (~> 1.22.1)
88
+ rubocop-rake (~> 0.6.0)
89
+ rubocop-rspec (~> 2.5.0)
91
90
  sorare-rewards!
92
91
 
93
92
  BUNDLED WITH
94
- 2.1.4
93
+ 2.2.22
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Sorare
6
+ module Rewards
7
+ # WithAnalytics defines analytics methods
8
+ module WithAnalytics
9
+ extend ActiveSupport::Concern
10
+
11
+ def analytics
12
+ @analytics ||= each_league.each_with_object({}) do |league, stats|
13
+ stats[league.name] = league_analytics(league)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def reward_distributed
20
+ @reward_distributed ||= reward_allocations.card_allocations.transform_values do |league|
21
+ league.transform_values do |rarity|
22
+ rarity.sum { |_, divisions| divisions.values.sum }
23
+ end
24
+ end
25
+ end
26
+
27
+ def league_analytics(league)
28
+ {
29
+ playing_players_with_supply: nb_of_playing_players(league),
30
+ available_cards: nb_of_available_cards(league),
31
+ cooldown_players: nb_of_fully_cooldown_players(league),
32
+ rewarded: reward_distributed[league.name]
33
+ }
34
+ end
35
+
36
+ def nb_of_playing_players(league)
37
+ supply_for(league.name).keys.index_with do |rarity|
38
+ (supply_for(league.name, rarity: rarity).keys & playing_players.keys).count
39
+ end
40
+ end
41
+
42
+ def nb_of_available_cards(league)
43
+ supply_for(league.name).keys.index_with do |rarity|
44
+ supply_for(league.name, rarity: rarity).sum { |_, data| data['supply'] }
45
+ end
46
+ end
47
+
48
+ def nb_of_fully_cooldown_players(league)
49
+ supply_for(league.name).keys.index_with do |rarity|
50
+ supply_for(league.name, rarity: rarity).filter do |player_slug|
51
+ player(player_slug).available_during_cooldown(league, rarity).zero?
52
+ end.count
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -8,6 +8,8 @@ module Sorare
8
8
  module Rewards
9
9
  # GameWeek stores the reward data of a game week
10
10
  class GameWeek
11
+ include WithAnalytics
12
+
11
13
  attr_reader :salt
12
14
 
13
15
  delegate :card_allocations, :prize_pools, to: :reward_allocations
@@ -69,6 +71,10 @@ module Sorare
69
71
  def player(slug)
70
72
  Player.new(slug, self)
71
73
  end
74
+
75
+ def inspect
76
+ super.splice(:version)
77
+ end
72
78
  end
73
79
  end
74
80
  end
@@ -12,7 +12,7 @@ module Sorare
12
12
  @config = config
13
13
  end
14
14
 
15
- %w[cooldown limits prize_pool_currency].each do |key|
15
+ %w[cooldown limits prize_pool_currency rewards_ratio_per_cards_in_circulation].each do |key|
16
16
  define_method(key) do
17
17
  config[key]
18
18
  end
@@ -17,10 +17,8 @@ module Sorare
17
17
  end
18
18
 
19
19
  def allocate_and_format!
20
- allocations = allocate!
21
-
22
- allocations.keys.index_with do |rarity|
23
- allocations[rarity].first.keys.index_with do |division|
20
+ each_rarity_allocation do |rarity|
21
+ (allocations[rarity].first || {}).keys.index_with do |division|
24
22
  allocations[rarity].each_with_index.map do |qualified_allocations, tier|
25
23
  [Sorare::Rewards.configuration.transform_tier.call(tier), qualified_allocations[division]]
26
24
  end.to_h
@@ -28,8 +26,12 @@ module Sorare
28
26
  end
29
27
  end
30
28
 
31
- def allocate!
32
- (config || {}).keys.index_with do |rarity|
29
+ def each_rarity_allocation(&block)
30
+ allocations.keys.index_with(&block)
31
+ end
32
+
33
+ def allocations
34
+ @allocations ||= (config || {}).keys.index_with do |rarity|
33
35
  ComputeForRarity.call!(**context.to_h, supply: supply[rarity], config: config[rarity]).rarity_allocations
34
36
  end
35
37
  end
@@ -15,7 +15,13 @@ module Sorare
15
15
  def call
16
16
  context.fail!(error: 'Invalid config') unless config
17
17
 
18
- context.rarity_allocations = supply.each_with_index.map do |tier_supply, tier|
18
+ context.rarity_allocations = allocations
19
+ end
20
+
21
+ def allocations
22
+ return [] unless supply
23
+
24
+ supply.each_with_index.map do |tier_supply, tier|
19
25
  ComputeForQuality.call!(
20
26
  **context.to_h,
21
27
  supply: tier_supply,
@@ -16,39 +16,49 @@ module Sorare
16
16
  def call
17
17
  context.rarity_supply = []
18
18
 
19
- context.rewardable = compute_rewardable_supply!
19
+ context.rewardable = rewardable_supply
20
20
  distribute_in_tiers!
21
21
  end
22
22
 
23
- def compute_rewardable_supply!
24
- total_supply = supply.keys.sum do |player|
25
- player_supply(player)
26
- end
23
+ def rewardable_supply
24
+ total_float_supply = supply.keys.sum { |player| player_contribution(player) }
27
25
 
28
- rounded_supply(total_supply)
26
+ round_and_cap_league_supply(total_float_supply)
29
27
  end
30
28
 
31
29
  def distribute_in_tiers!
32
30
  ctx = Tiers::QualifySupply.call!(sorted_supply: supply)
33
- ctx.supply.each do |tier_supply|
31
+ qualified_players = Tiers::QualifyPlayers.call!(sorted_supply: supply).players
32
+ ctx.supply.each_with_index do |tier_supply, index|
34
33
  rarity_supply.push(
35
- ComputeForQuality.call!(
36
- randomizer: randomizer,
37
- total_supply: ctx.count,
38
- tier_supply: tier_supply,
39
- rewardable: rewardable,
40
- rewarded: rarity_supply
41
- ).quality_supply
34
+ capped_tier_supply(ctx.count, tier_supply, rewardable, qualified_players[index])
42
35
  )
43
36
  end
44
37
  end
45
38
 
46
- def player_supply(slug)
39
+ # Cap with the actual pickable supply for the tier
40
+ def capped_tier_supply(total_supply, tier_supply, rewardable, tier_players)
41
+ target = ComputeForQuality.call!(
42
+ randomizer: randomizer, total_supply: total_supply,
43
+ tier_supply: tier_supply, rewardable: rewardable, rewarded: rarity_supply
44
+ ).quality_supply
45
+
46
+ [target, tier_players.sum { |player| player_pickable_supply(player) }].min
47
+ end
48
+
49
+ def round_and_cap_league_supply(float_supply)
50
+ [
51
+ float_supply.floor + remaining_supply(float_supply.modulo(1)), # Supply limit
52
+ league.cards_in_circulation_limit(rarity) # Circulation limit
53
+ ].compact.min
54
+ end
55
+
56
+ def player_contribution(slug)
47
57
  game_week.player(slug).reward_pool_supply_contribution(league, rarity)
48
58
  end
49
59
 
50
- def rounded_supply(float_supply)
51
- float_supply.floor + remaining_supply(float_supply.modulo(1))
60
+ def player_pickable_supply(slug)
61
+ game_week.player(slug).pickable_supply(league, rarity)
52
62
  end
53
63
 
54
64
  def remaining_supply(reward_probability)
@@ -33,13 +33,13 @@ module Sorare
33
33
  end
34
34
 
35
35
  def tier_depth
36
- @tier_depth ||= sorted_supply.keys.length / (nb_of_tiers**2 - 1)
36
+ @tier_depth ||= sorted_supply.keys.length / ((nb_of_tiers**2) - 1)
37
37
  end
38
38
 
39
39
  def nb_of_tiers
40
40
  @nb_of_tiers ||= begin
41
41
  default = Sorare::Rewards.configuration.tiers
42
- default -= 1 while (default**2 - 1) > sorted_supply.keys.length
42
+ default -= 1 while ((default**2) - 1) > sorted_supply.keys.length
43
43
 
44
44
  default
45
45
  end
@@ -49,7 +49,7 @@ module Sorare
49
49
  return 0 unless tier.positive?
50
50
  return sorted_supply.keys.length if tier == nb_of_tiers
51
51
 
52
- tier_index(tier - 1) + tier_depth * tier_size(tier - 1)
52
+ tier_index(tier - 1) + (tier_depth * tier_size(tier - 1))
53
53
  end
54
54
 
55
55
  def tier_size(tier)
@@ -17,12 +17,18 @@ module Sorare
17
17
  @game_week = game_week
18
18
  end
19
19
 
20
- %w[playing_rate prize_pools].each do |key|
20
+ %w[playing_rate prize_pools cards_in_circulation].each do |key|
21
21
  define_method(key) do
22
22
  config[key]
23
23
  end
24
24
  end
25
25
 
26
+ def cards_in_circulation_limit(rarity)
27
+ return unless cards_in_circulation&.dig(rarity) && game_week.config.rewards_ratio_per_cards_in_circulation
28
+
29
+ (cards_in_circulation[rarity] * game_week.config.rewards_ratio_per_cards_in_circulation).floor
30
+ end
31
+
26
32
  def each_division_prize_pools
27
33
  prize_pools.each_with_index do |prize_pool, index|
28
34
  return to_enum(:each_division_prize_pools) unless block_given?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sorare
4
4
  module Rewards
5
- VERSION = '1.0.2'
5
+ VERSION = '1.1.3.beta0'
6
6
  end
7
7
  end
@@ -30,15 +30,15 @@ Gem::Specification.new do |spec|
30
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
31
  spec.require_paths = ['lib']
32
32
 
33
- spec.add_dependency 'activesupport', '~> 6.1'
34
- spec.add_dependency 'interactor', '~> 3.0'
33
+ spec.add_dependency 'activesupport', '~> 6.1.4'
34
+ spec.add_dependency 'interactor', '~> 3.1.2'
35
35
  spec.add_dependency 'json', '~> 2'
36
36
  spec.add_dependency 'net-http', '~> 0.1.1'
37
- spec.add_dependency 'yaml', '~> 0.1.1'
38
- spec.add_development_dependency 'ostruct', '~> 0.2.0'
37
+ spec.add_dependency 'yaml', '~> 0.2.0'
38
+ spec.add_development_dependency 'ostruct', '~> 0.4.0'
39
39
  spec.add_development_dependency 'rspec', '~> 3.10'
40
- spec.add_development_dependency 'rubocop', '~> 1.12.1'
41
- spec.add_development_dependency 'rubocop-rake', '~> 0.5.1'
42
- spec.add_development_dependency 'rubocop-rspec', '~> 2.2.0'
40
+ spec.add_development_dependency 'rubocop', '~> 1.22.1'
41
+ spec.add_development_dependency 'rubocop-rake', '~> 0.6.0'
42
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.5.0'
43
43
  end
44
44
  # rubocop:enable Metrics/BlockLength
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sorare-rewards
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.3.beta0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pierre
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-17 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '6.1'
19
+ version: 6.1.4
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '6.1'
26
+ version: 6.1.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: interactor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.0'
33
+ version: 3.1.2
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.0'
40
+ version: 3.1.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: json
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -72,28 +72,28 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.1.1
75
+ version: 0.2.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.1.1
82
+ version: 0.2.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: ostruct
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.2.0
89
+ version: 0.4.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.2.0
96
+ version: 0.4.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -114,42 +114,42 @@ dependencies:
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: 1.12.1
117
+ version: 1.22.1
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: 1.12.1
124
+ version: 1.22.1
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-rake
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 0.5.1
131
+ version: 0.6.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 0.5.1
138
+ version: 0.6.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rubocop-rspec
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: 2.2.0
145
+ version: 2.5.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: 2.2.0
152
+ version: 2.5.0
153
153
  description:
154
154
  email:
155
155
  - pierre@sorare.com
@@ -171,6 +171,7 @@ files:
171
171
  - data.patch
172
172
  - lib/sorare/rewards.rb
173
173
  - lib/sorare/rewards/allocation_configuration.yml
174
+ - lib/sorare/rewards/concerns/with_analytics.rb
174
175
  - lib/sorare/rewards/configuration.rb
175
176
  - lib/sorare/rewards/game_week.rb
176
177
  - lib/sorare/rewards/game_week_allocations.rb
@@ -220,11 +221,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
220
221
  version: 2.7.1
221
222
  required_rubygems_version: !ruby/object:Gem::Requirement
222
223
  requirements:
223
- - - ">="
224
+ - - ">"
224
225
  - !ruby/object:Gem::Version
225
- version: '0'
226
+ version: 1.3.1
226
227
  requirements: []
227
- rubygems_version: 3.1.6
228
+ rubygems_version: 3.2.22
228
229
  signing_key:
229
230
  specification_version: 4
230
231
  summary: '["Sorare", "reward", "allocation", "algorithm"]'