mgmg 1.5.7 → 1.6.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: 959345a0547c379e6ea2cc55e56283b580429c6b25d2a50df0c3ac9c7b02f8db
4
- data.tar.gz: 8832f8ad1f54c1f06c77a2c72b25631fbfa9e9f98b5fe0d48ae15c7dd15568da
3
+ metadata.gz: beb7f465bd84969abfb7ce5897d95f46171e84c2a0e3de9a14c42ccef5c23dfc
4
+ data.tar.gz: '09a7eda9204cb28a7a9fc24857353fb5cdcfd21e44564d4a25997658c92fdfd3'
5
5
  SHA512:
6
- metadata.gz: d22e5011de865ee5a40550ca1341ae7f5c4ea696f086c95e9ce7be273cd2c4d1acbd6b676c1e87371fc1af05bfd90c1dc796d2b3076a3f5f7a01c1336bed7856
7
- data.tar.gz: a70bd19a98d4212ff63d535be59b528d054dc4cbf981eda4bed20ef9e4dce065bc48f7aa4a15e9e6b90542872dde0c3537558557ce3ad1e4129ab174ceb84b8b
6
+ metadata.gz: 5642dc8af3ac998c76650047c97747a32f2b631e9f6438c6a95e6068a9534dcd726d34dd8466fb1cba0e787f11847552aab4812e1b32d4320ff23a5ec8e15e18
7
+ data.tar.gz: a327745f26724f3f6bbeabf2ed9fcb687ca4e462ac608c219165845b6ccfeafd5a30c32fdda4ee182dd268db8e0b4528e0acc1bc819eaaae0698d9400c764797
data/CHANGELOG.md CHANGED
@@ -165,3 +165,7 @@
165
165
  ## 1.5.7 2022/10/15
166
166
  - 経験値上限を指定して,目標パラメータを最大化する製作Lvを返す`Mgmg::Recipe#find_max`を追加.
167
167
  - `Mgmg::Recipe#search`において,解の経験値が`cut_exp`ちょうどの場合に例外となっていたバグを修正.
168
+
169
+ ## 1.6.0 2022/10/18
170
+ - `Mgmg.#find_upperbound`のアルゴリズムを改善し,探索下限目標値の引数を削除.
171
+ - `Enumerable#search`,`Enumerable#find_max`が正しい解を返さない場合があったバグを修正.
data/lib/mgmg/option.rb CHANGED
@@ -2,7 +2,7 @@ module Mgmg
2
2
  class Option
3
3
  Defaults = {
4
4
  left_associative: true, include_system_equips: true,
5
- smith_max: 10000, armor_max: 10000, comp_max: 10000
5
+ smith_max: 10_000, armor_max: 10_000, comp_max: 10_000
6
6
  }
7
7
  def initialize(
8
8
  left_associative: Defaults[:left_associative],
data/lib/mgmg/search.rb CHANGED
@@ -79,15 +79,27 @@ class String
79
79
  ret
80
80
  end
81
81
 
82
+ private def minimize_smith(para, smith, comp, cur, opt)
83
+ (smith-1).downto(opt.smith_min) do |s|
84
+ foo = opt.irep.para_call(para, s, comp)
85
+ if cur == foo
86
+ smith = s
87
+ else
88
+ break
89
+ end
90
+ end
91
+ smith
92
+ end
82
93
  def find_max(para, max_exp, opt: Mgmg::Option.new)
83
94
  opt = opt.dup.set_default(self)
84
95
  exp = Mgmg.exp(opt.smith_min, opt.comp_min)
85
96
  raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
86
97
  ret = [Mgmg.invexp2(max_exp, opt.comp_min), opt.comp_min]
87
98
  max = opt.irep.para_call(para, *ret)
88
- (opt.comp_min+1).step(Mgmg.invexp2c(max_exp, opt.smith_min), opt.step) do |comp|
99
+ (opt.comp_min+1).upto(Mgmg.invexp2c(max_exp, opt.smith_min)) do |comp|
89
100
  smith = Mgmg.invexp2(max_exp, comp)
90
101
  cur = opt.irep.para_call(para, smith, comp)
102
+ smith = minimize_smith(para, smith, comp, cur, opt) if max <= cur
91
103
  ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
92
104
  end
93
105
  ret
@@ -211,20 +223,79 @@ module Enumerable
211
223
  end
212
224
  opt.comp_max
213
225
  end
226
+ private def search_aonly(para, target, opt: Mgmg::Option.new)
227
+ opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
228
+ opt.armor_max = armor_search(para, target, -1, opt.comp_min, opt: opt_nocut)
229
+ opt.armor_min = armor_search(para, target, -1, opt.comp_max, opt: opt_nocut)
230
+ raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.armor_min, opt.comp_min)
231
+ opt.comp_max = comp_search(para, target, -1, opt.armor_min, opt:)
232
+ ret = nil
233
+ exp = Mgmg.exp(opt.armor_min, opt.comp_max)
234
+ opt.cut_exp, ret = exp, [-1, opt.armor_min, opt.comp_max] if exp <= opt.cut_exp
235
+ exp = Mgmg.exp(opt.armor_max, opt.comp_min)
236
+ opt.cut_exp, ret = exp, [-1, opt.armor_max, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
237
+ (opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
238
+ break if opt.cut_exp < Mgmg.exp(opt.armor_min, comp)
239
+ armor = armor_search(para, target, -1, comp, opt:)
240
+ exp = Mgmg.exp(armor, comp)
241
+ if exp < opt.cut_exp
242
+ opt.cut_exp, ret = exp, [-1, armor, comp]
243
+ elsif exp == opt.cut_exp
244
+ if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, -1, armor, comp) then
245
+ ret = [-1, armor, comp]
246
+ end
247
+ end
248
+ rescue Mgmg::SearchCutException
249
+ end
250
+ if ret.nil?
251
+ max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
252
+ 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}"
253
+ end
254
+ ret
255
+ end
256
+ private def search_sonly(para, target, opt: Mgmg::Option.new)
257
+ opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
258
+ opt.smith_max = smith_search(para, target, -1, opt.comp_min, opt: opt_nocut)
259
+ opt.smith_min = smith_search(para, target, -1, opt.comp_max, opt: opt_nocut)
260
+ raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.comp_min)
261
+ opt.comp_max = comp_search(para, target, opt.smith_min, -1, opt:)
262
+ ret = nil
263
+ exp = Mgmg.exp(opt.smith_min, opt.comp_max)
264
+ opt.cut_exp, ret = exp, [opt.smith_min, -1, opt.comp_max] if exp <= opt.cut_exp
265
+ exp = Mgmg.exp(opt.smith_max, opt.comp_min)
266
+ opt.cut_exp, ret = exp, [opt.smith_max, -1, opt.comp_min] if ( exp < opt.cut_exp || (ret.nil? && exp==opt.cut_exp) )
267
+ (opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
268
+ break if opt.cut_exp < Mgmg.exp(opt.smith_min, comp)
269
+ smith = smith_search(para, target, -1, comp, opt:)
270
+ exp = Mgmg.exp(smith, comp)
271
+ if exp < opt.cut_exp
272
+ opt.cut_exp, ret = exp, [smith, -1, comp]
273
+ elsif exp == opt.cut_exp
274
+ if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, smith, -1, comp) then
275
+ ret = [smith, -1, comp]
276
+ end
277
+ end
278
+ rescue Mgmg::SearchCutException
279
+ end
280
+ if ret.nil?
281
+ max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
282
+ 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}"
283
+ end
284
+ ret
285
+ end
214
286
  def search(para, target, opt: Mgmg::Option.new)
215
287
  opt = opt.dup.set_default(self)
216
288
  opt.comp_min = comp_search(para, target, opt.smith_max, opt.armor_max, opt:)
217
289
  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)
290
+ opt.smith_max = smith_search(para, target, opt.armor_min, opt.comp_min, opt: opt_nocut) rescue ( return search_aonly(para, target, opt:) )
291
+ opt.armor_max = armor_search(para, target, opt.smith_min, opt.comp_min, opt: opt_nocut) rescue ( return search_sonly(para, target, opt:) )
292
+ opt.smith_min = smith_search(para, target, opt.armor_max, opt.comp_max, opt: opt_nocut)
293
+ opt.armor_min = armor_search(para, target, opt.smith_max, opt.comp_max, opt: opt_nocut)
220
294
  raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
221
295
  opt.comp_max = comp_search(para, target, opt.smith_min, opt.armor_min, opt:)
222
- ret = nil
223
296
  exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_max)
224
297
  opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp <= opt.cut_exp
225
- exp = Mgmg.exp(opt.smith_max, opt.armor_max, opt.comp_min)
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) )
227
- (opt.comp_min+1).upto(opt.comp_max-1) do |comp|
298
+ (opt.comp_min).upto(opt.comp_max-1) do |comp|
228
299
  break if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, comp)
229
300
  smith, armor = sa_search(para, target, comp, opt:)
230
301
  exp = Mgmg.exp(smith, armor, comp)
@@ -244,17 +315,31 @@ module Enumerable
244
315
  ret
245
316
  end
246
317
 
318
+ private def minimize_smith(para, smith, armor, comp, cur, opt)
319
+ return -1 if opt.smith_min < 0
320
+ (smith-1).downto(opt.smith_min) do |s|
321
+ foo = opt.irep.para_call(para, s, armor, comp)
322
+ if cur == foo
323
+ smith = s
324
+ else
325
+ break
326
+ end
327
+ end
328
+ smith
329
+ end
247
330
  def find_max(para, max_exp, opt: Mgmg::Option.new)
248
331
  opt = opt.dup.set_default(self)
249
332
  exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
250
333
  raise Mgmg::SearchCutException, "the recipe requires #{exp.comma3} experiment points, which exceeds given max_exp=#{max_exp.comma3}" if max_exp < exp
251
334
  ret = [Mgmg.invexp3(max_exp, opt.armor_min, opt.comp_min), opt.armor_min, opt.comp_min]
252
335
  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|
336
+ (opt.comp_min).step(Mgmg.invexp3c(max_exp, opt.smith_min, opt.armor_min), opt.step) do |comp|
254
337
  opt.armor_min.upto(Mgmg.invexp3(max_exp, opt.smith_min, comp)) do |armor|
255
338
  smith = Mgmg.invexp3(max_exp, armor, comp)
256
339
  cur = opt.irep.para_call(para, smith, armor, comp)
340
+ smith = minimize_smith(para, smith, armor, comp, cur, opt) if max <= cur
257
341
  ret, max = [smith, armor, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, armor, comp) < Mgmg.exp(*ret) ) )
342
+ break if armor < 0
258
343
  end
259
344
  end
260
345
  ret
@@ -281,38 +366,42 @@ module Mgmg
281
366
  end
282
367
  sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
283
368
  ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
284
- if eb < ea || ( ea == eb && opt_a.irep.para_call(para, *sca) < opt_b.irep.para_call(para, *scb) )
369
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
370
+ if eb < ea || ( ea == eb && pa < pb )
285
371
  a, b, opt_a, opt_b, sca, scb, ea, eb = b, a, opt_b, opt_a, scb, sca, eb, ea
286
372
  end
287
- tag = opt_a.irep.para_call(para, *sca) + Eighth
288
- sca, scb = a.search(para, term, opt: opt_a), b.search(para, term, opt: opt_b)
289
- ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
290
- if ea < eb || ( ea == eb && opt_b.irep.para_call(para, *scb) < opt_a.irep.para_call(para, *sca) )
291
- raise Mgmg::SearchCutException
292
- end
293
- while tag < term
294
- sca, scb = a.search(para, tag, opt: opt_a), b.search(para, tag, opt: opt_b)
295
- ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
296
- pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
297
- if eb < ea
298
- return [(tag-Eighth).to_ii, pb]
299
- elsif ea == eb
300
- if pa < pb
301
- return [(tag-Eighth).to_ii, pa]
302
- else
303
- tag = pb + Eighth
304
- end
305
- else
373
+
374
+ loop do
375
+ loop do
376
+ foo = a.find_max(para, eb, opt: opt_a)
377
+ break if sca == foo
378
+ sca, pa = foo, opt_a.irep.para_call(para, *foo)
379
+ scb = b.search(para, pa, opt: opt_b)
380
+ foo = Mgmg.exp(*scb)
381
+ break if eb == foo
382
+ eb = foo
383
+ end
384
+ ea = Mgmg.exp(*sca)
385
+ while ea<=eb
306
386
  tag = pa + Eighth
387
+ raise Mgmg::SearchCutException, "given recipes are never reversed from start target=#{start.comma3} until term target=#{term.comma3}" if term < tag
388
+ sca, scb = a.search(para, tag, opt: opt_a), b.search(para, tag, opt: opt_b)
389
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
390
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
391
+ break if ea == eb && pa < pb
392
+ end
393
+ if eb < ea || ( ea == eb && pa < pb )
394
+ until ea < eb || ( ea == eb && pb < pa )
395
+ sca = a.find_max(para, ea-1, opt: opt_a)
396
+ ea, pa = Mgmg.exp(*sca), opt_a.irep.para_call(para, *sca)
397
+ end
398
+ return [pa, pb]
307
399
  end
308
400
  end
309
401
  raise UnexpectedError
310
402
  end
311
403
 
312
- module_function def find_upperbound(a, b, para, start, term, opt_a: Option.new, opt_b: Option.new)
313
- if start <= term
314
- raise ArgumentError, "term < start is needed, (start, term) = (#{start}, #{term}) are given"
315
- end
404
+ module_function def find_upperbound(a, b, para, start, opt_a: Option.new, opt_b: Option.new)
316
405
  if a.kind_of?(Recipe)
317
406
  opt_a = a.option.dup
318
407
  a = a.recipe
@@ -327,58 +416,53 @@ module Mgmg
327
416
  end
328
417
  sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
329
418
  ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
330
- if ea < eb || ( ea == eb && opt_b.irep.para_call(para, *scb) < opt_a.irep.para_call(para, *sca) )
419
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
420
+ if ea < eb || ( ea == eb && pb < pa )
331
421
  a, b, opt_a, opt_b, sca, scb, ea, eb = b, a, opt_b, opt_a, scb, sca, eb, ea
332
422
  end
333
- tagu = opt_a.irep.para_call(para, *sca)
334
- sca[-1] -= 2
335
- tagl = opt_a.irep.para_call(para, *sca)
336
- sca, scb = a.search(para, term, opt: opt_a), b.search(para, term, opt: opt_b)
337
- ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
338
- if eb < ea || ( ea == eb && opt_a.irep.para_call(para, *sca) < opt_b.irep.para_call(para, *scb) )
339
- raise Mgmg::SearchCutException
340
- end
341
- while term < tagu
342
- ret = nil
343
- sca = a.search(para, tagl, opt: opt_a)
344
- next_tagu, next_sca = tagl, sca
345
- scb = b.search(para, tagl, opt: opt_b)
346
- while tagl < tagu
423
+
424
+ loop do
425
+ loop do
426
+ foo = a.find_max(para, eb, opt: opt_a)
427
+ break if sca == foo
428
+ sca, pa = foo, opt_a.irep.para_call(para, *foo)
429
+ scb = b.search(para, pa, opt: opt_b)
430
+ foo = Mgmg.exp(*scb)
431
+ break if eb == foo
432
+ eb = foo
433
+ end
434
+ ea = Mgmg.exp(*sca)
435
+ while ea==eb do
436
+ res = 0
437
+ begin
438
+ sca = a.find_max(para, ea-1, opt: opt_a)
439
+ rescue Mgmg::SearchCutException
440
+ res += 1
441
+ end
442
+ begin
443
+ scb = b.find_max(para, eb-1, opt: opt_b)
444
+ rescue Mgmg::SearchCutException
445
+ res += 1
446
+ end
347
447
  ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
348
448
  pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
349
- if ea < eb
350
- ret = tagl
351
- sca = a.search(para, pa + Eighth, opt: opt_a)
352
- tagl = opt_a.irep.para_call(para, *sca)
353
- scb = b.search(para, tagl, opt: opt_b)
354
- elsif ea == eb
355
- if pb < pa
356
- ret = tagl
357
- sca = a.search(para, pa + Eighth, opt: opt_a)
358
- tagl = opt_a.irep.para_call(para, *sca)
359
- scb = b.search(para, tagl, opt: opt_b)
360
- else
361
- scb = b.search(para, pb + Eighth, opt: opt_b)
362
- tagl = opt_b.irep.para_call(para, *scb)
363
- sca = a.search(para, tagl, opt: opt_a)
449
+ if ea < eb || ( ea == eb && pb < pa )
450
+ until pa < pb
451
+ scb = b.search(para, pb+Eighth, opt: opt_b)
452
+ pb = opt_b.irep.para_call(para, *scb)
364
453
  end
365
- else
366
- sca = a.search(para, pa + Eighth, opt: opt_a)
367
- tagl = opt_a.irep.para_call(para, *sca)
368
- scb = b.search(para, tagl, opt: opt_b)
454
+ return [pa, pb]
455
+ elsif res == 2
456
+ raise Mgmg::SearchCutException, "given recipes are never reversed from the start target=#{start.comma3} until #{pa.comma3}"
369
457
  end
370
458
  end
371
- if ret.nil?
372
- tagu = next_tagu
373
- next_sca[-1] -= 2
374
- tagl = opt_a.irep.para_call(para, *next_sca)
375
- if tagl == tagu
376
- tagl = term
459
+ if ea < eb
460
+ pb = opt_b.irep.para_call(para, *scb)
461
+ until pa < pb
462
+ scb = b.search(para, pb+Eighth, opt: opt_b)
463
+ pb = opt_b.irep.para_call(para, *scb)
377
464
  end
378
- else
379
- pa = opt_a.irep.para_call(para, *a.search(para, ret+Eighth, opt: opt_a))
380
- pb = opt_b.irep.para_call(para, *b.search(para, ret+Eighth, opt: opt_b))
381
- return [ret.to_ii, [pa, pb].min]
465
+ return [pa, pb]
382
466
  end
383
467
  end
384
468
  raise UnexpectedError
@@ -386,7 +470,32 @@ module Mgmg
386
470
 
387
471
  module_function def find_lubounds(a, b, para, lower, upper, opt_a: Mgmg::Option.new, opt_b: Mgmg::Option.new)
388
472
  xl, yl = find_lowerbound(a, b, para, lower, upper, opt_a:, opt_b:)
389
- xu, yu = find_upperbound(a, b, para, upper, lower, opt_a:, opt_b:)
473
+ xu, yu = find_upperbound(a, b, para, upper, opt_a:, opt_b:)
390
474
  [xl, yl, xu, yu]
391
475
  end
476
+ module_function def find_lubounds2(a, b, para, lower, upper, opt_a: Mgmg::Option.new, opt_b: Mgmg::Option.new)
477
+ xl, yl, xu, yu = find_lubounds(a, b, para, lower, upper, opt_a: Mgmg::Option.new, opt_b: Mgmg::Option.new)
478
+ if a.kind_of?(Recipe)
479
+ opt_a = a.option.dup
480
+ a = a.recipe
481
+ else
482
+ opt_a = opt_a.dup.set_default(a)
483
+ end
484
+ if b.kind_of?(Recipe)
485
+ opt_b = b.option.dup
486
+ b = b.recipe
487
+ else
488
+ opt_b = opt_b.dup.set_default(b)
489
+ end
490
+ sca, scb = a.search(para, lower, opt: opt_a), b.search(para, lower, opt: opt_b)
491
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
492
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
493
+ if eb < ea || ( ea == eb && pa < pb )
494
+ a, b, opt_a, opt_b, sca, scb, ea, eb = b, a, opt_b, opt_a, scb, sca, eb, ea
495
+ end
496
+ sca, scb = a.search(para, xl, opt: opt_a), b.search(para, yu, opt: opt_b)
497
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
498
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
499
+ [sca, ea, pa, scb, eb, pb]
500
+ end
392
501
  end
data/lib/mgmg/utils.rb CHANGED
@@ -158,7 +158,11 @@ module Mgmg
158
158
  end
159
159
  end
160
160
  module_function def invexp2(exp, comp)
161
- ret = Math.sqrt(exp - (2*((comp-1)**2)) - 3).floor + 2
161
+ begin
162
+ ret = Math.sqrt(exp - (2*((comp-1)**2)) - 3).floor + 2
163
+ rescue Math::DomainError
164
+ return -1
165
+ end
162
166
  if Mgmg.exp(ret, comp) <= exp
163
167
  ret
164
168
  else
@@ -166,7 +170,11 @@ module Mgmg
166
170
  end
167
171
  end
168
172
  module_function def invexp2c(exp, s)
169
- ret = Math.sqrt((exp - (((s-1)**2)) - 3).quo(2)).floor + 2
173
+ begin
174
+ ret = Math.sqrt((exp - (((s-1)**2)) - 3).quo(2)).floor + 2
175
+ rescue Math::DomainError
176
+ return -1
177
+ end
170
178
  if Mgmg.exp(s, ret) <= exp
171
179
  ret
172
180
  else
@@ -174,7 +182,12 @@ module Mgmg
174
182
  end
175
183
  end
176
184
  module_function def invexp3(exp, sa, comp)
177
- ret = Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).floor + 2
185
+ return invexp2(exp, comp) if sa < 0
186
+ begin
187
+ ret = Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).floor + 2
188
+ rescue Math::DomainError
189
+ return -1
190
+ end
178
191
  if Mgmg.exp(ret, sa, comp) <= exp
179
192
  ret
180
193
  else
@@ -182,7 +195,16 @@ module Mgmg
182
195
  end
183
196
  end
184
197
  module_function def invexp3c(exp, smith, armor)
185
- ret = Math.sqrt((exp - ((smith-1)**2) - ((armor-1)**2) - 4).quo(2)).floor + 2
198
+ if smith < 0
199
+ return invexp2c(exp, armor)
200
+ elsif armor < 0
201
+ return invexp2c(exp, smith)
202
+ end
203
+ begin
204
+ ret = Math.sqrt((exp - ((smith-1)**2) - ((armor-1)**2) - 4).quo(2)).floor + 2
205
+ rescue Math::DomainError
206
+ return -1
207
+ end
186
208
  if Mgmg.exp(smith, armor, ret) <= exp
187
209
  ret
188
210
  else
data/lib/mgmg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mgmg
2
- VERSION = "1.5.7"
2
+ VERSION = "1.6.0"
3
3
  end
data/reference.md CHANGED
@@ -161,7 +161,7 @@
161
161
 
162
162
  `opt_a`,`opt_b`には,それぞれ`a`と`b`に関するオプションパラメータを指定します.`smith_min`,`armor_min`,`min_smith`,`left_associative`,`reinforcement`,`irep`を使用します.
163
163
 
164
- ## `Mgmg.#find_upperbound(a, b, para, start, term, opt_a: Mgmg.option(), opt_b: Mgmg.option())`
164
+ ## `Mgmg.#find_upperbound(a, b, para, start, opt_a: Mgmg.option(), opt_b: Mgmg.option())`
165
165
  `Mgmg.#find_lowerbound`とは逆に,目標値を下げながら,優劣が逆転する最大の目標値を探索し,返します.返り値は`[逆転する最大目標値, 逆転前の最小para値]`です.目標値が,前者よりも少しでも大きいと逆転が起こらず(逆転する目標値の上限),少しだけ大きい時の`para`値が後者になります.
166
166
 
167
167
  `opt_a`,`opt_b`は,`Mgmg.#find_lowerbound`と同様です.
@@ -455,7 +455,7 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
455
455
  |smith_min|`recipe.min_level(target_weight)`|非対応|鍛冶Lvに関する探索範囲の最小値|`String#search`など|
456
456
  |armor_min|`recipe.min_level(*target_weight)[1]`|非対応|防具製作Lvに関する探索範囲の最小値|`Enumerable#search`など.`String`系では代わりに`smith_min`を使う|
457
457
  |comp_min|`recipe.min_comp`|非対応|道具製作Lvに関する探索範囲の最小値|`String#search`など|
458
- |smith_max, armor_max, comp_max|`10000`|対応|各製作Lvの探索範囲の最大値|`String#search`など|
458
+ |smith_max, armor_max, comp_max|`10,000`|対応|各製作Lvの探索範囲の最大値|`String#search`など|
459
459
  |target_weight|`0`|非対応|`smith_min`のデフォルト値計算に使う目標重量|`String#search`など|
460
460
  |step|`1`|非対応|探索時において道具製作Lvを動かす幅|`String#search`など|
461
461
  |magdef_maximize|`true`|非対応|目標を魔防最大(真)かコスト最小(偽)にするためのスイッチ|`String#phydef_optimize`|
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.7
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - KAZOON
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-15 00:00:00.000000000 Z
11
+ date: 2022-10-18 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.23
107
+ rubygems_version: 3.3.24
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: Calculate specs of equipments of Megurimeguru, a game produced by Kou.