mgmg 1.5.6 → 1.5.7

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: 8ae7f8d4f1a701c2f96a4fddbcabdda81fad3355276a368cf7b987ee47e6bfa3
4
- data.tar.gz: 26ee4b16fa9e8a97db0245ddc1019f94b8bbb166dac3fb1812a573cfc9920538
3
+ metadata.gz: 959345a0547c379e6ea2cc55e56283b580429c6b25d2a50df0c3ac9c7b02f8db
4
+ data.tar.gz: 8832f8ad1f54c1f06c77a2c72b25631fbfa9e9f98b5fe0d48ae15c7dd15568da
5
5
  SHA512:
6
- metadata.gz: e973d0aed431aa65d45b479a3017a78c04e1d7403d8cebacc3337065c4111b382294e51d472a240a80bfea1ed9281860aaf3597225fb5da0088d50758632842c
7
- data.tar.gz: d0ea591eaa7fe9418191289468592d1b207a434fc367a0e0a8811550a7104a7b2dfc9b75df60a929c83ceeda0c4e41915451718a3a25662dd93abe8b7b500986
6
+ metadata.gz: d22e5011de865ee5a40550ca1341ae7f5c4ea696f086c95e9ce7be273cd2c4d1acbd6b676c1e87371fc1af05bfd90c1dc796d2b3076a3f5f7a01c1336bed7856
7
+ data.tar.gz: a70bd19a98d4212ff63d535be59b528d054dc4cbf981eda4bed20ef9e4dce065bc48f7aa4a15e9e6b90542872dde0c3537558557ce3ad1e4129ab174ceb84b8b
data/CHANGELOG.md CHANGED
@@ -158,6 +158,10 @@
158
158
  - `String#min_level`において,正しい答えを返さなくなったバグを修正.
159
159
 
160
160
  ## 1.5.6 2022/07/17
161
- - `String#find_lowerbound`,`String#find_upperbound`における探索刻み幅を1から1/8に変更し,コーナーケースでの精度を上昇させた.
161
+ - `Mgmg.#find_lowerbound`,`Mgmg.#find_upperbound`における探索刻み幅を1から1/8に変更し,コーナーケースでの精度を上昇させた.
162
162
  - `Enumerable#min_level`が,原料☆によるレベル制限を無視した値を返すことがあったバグを修正.
163
- - `String#find_lowerbound`や`Mgmg::IR#atk_sd` などにおいて,返り値が,分母が1の`Rational`である場合,代わりに`Integer`を返すように修正.
163
+ - `Mgmg.#find_lowerbound`や`Mgmg::IR#atk_sd` などにおいて,返り値が,分母が1の`Rational`である場合,代わりに`Integer`を返すように修正.
164
+
165
+ ## 1.5.7 2022/10/15
166
+ - 経験値上限を指定して,目標パラメータを最大化する製作Lvを返す`Mgmg::Recipe#find_max`を追加.
167
+ - `Mgmg::Recipe#search`において,解の経験値が`cut_exp`ちょうどの場合に例外となっていたバグを修正.
data/lib/mgmg/recipe.rb CHANGED
@@ -93,6 +93,10 @@ module Mgmg
93
93
  opt = temp_opt(**kw)
94
94
  @recipe.search(para, target, opt:)
95
95
  end
96
+ def find_max(max_exp, para: @para, **kw)
97
+ opt = temp_opt(**kw)
98
+ @recipe.find_max(para, max_exp, opt:)
99
+ end
96
100
  private def correct_level(s, ac, x, opt)
97
101
  if s.nil?
98
102
  if x.equal?(false)
data/lib/mgmg/search.rb CHANGED
@@ -1,3 +1,4 @@
1
+ using Mgmg::Refiner
1
2
  class String
2
3
  def smith_search(para, target, comp, opt: Mgmg::Option.new)
3
4
  opt = opt.dup.set_default(self)
@@ -55,9 +56,9 @@ class String
55
56
  opt.comp_max = comp_search(para, target, opt.smith_min, opt:)
56
57
  ret = nil
57
58
  exp = Mgmg.exp(opt.smith_min, opt.comp_max)
58
- opt.cut_exp, ret = exp, [opt.smith_min, opt.comp_max] if exp < opt.cut_exp
59
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.comp_max] if exp <= opt.cut_exp
59
60
  exp = Mgmg.exp(opt.smith_max, opt.comp_min)
60
- opt.cut_exp, ret = exp, [opt.smith_max, opt.comp_min] if exp < opt.cut_exp
61
+ opt.cut_exp, ret = exp, [opt.smith_max, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
61
62
  (opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
62
63
  break if opt.cut_exp < Mgmg.exp(opt.smith_min, comp)
63
64
  smith = smith_search(para, target, comp, opt:)
@@ -71,7 +72,24 @@ class String
71
72
  end
72
73
  rescue Mgmg::SearchCutException
73
74
  end
74
- raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{opt.cut_exp}" if ret.nil?
75
+ if ret.nil?
76
+ max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
77
+ raise Mgmg::SearchCutException, "the maximum output with given cut_exp=#{opt.cut_exp.comma3} is #{max.comma3}, which does not reach given target=#{target.comma3}"
78
+ end
79
+ ret
80
+ end
81
+
82
+ def find_max(para, max_exp, opt: Mgmg::Option.new)
83
+ opt = opt.dup.set_default(self)
84
+ exp = Mgmg.exp(opt.smith_min, opt.comp_min)
85
+ raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
86
+ ret = [Mgmg.invexp2(max_exp, opt.comp_min), opt.comp_min]
87
+ max = opt.irep.para_call(para, *ret)
88
+ (opt.comp_min+1).step(Mgmg.invexp2c(max_exp, opt.smith_min), opt.step) do |comp|
89
+ smith = Mgmg.invexp2(max_exp, comp)
90
+ cur = opt.irep.para_call(para, smith, comp)
91
+ ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
92
+ end
75
93
  ret
76
94
  end
77
95
  end
@@ -138,10 +156,10 @@ module Enumerable
138
156
  opt.armor_max = armor_search(para, target, opt.smith_min, comp, opt: opt_nocut)
139
157
  ret = nil
140
158
  exp = Mgmg.exp(opt.smith_min, opt.armor_max, comp)
141
- opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_max] if exp < opt.cut_exp
159
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_max] if exp <= opt.cut_exp
142
160
  exp2 = Mgmg.exp(opt.smith_max, opt.armor_min, comp)
143
161
  if exp2 < exp
144
- opt.cut_exp, ret = exp2, [opt.smith_max, opt.armor_min] if exp2 < opt.cut_exp
162
+ opt.cut_exp, ret = exp2, [opt.smith_max, opt.armor_min] if exp2 <= opt.cut_exp
145
163
  (opt.armor_min+1).upto(opt.armor_max-1) do |armor|
146
164
  break if opt.cut_exp < Mgmg.exp(opt.smith_min, armor, comp)
147
165
  smith = smith_search(para, target, armor, comp, opt:)
@@ -196,15 +214,16 @@ module Enumerable
196
214
  def search(para, target, opt: Mgmg::Option.new)
197
215
  opt = opt.dup.set_default(self)
198
216
  opt.comp_min = comp_search(para, target, opt.smith_max, opt.armor_max, opt:)
199
- opt.smith_max, opt.armor_max = sa_search(para, target, opt.comp_min, opt:)
200
- opt.smith_min, opt.armor_min = sa_search(para, target, opt.comp_max, opt:)
217
+ opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
218
+ opt.smith_max, opt.armor_max = sa_search(para, target, opt.comp_min, opt: opt_nocut)
219
+ opt.smith_min, opt.armor_min = sa_search(para, target, opt.comp_max, opt: opt_nocut)
201
220
  raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
202
221
  opt.comp_max = comp_search(para, target, opt.smith_min, opt.armor_min, opt:)
203
222
  ret = nil
204
223
  exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_max)
205
- opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp < opt.cut_exp
224
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp <= opt.cut_exp
206
225
  exp = Mgmg.exp(opt.smith_max, opt.armor_max, opt.comp_min)
207
- opt.cut_exp, ret = exp, [opt.smith_max, opt.armor_max, opt.comp_min] if exp < opt.cut_exp
226
+ opt.cut_exp, ret = exp, [opt.smith_max, opt.armor_max, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
208
227
  (opt.comp_min+1).upto(opt.comp_max-1) do |comp|
209
228
  break if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, comp)
210
229
  smith, armor = sa_search(para, target, comp, opt:)
@@ -218,14 +237,32 @@ module Enumerable
218
237
  end
219
238
  rescue Mgmg::SearchCutException
220
239
  end
221
- raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{opt.cut_exp}" if ret.nil?
240
+ if ret.nil?
241
+ max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
242
+ raise Mgmg::SearchCutException, "the maximum output with given cut_exp=#{opt.cut_exp.comma3} is #{max.comma3}, which does not reach given target=#{target.comma3}"
243
+ end
244
+ ret
245
+ end
246
+
247
+ def find_max(para, max_exp, opt: Mgmg::Option.new)
248
+ opt = opt.dup.set_default(self)
249
+ exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
250
+ raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
251
+ ret = [Mgmg.invexp3(max_exp, opt.armor_min, opt.comp_min), opt.armor_min, opt.comp_min]
252
+ max = opt.irep.para_call(para, *ret)
253
+ (opt.comp_min+1).step(Mgmg.invexp3c(max_exp, opt.smith_min, opt.armor_min), opt.step) do |comp|
254
+ opt.armor_min.upto(Mgmg.invexp3(max_exp, opt.smith_min, comp)) do |armor|
255
+ smith = Mgmg.invexp3(max_exp, armor, comp)
256
+ cur = opt.irep.para_call(para, smith, armor, comp)
257
+ ret, max = [smith, armor, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, armor, comp) < Mgmg.exp(*ret) ) )
258
+ end
259
+ end
222
260
  ret
223
261
  end
224
262
  end
225
263
 
226
264
  module Mgmg
227
265
  Eighth = 1.quo(8)
228
- using Refiner
229
266
  module_function def find_lowerbound(a, b, para, start, term, opt_a: Option.new, opt_b: Option.new)
230
267
  if term <= start
231
268
  raise ArgumentError, "start < term is needed, (start, term) = (#{start}, #{term}) are given"
data/lib/mgmg/utils.rb CHANGED
@@ -158,10 +158,36 @@ module Mgmg
158
158
  end
159
159
  end
160
160
  module_function def invexp2(exp, comp)
161
- Math.sqrt(exp - (2*((comp-1)**2)) - 3).round + 1
161
+ ret = Math.sqrt(exp - (2*((comp-1)**2)) - 3).floor + 2
162
+ if Mgmg.exp(ret, comp) <= exp
163
+ ret
164
+ else
165
+ ret-1
166
+ end
167
+ end
168
+ module_function def invexp2c(exp, s)
169
+ ret = Math.sqrt((exp - (((s-1)**2)) - 3).quo(2)).floor + 2
170
+ if Mgmg.exp(s, ret) <= exp
171
+ ret
172
+ else
173
+ ret-1
174
+ end
162
175
  end
163
176
  module_function def invexp3(exp, sa, comp)
164
- Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).round + 1
177
+ ret = Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).floor + 2
178
+ if Mgmg.exp(ret, sa, comp) <= exp
179
+ ret
180
+ else
181
+ ret-1
182
+ end
183
+ end
184
+ module_function def invexp3c(exp, smith, armor)
185
+ ret = Math.sqrt((exp - ((smith-1)**2) - ((armor-1)**2) - 4).quo(2)).floor + 2
186
+ if Mgmg.exp(smith, armor, ret) <= exp
187
+ ret
188
+ else
189
+ ret-1
190
+ end
165
191
  end
166
192
  module_function def clear_cache
167
193
  CacheMLS.clear; Equip::Cache.clear; Equip::CacheML.clear; TPolynomial::Cache.clear; IR::Cache.clear
data/lib/mgmg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mgmg
2
- VERSION = "1.5.6"
2
+ VERSION = "1.5.7"
3
3
  end
data/reference.md CHANGED
@@ -130,7 +130,7 @@
130
130
  `opt`は,`comp_min`,`comp_max`,`left_associative`,`reinforcement`,`irep`を使用します.
131
131
 
132
132
  ## `String#search(para, target, opt: Mgmg.option())`
133
- `c_min=comp_search(para, target, opt.smith_max, opt: opt)` から `c_max=comp_search(para, target, opt.smith_min, opt: opt)` まで,`opt.step`ずつ動かして,
133
+ 道具製作Lvを `c_min=comp_search(para, target, opt.smith_max, opt: opt)` から `c_max=comp_search(para, target, opt.smith_min, opt: opt)` まで,`opt.step`ずつ動かして,
134
134
  `smith_search`を行い,その過程で得られた最小経験値の鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.
135
135
  レシピ中の,対象パラメータの種別値がすべて奇数,または全て偶数であるなら,`opt.step`を`2`にしても探索すべき範囲を網羅できます.
136
136
  その他は`String#smith_seach`と同様です.
@@ -139,12 +139,18 @@
139
139
 
140
140
  ## `Enumerable#search(para, target, opt: Mgmg.option())`
141
141
  複数装備の組について,`para`の値が`target`以上となる最小経験値の`[鍛冶Lv,防具製作Lv,道具製作Lv]`を返します.
142
- 武器のみなら防具製作Lvは`0`,防具のみなら鍛冶Lvは`0`,合成なしなら道具製作Lvは`0`となります.
142
+ 武器のみなら防具製作Lvは`-1`,防具のみなら鍛冶Lvは`-1`,合成なしなら道具製作Lvは`0`となります.
143
143
 
144
144
  `opt.smith_min`および`opt.armor_min`のデフォルト値は,武器・防具の各総重量を`opt.target_weight`で製作するのに必要な鍛冶・防具製作Lv (`self.min_level(*opt.target_weight)`)です.`opt.target_weight`には2要素からなる配列を指定しますが,整数が与えられた場合,それを2つ並べた配列と同等のものとして扱います.合計重量を指定することにはならないので注意してください.`opt.target_weight`のデフォルト値は`0`です.
145
145
 
146
146
  その他は,`String#smith_seach`と同様です.
147
147
 
148
+ ## `String#find_max(para, max_exp, opt: Mgmg.option())`
149
+ 経験値の合計が`max_exp`以下の範囲で,`para`の値が最大となる鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.`para`の値が最大となる組が複数存在する場合,経験値が小さい方が優先されます.
150
+
151
+ ## `Enumerable#find_max(para, max_exp, opt: Mgmg.option())`
152
+ 複数装備の組について,経験値の合計が`max_exp`以下の範囲で,`para`の値が最大となる鍛冶Lv,防具製作Lv,道具製作Lvからなる配列を返します.`para`の値が最大となる組が複数存在する場合,経験値が小さい方が優先されます.
153
+
148
154
  ## `Mgmg.#find_lowerbound(a, b, para, start, term, opt_a: Mgmg.option(), opt_b: Mgmg.option())`
149
155
  レシピ`a`とレシピ`b`について,`para`の値を目標値以上にする最小経験値の組において,目標値`start`における優劣が逆転する目標値の下限を探索し,返します.
150
156
  返り値は`[逆転しない最大目標値, 逆転時の最小para値]`です.前者は逆転目標値の下限,後者は,目標値が前者よりも少しだけ大きいときの`para`値です.
@@ -482,6 +488,9 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
482
488
  ## `Mgmg::Recipe#search(target, para: self.para, **kw)`
483
489
  `self.recipe.search`を呼び出して返します.注目パラメータはセットされたものを自動的に渡しますが,別のパラメータを使いたい場合,キーワード引数で指定します.その他のキーワード引数を与えた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
484
490
 
491
+ ## `Mgmg::Recipe#find_max(max_exp, para: self.para, **kw)`
492
+ `self.recipe.find_max`を呼び出して返します.注目パラメータはセットされたものを自動的に渡しますが,別のパラメータを使いたい場合,キーワード引数で指定します.その他のキーワード引数を与えた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
493
+
485
494
  ## `Mgmg::Recipe#min_level(w=self.option.target_weight, include_outsourcing=false)`
486
495
  `self.recipe.min_level(w, include_outsourcing)`を返します.`w`のデフォルトパラメータが`target_weight`になっている以外は`String#min_level`または`Enumerable#min_level`と同じです.
487
496
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mgmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.6
4
+ version: 1.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - KAZOON
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-17 00:00:00.000000000 Z
11
+ date: 2022-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  requirements: []
107
- rubygems_version: 3.3.18
107
+ rubygems_version: 3.3.23
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Calculate specs of equipments of Megurimeguru, a game produced by Kou.