mgmg 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +19 -0
- data/lib/mgmg/recipe.rb +13 -4
- data/lib/mgmg/search.rb +142 -55
- data/lib/mgmg/utils.rb +8 -0
- data/lib/mgmg/version.rb +1 -1
- data/lib/mgmg.rb +17 -11
- data/reference.md +51 -9
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3698312de546d3f9a7eac1aadd6024ae8132a8c58f97c041fa07b788828a3bcc
|
4
|
+
data.tar.gz: 19d8263ccfd11a476472868a8420959cccc356bbd7f69fcf619f831fde589794
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0edb6042eb1fccbe9d6b4761afd1a2ad0814910850b2664325d20f109fe9d6805cf28aab5d25b363842cde62dce3e1739319668446e912b6a15d94e2043654f
|
7
|
+
data.tar.gz: 70ed1f01ca7bfd7ef4be9fc886f74f2049d466cc73e2fb79276dd9768d40bed0232119cde2a177def7721f677271ff602b71d3231d207a94a5850fcd82844b8a
|
data/CHANGELOG.md
CHANGED
@@ -189,3 +189,8 @@
|
|
189
189
|
- オプション`comp_ext`を`fib_ext`に変更し,追加探索の範囲を修正.
|
190
190
|
- オプション`smith/armor/comp_max`の扱い方を修正し,デフォルト値を10^5に変更.
|
191
191
|
- `Enumerable#find_max`,`Mgmg.#find_lowerbound`のバグを修正.
|
192
|
+
|
193
|
+
## 1.8.1 2022/11/19
|
194
|
+
- `Mgmg::Recipe`に`name`属性を追加.`String/Enumerable#to_recipe`の際,キーワード引数`name`を追加することで設定できる.
|
195
|
+
- `Mgmg.#efficient_list` を追加.
|
196
|
+
- `Enumerable#build`,`Enumerable#search`で意図せぬ例外が発生していた問題を修正.
|
data/README.md
CHANGED
@@ -132,6 +132,25 @@ puts r.build(*sc, buff: []) # 一時的に強化を解除して素の性能を
|
|
132
132
|
#=> 重鎧8☆20(綿宝)[物防:32,538, 魔防:4]
|
133
133
|
```
|
134
134
|
|
135
|
+
連続して探索し,最適レシピの推移をcsvファイルに出力する.また,探索範囲内で少なくとも一度は最適に選ばれたレシピのリストを確認する.
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
str = <<EOS
|
139
|
+
斧(火玉5綿1)+[杖(水1綿1)+[斧(玉5水1)+[杖(綿1綿1)+[斧(玉5綿1)+[剣(金3牙1)+[斧(木2牙1)+[剣(木2牙1)+双短剣(鉄10皮1)]]]]]]] 鍛冶Lv66
|
140
|
+
斧(火玉5綿1)+[杖(鉄2綿1)+[斧(木1金3)+[杖(綿1綿1)+[斧(玉5綿1)+[剣(金3牙1)+[双短剣(金3牙1)+[斧(木2牙1)+剣(鉄10木1)]]]]]]] 鍛冶Lv94
|
141
|
+
斧(木2皮1)+[杖(鉄2綿1)+[斧(木1金3)+[杖(綿1綿1)+[斧(玉5玉5)+[剣(金3牙1)+[双短剣(金3牙1)+[斧(木2牙1)+剣(鉄10木1)]]]]]]] 鍛冶Lv106
|
142
|
+
斧(木2皮1)+[杖(鉄2綿1)+[斧(玉5金3)+[杖(綿1綿1)+[斧(玉5金3)+[剣(金3牙1)+[斧(木2牙1)+[剣(木2牙1)+双短剣(鉄10木1)]]]]]]] 鍛冶Lv116
|
143
|
+
斧(金3水1)+[杖(水1綿1)+[斧(金3水1)+[杖(綿1綿1)+[斧(玉5金3)+[剣(金3牙1)+[双短剣(金3牙1)+[斧(木2牙1)+剣(鉄10木1)]]]]]]] 鍛冶Lv152
|
144
|
+
EOS
|
145
|
+
rs = str.split(/\n/).map do |line|
|
146
|
+
ary = line.split(/ /)
|
147
|
+
ary[0].to_recipe(:atkstr, target_weight: 9, name: ary[1])
|
148
|
+
end
|
149
|
+
res = Mgmg.efficient_list(rs, 20_000, 50_000, './csv.csv', external_encoding: 'Windows-31J')
|
150
|
+
puts res.map(&:name).join(', ')
|
151
|
+
#=> 鍛冶Lv106, 鍛冶Lv94, 鍛冶Lv116
|
152
|
+
```
|
153
|
+
|
135
154
|
各メソッドの詳しい説明等は [リファレンス](./reference.md) を参照されたい.
|
136
155
|
|
137
156
|
### 表記ゆれについて
|
data/lib/mgmg/recipe.rb
CHANGED
@@ -1,14 +1,23 @@
|
|
1
1
|
module Mgmg
|
2
2
|
class Recipe
|
3
|
-
def initialize(recipe, para=:power, **kw)
|
3
|
+
def initialize(recipe, para=:power, name: nil, **kw)
|
4
4
|
@recipe = recipe
|
5
5
|
@recipe.each(&:freeze) if @recipe.kind_of?(Enumerable)
|
6
6
|
@recipe.freeze
|
7
7
|
@para = para
|
8
|
+
if name.nil?
|
9
|
+
if recipe.kind_of?(String)
|
10
|
+
@name = recipe
|
11
|
+
else
|
12
|
+
@name = recipe.join(' ')
|
13
|
+
end
|
14
|
+
else
|
15
|
+
@name = name
|
16
|
+
end
|
8
17
|
@option = Option.new(**kw).set_default(@recipe)
|
9
18
|
end
|
10
19
|
attr_reader :recipe
|
11
|
-
attr_accessor :para
|
20
|
+
attr_accessor :para, :name
|
12
21
|
def initialize_copy(other)
|
13
22
|
@recipe = other.recipe.dup
|
14
23
|
@option = other.option.dup
|
@@ -82,9 +91,9 @@ module Mgmg
|
|
82
91
|
smith, armor, comp = opt.smith_min, opt.armor_min, opt.comp_min if smith.nil?
|
83
92
|
case @recipe
|
84
93
|
when String
|
85
|
-
recipe.show(smith, comp, para:, opt:)
|
94
|
+
@recipe.show(smith, comp, para:, name: @name, opt:)
|
86
95
|
when Enumerable
|
87
|
-
recipe.show(smith, armor, comp, para:, opt:)
|
96
|
+
@recipe.show(smith, armor, comp, para:, name: @name, opt:)
|
88
97
|
else
|
89
98
|
raise BrokenRecipeError
|
90
99
|
end
|
data/lib/mgmg/search.rb
CHANGED
@@ -110,16 +110,18 @@ class String
|
|
110
110
|
end
|
111
111
|
exp_best = opt.cut_exp
|
112
112
|
diff = values.max-values.min
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
113
|
+
if 0 < diff
|
114
|
+
opt.cut_exp = exp_best + diff*opt.fib_ext[0]
|
115
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
116
|
+
exp_best, ret = fine(exp_best, ret, para, target, comp, opt, eo)
|
117
|
+
rescue Mgmg::SearchCutException
|
118
|
+
break
|
119
|
+
end
|
120
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
121
|
+
exp_best, ret = fine(exp_best, ret, para, target, comp, opt, eo)
|
122
|
+
rescue Mgmg::SearchCutException
|
123
|
+
break
|
124
|
+
end
|
123
125
|
end
|
124
126
|
if ret.nil?
|
125
127
|
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
@@ -177,18 +179,20 @@ class String
|
|
177
179
|
end
|
178
180
|
end
|
179
181
|
diff = values.max-values.min
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
182
|
+
if 0 < diff
|
183
|
+
th = max - diff*opt.fib_ext[1]
|
184
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
185
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
186
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
187
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
188
|
+
break if cur < th
|
189
|
+
end
|
190
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
191
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
192
|
+
cur, smith = eval_comp_fm(para, comp, eo, opt, max, max_exp)
|
193
|
+
ret, max = [smith, comp], cur if ( max < cur || ( max == cur && Mgmg.exp(smith, comp) < Mgmg.exp(*ret) ) )
|
194
|
+
break if cur < th
|
195
|
+
end
|
192
196
|
end
|
193
197
|
ret
|
194
198
|
end
|
@@ -342,12 +346,12 @@ module Enumerable
|
|
342
346
|
raise Mgmg::SearchCutException, "#{self} could not reach target=#{target} until (smith_max, armor_max, comp_max)=(#{opt.smith_max}, #{opt.armor_max}, #{opt.comp_max}), which yields #{foo.comma3}"
|
343
347
|
end
|
344
348
|
opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
|
345
|
-
opt.smith_max = smith_search(para, target, opt.armor_min, opt.comp_min, opt: opt_nocut) rescue
|
346
|
-
opt.armor_max = armor_search(para, target, opt.smith_min, opt.comp_min, opt: opt_nocut) rescue
|
349
|
+
opt.smith_max = ( smith_search(para, target, opt.armor_min, opt.comp_min, opt: opt_nocut) rescue opt.smith_max )
|
350
|
+
opt.armor_max = ( armor_search(para, target, opt.smith_min, opt.comp_min, opt: opt_nocut) rescue opt.armor_max )
|
347
351
|
opt.smith_min = smith_search(para, target, opt.armor_max, opt.comp_max, opt: opt_nocut)
|
348
352
|
opt.armor_min = armor_search(para, target, opt.smith_max, opt.comp_max, opt: opt_nocut)
|
349
353
|
raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
|
350
|
-
opt.comp_max = comp_search(para, target, opt.smith_min, opt.armor_min, opt:)
|
354
|
+
opt.comp_max = ( comp_search(para, target, opt.smith_min, opt.armor_min, opt:) rescue opt.comp_max )
|
351
355
|
exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_max)
|
352
356
|
opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp <= opt.cut_exp
|
353
357
|
eo = opt.irep.eo_para(para)
|
@@ -374,16 +378,18 @@ module Enumerable
|
|
374
378
|
end
|
375
379
|
exp_best = opt.cut_exp
|
376
380
|
diff = values.max-values.min
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
381
|
+
if 0 < diff
|
382
|
+
opt.cut_exp = exp_best + diff*opt.fib_ext[0]
|
383
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
384
|
+
exp_best, ret = fine_sa(exp_best, ret, para, target, comp, opt, eo)
|
385
|
+
rescue Mgmg::SearchCutException
|
386
|
+
break
|
387
|
+
end
|
388
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
389
|
+
exp_best, ret = fine_sa(exp_best, ret, para, target, comp, opt, eo)
|
390
|
+
rescue Mgmg::SearchCutException
|
391
|
+
break
|
392
|
+
end
|
387
393
|
end
|
388
394
|
if ret.nil?
|
389
395
|
max = opt.irep.para_call(para, *find_max(para, opt.cut_exp, opt:))
|
@@ -439,16 +445,18 @@ module Enumerable
|
|
439
445
|
end
|
440
446
|
end
|
441
447
|
diff = a_vals.max-a_vals.min
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
448
|
+
if 0 < diff
|
449
|
+
th = max - diff*opt.fib_ext[1]
|
450
|
+
(arms[0]-1).downto(opt.armor_min) do |armor|
|
451
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
452
|
+
break if cur_i < th
|
453
|
+
cur = cur_i if cur < cur_i
|
454
|
+
end
|
455
|
+
(arms[3]+1).upto(a_max) do |armor|
|
456
|
+
cur_i, ret, max = eval_arm(para, armor, comp, eo, opt, ret, max, max_exp)
|
457
|
+
break if cur_i < th
|
458
|
+
cur = cur_i if cur < cur_i
|
459
|
+
end
|
452
460
|
end
|
453
461
|
[cur, ret, max]
|
454
462
|
end
|
@@ -479,16 +487,18 @@ module Enumerable
|
|
479
487
|
end
|
480
488
|
end
|
481
489
|
diff = values.max-values.min
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
490
|
+
if 0 < diff
|
491
|
+
th = max - diff*opt.fib_ext[1]
|
492
|
+
(comps[0]-1).downto(opt.comp_min) do |comp|
|
493
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
494
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
495
|
+
break if cur < th
|
496
|
+
end
|
497
|
+
(comps[3]+1).upto(opt.comp_max) do |comp|
|
498
|
+
next if ( eo & (2**(comp&1)) == 0 )
|
499
|
+
cur, ret, max = eval_comp_fm(para, comp, eo, opt, ret, max, max_exp)
|
500
|
+
break if cur < th
|
501
|
+
end
|
492
502
|
end
|
493
503
|
ret
|
494
504
|
end
|
@@ -669,4 +679,81 @@ module Mgmg
|
|
669
679
|
pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
|
670
680
|
[sca, ea, pa, scb, eb, pb]
|
671
681
|
end
|
682
|
+
|
683
|
+
class ELItem
|
684
|
+
def initialize(recipe=nil, sc=nil)
|
685
|
+
if recipe.nil?
|
686
|
+
@para = -Float::INFINITY
|
687
|
+
@exp = Float::INFINITY
|
688
|
+
else
|
689
|
+
@recipe = recipe
|
690
|
+
if sc.size == 3
|
691
|
+
@smith, @armor, @comp = *sc
|
692
|
+
else
|
693
|
+
if recipe.option.irep.kind < 8
|
694
|
+
@smith, @comp = *sc
|
695
|
+
@armor = -1
|
696
|
+
else
|
697
|
+
@armor, @comp = *sc
|
698
|
+
@smith = -1
|
699
|
+
end
|
700
|
+
end
|
701
|
+
@para = recipe.para_call(*sc)
|
702
|
+
@exp = Mgmg.exp(*sc)
|
703
|
+
@name = recipe.name
|
704
|
+
end
|
705
|
+
end
|
706
|
+
attr_reader :recipe, :smith, :armor, :comp, :para, :exp, :name
|
707
|
+
%i|attack phydef magdef hp mp str dex speed magic atkstr atk_sd dex_as mag_das magic2 magmag pmdef hs|.each do |sym|
|
708
|
+
define_method(sym) do
|
709
|
+
@recipe.para_call(@smith, @armor, @comp, para: sym)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
def weight
|
713
|
+
@recipe.build(@smith, @armor, @comp).weight
|
714
|
+
end
|
715
|
+
end
|
716
|
+
private_module_function def _el_sub(f, recipes, start, term, params, header, separator)
|
717
|
+
tag, ret = start, []
|
718
|
+
f.puts params.join(separator) if header && !f.nil?
|
719
|
+
while tag < term
|
720
|
+
best = ELItem.new()
|
721
|
+
recipes.each do |r|
|
722
|
+
cur = ELItem.new(r, r.search(tag))
|
723
|
+
if cur.exp < best.exp
|
724
|
+
best = cur
|
725
|
+
elsif cur.exp == best.exp
|
726
|
+
if best.para < cur.para
|
727
|
+
best = cur
|
728
|
+
elsif best.para == cur.para
|
729
|
+
if block_given?
|
730
|
+
best = cur if yield(best, cur)
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|
734
|
+
end
|
735
|
+
f.puts( params.map do |sym|
|
736
|
+
best.method(sym).call
|
737
|
+
end.join(separator) ) unless f.nil?
|
738
|
+
ret << best.recipe unless ret.include?(best.recipe)
|
739
|
+
tag = best.para+Eighth
|
740
|
+
end
|
741
|
+
ret
|
742
|
+
end
|
743
|
+
module_function def efficient_list(recipes, start, term, out=nil, params=[:defaults], separator: ',', header: true, **kw)
|
744
|
+
i = params.index(:defaults)
|
745
|
+
if i
|
746
|
+
params[i] = [:smith, :armor, :comp, :exp, :para, :name]
|
747
|
+
params.flatten!
|
748
|
+
end
|
749
|
+
ret = nil
|
750
|
+
if out.kind_of?(String)
|
751
|
+
File.open(out, 'w', **kw) do |f|
|
752
|
+
ret = _el_sub(f, recipes, start, term, params, header, separator)
|
753
|
+
end
|
754
|
+
else
|
755
|
+
ret = _el_sub(nil, recipes, start, term, params, header, separator)
|
756
|
+
end
|
757
|
+
ret
|
758
|
+
end
|
672
759
|
end
|
data/lib/mgmg/utils.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
module Mgmg
|
2
2
|
module Refiner
|
3
|
+
refine Module do
|
4
|
+
private def private_module_function(sym)
|
5
|
+
module_function(sym)
|
6
|
+
singleton_class.instance_eval do
|
7
|
+
private(sym)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
3
11
|
refine Integer do
|
4
12
|
def comma3
|
5
13
|
self.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,')
|
data/lib/mgmg/version.rb
CHANGED
data/lib/mgmg.rb
CHANGED
@@ -117,18 +117,19 @@ class String
|
|
117
117
|
def peff(para, smith, comp=smith, opt: Mgmg::Option.new)
|
118
118
|
poly(para, opt:).eff(smith, comp)
|
119
119
|
end
|
120
|
-
def show(smith=-1, comp=smith, para: :power, opt: Mgmg::Option.new)
|
120
|
+
def show(smith=-1, comp=smith, para: :power, name: nil, opt: Mgmg::Option.new)
|
121
121
|
rein = case opt.reinforcement
|
122
122
|
when Array
|
123
123
|
opt.reinforcement.map{|r| Mgmg::Reinforcement.compile(r)}
|
124
124
|
else
|
125
125
|
[Mgmg::Reinforcement.compile(opt.reinforcement)]
|
126
126
|
end
|
127
|
+
name = self if name.nil?
|
127
128
|
built = build(smith, comp, opt:)
|
128
129
|
pstr = '%.3f' % built.para_call(para)
|
129
130
|
pstr.sub!(/\.?0+\Z/, '')
|
130
131
|
puts "With levels (#{smith}, #{comp}: #{Mgmg.exp(smith, comp).comma3}), building"
|
131
|
-
puts " #{
|
132
|
+
puts " #{name}"
|
132
133
|
rein = rein.empty? ? '' : "reinforced by {#{rein.join(',')}} "
|
133
134
|
puts "#{rein}yields (#{pstr}, #{built.total_cost})"
|
134
135
|
puts " #{built}"
|
@@ -155,31 +156,36 @@ module Enumerable
|
|
155
156
|
opt = opt.dup
|
156
157
|
rein = opt.reinforcement
|
157
158
|
opt.reinforcement = []
|
158
|
-
self.
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
str.build(
|
163
|
-
|
164
|
-
|
159
|
+
if self.empty?
|
160
|
+
Mgmg::Equip::Zero
|
161
|
+
else
|
162
|
+
self.sum(Mgmg::Equip::Zero) do |str|
|
163
|
+
if Mgmg::EquipPosition[str.build(opt:).kind] == 0
|
164
|
+
str.build(smith, comp, opt:)
|
165
|
+
else
|
166
|
+
str.build(armor, comp, opt:)
|
167
|
+
end
|
168
|
+
end.reinforce(*rein)
|
169
|
+
end
|
165
170
|
end
|
166
171
|
def ir(opt: Mgmg::Option.new)
|
167
172
|
self.sum(Mgmg::IR::Zero) do |str|
|
168
173
|
str.ir(opt:)
|
169
174
|
end.add_reinforcement(opt.reinforcement)
|
170
175
|
end
|
171
|
-
def show(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: :power, opt: Mgmg::Option.new)
|
176
|
+
def show(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: :power, name: nil, opt: Mgmg::Option.new)
|
172
177
|
rein = case opt.reinforcement
|
173
178
|
when Array
|
174
179
|
opt.reinforcement.map{|r| Mgmg::Reinforcement.compile(r)}
|
175
180
|
else
|
176
181
|
[Mgmg::Reinforcement.compile(opt.reinforcement)]
|
177
182
|
end
|
183
|
+
name = self.join(' ') if name.nil?
|
178
184
|
built = self.build(smith, armor, comp, opt:)
|
179
185
|
pstr = '%.3f' % built.para_call(para)
|
180
186
|
pstr.sub!(/\.?0+\Z/, '')
|
181
187
|
puts "With levels (#{smith}, #{armor}, #{comp}: #{Mgmg.exp(smith, armor, comp).comma3}), building"
|
182
|
-
puts " #{
|
188
|
+
puts " #{name}"
|
183
189
|
rein = rein.empty? ? '' : "reinforced by {#{rein.join(',')}} "
|
184
190
|
puts "#{rein}yields (#{pstr}, #{built.total_cost})"
|
185
191
|
puts " #{built}"
|
data/reference.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
# リファレンス
|
2
2
|
本ライブラリで定義される主要なメソッドを以下に解説します.
|
3
3
|
|
4
|
-
## `String#to_recipe(para=:power, allow_over20: false, **kw)`,`Enumerable#to_recipe(para=:power, allow_over20: false, **kw)`
|
4
|
+
## `String#to_recipe(para=:power, allow_over20: false, name: nil, **kw)`,`Enumerable#to_recipe(para=:power, allow_over20: false, name: nil, **kw)`
|
5
5
|
レシピ文字列である`self`と,注目パラメータ`para`,オプション`Mgmg.option(**kw)`をセットにした[後述](#mgmgrecipe)の`Mgmg::Recipe`オブジェクトを生成して返します.デフォルト値としてセットされたパラメータを使用する以外は,レシピ文字列と同様に扱えます.
|
6
6
|
|
7
7
|
`allow_over20`が偽の場合,レシピの☆を確認し,20を超える場合は,例外`Mgmg::Over20Error`を発生します.このチェックを抑制したい場合は,真にしてください.
|
8
8
|
|
9
|
+
`name`は,一部のメソッドでレシピ文字列の代わりに使われる文字列を指定します.デフォルト値の`nil`の場合,`String`なら`self`,`Enumerable`なら`self.join(' ')`になります.
|
10
|
+
|
9
11
|
## `String#build(smith=-1, comp=smith, opt: Mgmg.option())`
|
10
12
|
レシピ文字列である`self`を解釈し,鍛冶・防具製作Lvを`smith`,道具製作Lvを`comp`として鍛冶・防具製作及び武器・防具合成を行った結果を[後述](#mgmgequip)の`Mgmg::Equip`クラスのインスタンスとして生成し,返します.例えば,
|
11
13
|
```ruby
|
@@ -108,7 +110,7 @@
|
|
108
110
|
|
109
111
|
`opt`は,`left_associative`と`include_system_equips`,`reinforcement`を使用します.
|
110
112
|
|
111
|
-
## `String#
|
113
|
+
## `String#smith_search(para, target, comp, opt: Mgmg.option())`
|
112
114
|
`para`の値が`target`以上となるのに必要な最小の鍛冶・防具製作Lvを二分探索で探索して返します.
|
113
115
|
道具製作Lvは`comp`で固定,鍛冶・防具製作Lvを`opt.smith_min`と`opt.smith_max`で挟み込んで探索します.
|
114
116
|
|
@@ -123,16 +125,16 @@
|
|
123
125
|
`opt`は,上記の他に`left_associative`,`reinforcement`,`irep`を使用します.
|
124
126
|
|
125
127
|
## `String#comp_search(para, target, smith, opt: Mgmg.option())`
|
126
|
-
`String#
|
128
|
+
`String#smith_search`とは逆に,鍛冶・防具製作Lvを固定して最小の道具製作Lvを探索します.
|
127
129
|
探索の起点である`opt.comp_min`のデフォルト値は,製作に必要な最小の道具製作Lv (`self.min_comp`)です.
|
128
|
-
その他は`String#
|
130
|
+
その他は`String#smith_search`と同様です.
|
129
131
|
|
130
132
|
`opt`は,`comp_min`,`comp_max`,`left_associative`,`reinforcement`,`irep`を使用します.
|
131
133
|
|
132
134
|
## `String#search(para, target, opt: Mgmg.option())`
|
133
135
|
合計経験値が最小となる鍛冶・防具製作Lvと道具製作Lvの組を探索します.道具製作Lvを決定変数として,`smith_search`の返り値との合計経験値を最小化する道具製作Lvをフィボナッチ探索で探索した後,得られた解 c の前後を探索し,最適化します.このとき,道具製作Lv c における合計経験値`exp`,及びフィボナッチ探索で得られた最後の4点の経験値の最大値`exp2`に対して,`exp+(exp2-exp)*opt.fib_ext[0]`を超えない範囲を探索します.この目的関数は単峰ではないため,フィボナッチ探索のみでは最適解が得られないことがあります.
|
134
136
|
|
135
|
-
その他は`String#
|
137
|
+
その他は`String#smith_search`と同様で,`opt`は,`String#smith_search`または`String#comp_search`で使われるすべてのパラメータと,`fib_ext`を使用します.
|
136
138
|
|
137
139
|
## `Enumerable#search(para, target, opt: Mgmg.option())`
|
138
140
|
複数装備の組について,`para`の値が`target`以上となる最小経験値の`[鍛冶Lv,防具製作Lv,道具製作Lv]`を返します.
|
@@ -140,7 +142,7 @@
|
|
140
142
|
|
141
143
|
`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`です.
|
142
144
|
|
143
|
-
その他は,`String#
|
145
|
+
その他は,`String#search`と同様です.
|
144
146
|
|
145
147
|
## `String#find_max(para, max_exp, opt: Mgmg.option())`
|
146
148
|
経験値の合計が`max_exp`以下の範囲で,`para`の値が最大となる鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.`para`の値が最大となる組が複数存在する場合,経験値が小さい方が優先されます.
|
@@ -165,6 +167,46 @@
|
|
165
167
|
|
166
168
|
`opt_a`,`opt_b`は,`Mgmg.#find_lowerbound`と同様です.
|
167
169
|
|
170
|
+
## `Mgmg.#efficient_list(recipes, start, term, out=nil, params=[:defaults], separator: ',', header: true, **kw){|former, latter| ...}`
|
171
|
+
目標値`start`から`term`までにおいて,最も効率の良いレシピとそのときのpara値を求め,一覧にしたcsvファイルを出力します.
|
172
|
+
`recipes`のうち,一度でも最適レシピに選ばれたものを抽出した配列を返します.
|
173
|
+
|
174
|
+
具体的には,以下のように動作します.
|
175
|
+
`Mgmg::Recipe`の配列`recipes`の各要素`r`に対し,`r.search(start)`を実行し,総経験値が最も少なくなる`r_best`を求めます.
|
176
|
+
`r_best`の行を出力した後,目標値を`r_best.para_call(*r_best.search(start))+1.quo(8)`に変更し,目標値が`term`を超えるまで繰り返します.
|
177
|
+
|
178
|
+
結果は`out`に出力します.`out`が`String`の場合,ファイルパスとみなし,`File.open(out, 'w', **kw)`に対して出力します.
|
179
|
+
`out`が`nil`の場合,csvファイルは出力しません.その他の場合,`out.puts`により,`out`そのものに書き込みます.
|
180
|
+
|
181
|
+
`params`には,出力したい項目名の`Symbol`を並べた配列を指定します.`:defaults`は,自動的に`:smith, :armor, :comp, :exp, :para, :name`に展開され,
|
182
|
+
それぞれ鍛冶Lv,防具製作Lv,道具製作Lv,総経験値,para値,レシピ名です.その他,
|
183
|
+
`:weight`, `:attack`, `:phydef`, `:magdef`, `:hp`, `:mp`, `:str`, `:dex`, `:speed`, `:magic`, `:atkstr`, `:atk_sd`, `:dex_as`, `:mag_das`, `:magic2`, `:magmag`, `:pmdef`, `:hs`
|
184
|
+
が指定でき,各製作Lvでの個別のパラメータを出力できます.
|
185
|
+
|
186
|
+
`separator`は,項目間の区切り文字を指定します.`header`が真の場合,1行目に,項目名を並べたヘッダを出力します.不要な場合は偽を指定してください.
|
187
|
+
残りの`kw`は,`File.open(out, 'w', **kw)`にそのまま渡されます.出力結果をExcelで開く場合には`external_encoding: "Windows-31J"`などを指定します.
|
188
|
+
`out`が`String`でない場合は,`kw`は無視されます.
|
189
|
+
|
190
|
+
ブロック付きで呼び出した場合,ブロックの評価でタイブレイクを行います.必要な経験値が同じだった場合,para値が大きい方を優先しますが,para値も同じ場合,
|
191
|
+
`recipes`の並びで前の方を`former`,後ろの方を`latter`としてブロックを実行します.`yield(former, latter)`が真なら`latter`を,偽なら`former`を優先します.
|
192
|
+
`fomer`,`latter`は,`Mgmg::ELItem`インスタンスであり,`params`に指定できる項目がそのままメソッド名として定義されている他,
|
193
|
+
`Mgmg::ELItem#recipe`により,`recipes`の要素として渡したレシピオブジェクトを取り出せます.
|
194
|
+
例えば,双短剣のレシピを比較していて,para値として指定した威力が同じ場合は器用さの高い方を,それも同じ場合は素早さが高い方を優先したい場合,以下のようにします.
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
Mgmg.efficient_list(recipes, start, term) do |former, latter|
|
198
|
+
if former.dex < latter.dex
|
199
|
+
true
|
200
|
+
elsif former.dex == latter.dex
|
201
|
+
former.speed < latter.speed
|
202
|
+
else
|
203
|
+
false
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
ブロックを指定していない場合,常に`former`が優先されます.
|
209
|
+
|
168
210
|
## `String#eff(para, smith, comp=smith, opt: Mgmg.option())`
|
169
211
|
[`smith`を1上げたときの`para`値/(`smith`を1上げるのに必要な経験値), `comp`を1上げたときの`para`値/(`comp`を2上げるのに必要な経験値)]を返します.
|
170
212
|
`para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
|
@@ -438,7 +480,7 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
438
480
|
### 引数4つ
|
439
481
|
調理法,主食材,副食材,料理Lvを指定し,対応する料理の効果の**概算値**を計算します.計算式は [Wikiの記述](https://wikiwiki.jp/guruguru/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0/%E9%A3%9F%E7%B3%A7%E5%93%81#y1576f2d) に基づきますが,正確ではないことがわかっています.例えば,`('蒸す', 'アースドラン', '氷河酒', 27)`の物防は87ですが,この計算式では88になります.調理法,主食材,副食材は文字列で,料理Lvは整数で指定します.
|
440
482
|
|
441
|
-
|
483
|
+
調理法は「焼き」か「蒸す」,主食材は「獣肉」「ウッチ」「ゴッチ」「ガガッチ」「ドランギョ」「ドラバーン」「フレドラン」「アースドラン」「アクアドラン」「ダークドン」,副食材は「氷酒」「氷水酒」「氷河酒」「カエン酒」「爆炎酒」「煉獄酒」のみ対応しています.攻撃,物防,魔防の強化を考える場合,これらで十分と判断しての選択となっています.
|
442
484
|
|
443
485
|
## `Mgmg::Option`
|
444
486
|
多くのメソッドのオプション引数をまとめるクラスです.このクラスのインスタンスを使ってそれぞれのメソッドに引き渡します.
|
@@ -446,7 +488,7 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
446
488
|
## `Mgmg.#option(recipe=nil, **kw)`
|
447
489
|
`kw`はキーワード引数本体です.定義されているキーワードと意味,使用される主なメソッドは下表の通りです.デフォルト値は簡易的な表示であり,細かい点では不正確です.
|
448
490
|
`recipe`にレシピ`String`または`Enumerable`を渡すと,そのレシピを使ってデフォルト値を具体化しますが,各メソッドで自動的に具体化されるため,通常は必要ありません.
|
449
|
-
`Defaults`対応が「対応」となっているキーワード引数については,`Mgmg::Option::Defaults[:include_system_equips]=false
|
491
|
+
`Defaults`対応が「対応」となっているキーワード引数については,`Mgmg::Option::Defaults[:include_system_equips]=false`などとすることで,デフォルト値をグローバルに変更することができます.デフォルト値にかかわらず,メソッド呼び出し時に個別に指定すればその値が優先されます.また,デフォルト値を変更しても,すでに生成された`Option`オブジェクトの値は変更されません.
|
450
492
|
|
451
493
|
|キーワード|デフォルト値|`Defaults`対応|意味|主なメソッド,備考|
|
452
494
|
|:-|:-|:-|:-|:-|
|
@@ -491,7 +533,7 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
491
533
|
`self.recipe.find_max`を呼び出して返します.注目パラメータはセットされたものを自動的に渡しますが,別のパラメータを使いたい場合,キーワード引数で指定します.その他のキーワード引数を与えた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
|
492
534
|
|
493
535
|
## `Mgmg::Recipe#min_level(w=self.option.target_weight, include_outsourcing=false)`
|
494
|
-
`self.recipe.min_level(w, include_outsourcing)`を返します.`w
|
536
|
+
`self.recipe.min_level(w, include_outsourcing)`を返します.`w`のデフォルト値が`target_weight`になっている以外は`String#min_level`または`Enumerable#min_level`と同じです.
|
495
537
|
|
496
538
|
## `Mgmg::Recipe#min_weight, max_weight, min_levels, min_levels_max, min_smith, min_comp`
|
497
539
|
`self.recipe`の同名メソッドをそのまま呼び出して返します.
|
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.8.
|
4
|
+
version: 1.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- KAZOON
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-19 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.
|
107
|
+
rubygems_version: 3.3.26
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: Calculate specs of equipments of Megurimeguru, a game produced by Kou.
|