mgmg 1.5.7 → 1.6.0

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: 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.