mgmg 1.4.2 → 1.5.2
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 +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +41 -10
- data/lib/mgmg/equip.rb +19 -24
- data/lib/mgmg/ir.rb +5 -11
- data/lib/mgmg/optimize.rb +21 -9
- data/lib/mgmg/option.rb +84 -0
- data/lib/mgmg/recipe.rb +172 -0
- data/lib/mgmg/reinforce.rb +3 -3
- data/lib/mgmg/search.rb +204 -222
- data/lib/mgmg/system_equip.rb +4 -0
- data/lib/mgmg/utils.rb +53 -10
- data/lib/mgmg/version.rb +1 -1
- data/lib/mgmg.rb +181 -79
- data/mgmg.gemspec +4 -4
- data/reference.md +186 -49
- metadata +12 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 708daf16885a7532d26106458fbcabf1e043bfbbc0d6c8607af45a2e5b31ca45
|
4
|
+
data.tar.gz: 765e3c12305233d28ea32c8c13ea819bfe52849a393cc5dc64d3c4e54fbe3b70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d673f9054fe9a1c9ec2d771a699046eb457ddfbc08306355d2a64b988fd00b841e29edc8da7b9c00305423a255ca322a559eb7e8931463ef4ce6ebec63679ce8
|
7
|
+
data.tar.gz: 1b2374ffa189136a4b4036424a77660eef55401be88e06a00f9f6034354ae7ecfdf24eeb2b889c1f0df3049fb3978e63bb5ddb355acf4d165023feb9186446bb
|
data/CHANGELOG.md
CHANGED
@@ -120,3 +120,24 @@
|
|
120
120
|
- `Mgmg::Equip#reinforce`および`Mgmg::IR`を使うメソッド群に`reinforcement`キーワード引数を追加.
|
121
121
|
- スキルおよび料理による強化効果をシミュレートできるようになった.
|
122
122
|
- 料理については,プリセット料理名または`Mgmg.#cuisine`で生成される`Mgmg::Cuisine`オブジェクトを使う.
|
123
|
+
|
124
|
+
## 1.5.0 2022/06/22
|
125
|
+
- `Mgmg::Option`を実装し,search系メソッドを中心としたキーワード引数を,このクラスに集約してから受け渡すようにした.
|
126
|
+
- オプションオブジェクトは`Mgmg.#option`によって生成し,キーワード引数`opt`に渡す.従来のキーワード引数は廃止された.
|
127
|
+
- この変更で,一部の受け渡し忘れのバグが修正され,パフォーマンスが改善した.
|
128
|
+
- `Enumerable#search`で無駄な処理が発生していて,処理時間がかかっていたバグを修正.
|
129
|
+
- `String#min_level`,`Enumerable#min_level`の仕様を変更し,合成後の重量を目標値にするのに必要な鍛冶・道具製作Lvを計算するようにした.
|
130
|
+
- この変更に伴い,`Mgmg::Equip#min_level`を,`Mgmg::Equip#min_levels_max`に名称変更し,`String#min_levels_max`,`Enumerable#min_levels_max`を追加した.
|
131
|
+
- 関連して,`String#max_weight`,`String#min_weight`,`Enumerable#max_weight`,`Enumerable#min_weight`,`Enumerable#max_weights`,`Enumerable#min_weights`を追加した.
|
132
|
+
- `Mgmg::Option#smith_min`,`Mgmg::Option#armor_min`のデフォルト値を,`String#min_level`,`Enumerable#min_level`を用いて設定する仕様とし,その目標重量を`Mgmg::Option#target_weight`で指定するようにした.
|
133
|
+
- `String#min_comp`,`String#min_smith`,`Enumerable#min_comp`,`Enumerable#min_smith`において,既製品のみである,合成を行わないなど,該当スキルが必要ないレシピである場合の返り値を`-1`に変更した.
|
134
|
+
|
135
|
+
## 1.5.1 2022/06/24
|
136
|
+
- `Mgmg::Recipe`を実装し,レシピ`String`または`Enumerable`と,注目パラメータ`Symbol`,オプション`Mgmg::Option`をセットで取り扱えるようにした.
|
137
|
+
- `String#to_recipe(para=:power, allow_over20: false, **kw)`または`Enumerable#to_recipe(para=:power, **kw)`で生成できる.
|
138
|
+
- `Mgmg::Recipe#build`,`Mgmg::Recipe#search`など`String`等に対する操作と同様にでき,注目パラメータとオプションは,`to_recipe`でセットしたものがデフォルトで使われるようになる.各メソッド呼び出し時にキーワード引数を与えることで,一時的に上書きすることもできる.
|
139
|
+
- `String#to_recipe`にのみ,☆20制限のチェック機構を導入した.
|
140
|
+
- 計算を繰り返した際,複数装備の装備数が増加していってしまうバグを修正した.
|
141
|
+
|
142
|
+
## 1.5.2 2022/06/28
|
143
|
+
- `String#poly`が`:magic2`に対応していなかったバグを修正.
|
data/README.md
CHANGED
@@ -53,19 +53,36 @@ puts r.build(122, 139, 232)
|
|
53
53
|
#=> 複数装備9(武:1, 頭:1, 飾:2)[攻撃:15, 物防:34, 魔防:28, HP:241, MP:71, 器用:223, 素早:222, 魔力:6,604]
|
54
54
|
```
|
55
55
|
|
56
|
-
|
56
|
+
製作品の重量及び特定の重量にするために必要な鍛冶・防具製作Lvを確認する.
|
57
57
|
|
58
58
|
```ruby
|
59
|
-
|
60
|
-
|
59
|
+
r = 'サンダル(骨2皮1)+[重鎧(金3金3)+[フード(骨2宝1)+[重鎧(皮10金10)+軽鎧(鉄10皮1)]]]'
|
60
|
+
p r.min_levels # 各材料装備を重量1で作るのに必要な防具製作Lv
|
61
|
+
#=> {"サンダル(骨2皮1)"=>3, "重鎧(金3金3)"=>202, "フード(骨2宝1)"=>3, "重鎧(皮10金10)"=>162, "軽鎧(鉄10皮1)"=>68}
|
62
|
+
p r.min_levels(2) # 同重量2以下
|
63
|
+
#=> {"サンダル(骨2皮1)"=>3, "重鎧(金3金3)"=>102, "フード(骨2宝1)"=>3, "重鎧(皮10金10)"=>42, "軽鎧(鉄10皮1)"=>27}
|
64
|
+
p [r.min_weight, r.max_weight] # 最小重量と最大重量
|
65
|
+
#=> [5, 10]
|
66
|
+
p r.min_level # 最小重量で作るのに必要な防具製作Lv
|
67
|
+
#=> 202
|
68
|
+
p r.min_level(7) # 重量7以下で作るのに必要な防具製作Lv
|
69
|
+
#=> 102
|
70
|
+
p r.min_level(-1) # 最小重量+1=重量6以下で作るのに必要な防具製作Lv
|
71
|
+
#=> 162
|
61
72
|
```
|
62
73
|
|
63
|
-
|
74
|
+
注目パラメータやオプションパラメータを,レシピ文字列とセットにして取り回す.
|
64
75
|
```ruby
|
65
|
-
|
66
|
-
|
67
|
-
p
|
68
|
-
#=>
|
76
|
+
r = '[[斧(鉄10皮1)+剣(牙10皮1)]+剣(鉄10皮1)]+剣(鉄10皮1)'
|
77
|
+
r = r.to_recipe(:atkstr, target_weight: 5) # 注目パラメータを攻撃力+腕力,目標重量を5に設定
|
78
|
+
p [r.min_level, r.min_level(0)] # 必要な鍛冶Lvのデフォルトが目標重量ベースに
|
79
|
+
#=> [72, 168] # 鍛冶Lv72で重量5(目標)に,鍛冶Lv168で重量4(最小)になる
|
80
|
+
puts r.build(27, 42) # 変換前と同様に合成等もできる
|
81
|
+
#=> 斧8☆20(鉄鉄)[攻撃:1,112, 腕力:18] # 鍛冶Lv27だと重量8に
|
82
|
+
p r.para_call(27, 42) # 注目パラメータのみを計算
|
83
|
+
#=> 1130 # 1112+18=1130
|
84
|
+
puts r.build(nil) # 目標重量を達成する最小製作Lvで製作
|
85
|
+
#=> 斧5☆20(鉄鉄)[攻撃:1,436, 腕力:24] # 製作Lvを nil にすると,目標重量のための最小製作Lv (72, 42) で製作
|
69
86
|
```
|
70
87
|
|
71
88
|
近似多項式を得る.
|
@@ -91,16 +108,30 @@ p [sc, Mgmg.exp(*sc)]
|
|
91
108
|
#=> [[155, 376], 304969]
|
92
109
|
```
|
93
110
|
|
111
|
+
最小重量で製作できない鍛冶レベルを探索範囲に含める.
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
r = '双短剣(金3皮1)+[杖(水1綿1)+[斧(玉5水1)+[杖(鉄1綿1)+[[斧(木2金3)+剣(鉄10皮1)]+[剣(木2綿1)+双短剣(鉄10皮1)]]]]]'
|
115
|
+
r = r.to_recipe(:atk_sd, target_weight: 9)
|
116
|
+
sc = r.search(2000) # to_recipe で注目パラメータを入れているので,ここでは不要
|
117
|
+
p [sc, Mgmg.exp(*sc)]
|
118
|
+
#=> [[70, 130], 38046] # オプションなしの場合は鍛冶Lv100以上を探索するため,[[100, 126], 41054] になる
|
119
|
+
```
|
120
|
+
|
94
121
|
探索の際,スキル及び料理を考慮する.
|
95
122
|
|
96
123
|
```ruby
|
97
124
|
r = '重鎧(皮2綿1)+[帽子(宝1宝1)+[重鎧(玉5金3)+[帽子(宝1宝1)+[重鎧(玉5金6)+[軽鎧(金3骨1)+[重鎧(皮2骨1)+軽鎧(鉄10綿1)]]]]]]'
|
98
|
-
|
125
|
+
r = r.to_recipe(:phydef, buff: %w|物防御UP アースドランと氷河酒の蒸し焼き ガードアップ|)
|
126
|
+
sc = r.search(100_000)
|
99
127
|
p [sc, Mgmg.exp(*sc)]
|
100
128
|
#=> [[120, 264], 152502]
|
129
|
+
puts r.build(*sc) # 実際に作って確認
|
130
|
+
#=> 重鎧8☆20(綿宝)[物防:100,396.0, 魔防:4]
|
131
|
+
puts r.build(*sc, buff: []) # 一時的に強化を解除して素の性能を確認
|
132
|
+
#=> 重鎧8☆20(綿宝)[物防:32,538, 魔防:4]
|
101
133
|
```
|
102
134
|
|
103
|
-
|
104
135
|
各メソッドの詳しい説明等は [リファレンス](./reference.md) を参照されたい.
|
105
136
|
|
106
137
|
### 表記ゆれについて
|
data/lib/mgmg/equip.rb
CHANGED
@@ -13,7 +13,7 @@ module Mgmg
|
|
13
13
|
def initialize_copy(other)
|
14
14
|
@kind = other.kind
|
15
15
|
@weight = other.weight
|
16
|
-
@star = other.star
|
16
|
+
@star = other.star.dup
|
17
17
|
@main = other.main
|
18
18
|
@sub = other.sub
|
19
19
|
@para = other.para.dup
|
@@ -57,15 +57,15 @@ module Mgmg
|
|
57
57
|
@min_levels
|
58
58
|
else
|
59
59
|
@min_levels.map do |key, value|
|
60
|
-
[key,
|
60
|
+
[key, Equip.min_level(key, w)]
|
61
61
|
end.to_h
|
62
62
|
end
|
63
63
|
end
|
64
|
-
def
|
64
|
+
def min_levels_max(w=1)
|
65
65
|
if @kind == 28
|
66
|
-
ret = [
|
66
|
+
ret = [-1, -1]
|
67
67
|
min_levels(w).each do |str, ml|
|
68
|
-
if str.build
|
68
|
+
if str.build.kind < 8
|
69
69
|
if ret[0] < ml
|
70
70
|
ret[0] = ml
|
71
71
|
end
|
@@ -77,7 +77,7 @@ module Mgmg
|
|
77
77
|
end
|
78
78
|
ret
|
79
79
|
else
|
80
|
-
min_levels(w).values.append(
|
80
|
+
min_levels(w).values.append(-1).max
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -193,15 +193,9 @@ module Mgmg
|
|
193
193
|
def +(other)
|
194
194
|
self.dup.add!(other)
|
195
195
|
end
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
zero.history.clear
|
200
|
-
[zero, self]
|
201
|
-
else
|
202
|
-
raise TypeError, "Mgmg::Equip can't be coerced into other than 0"
|
203
|
-
end
|
204
|
-
end
|
196
|
+
Zero = self.new(28, 0, Vec.new(6, 0).freeze, 12, 12, Vec.new(9, 0).freeze, Vec.new(3, 0).freeze)
|
197
|
+
Zero.total_cost.freeze; Zero.history.clear.freeze
|
198
|
+
Zero.freeze
|
205
199
|
end
|
206
200
|
|
207
201
|
class << Equip
|
@@ -212,7 +206,7 @@ module Mgmg
|
|
212
206
|
end
|
213
207
|
private def build_sub0(stack, str)
|
214
208
|
SystemEquip.each do |k, v|
|
215
|
-
if
|
209
|
+
if SystemEquipRegexp[k].match(str)
|
216
210
|
stack << v
|
217
211
|
str = str.gsub(k, "<#{stack.length-1}>")
|
218
212
|
end
|
@@ -305,7 +299,7 @@ module Mgmg
|
|
305
299
|
|
306
300
|
ret = new(kind, ( weight<1 ? 1 : weight ), (main_s+sub_s).div(2), main_mc, sub_mc, para, ele)
|
307
301
|
ret.total_cost[kind < 8 ? 0 : 2] += ret.smith_cost(outsourcing)
|
308
|
-
ret.min_levels.store(str,
|
302
|
+
ret.min_levels.store(str, Equip.min_level(str))
|
309
303
|
ret
|
310
304
|
end
|
311
305
|
|
@@ -323,14 +317,14 @@ module Mgmg
|
|
323
317
|
[(main_s-1)*3, (sub_s-1)*3, l].max
|
324
318
|
end
|
325
319
|
|
326
|
-
def min_comp(str,
|
320
|
+
def min_comp(str, opt: Option.new)
|
327
321
|
str = Mgmg.check_string(str)
|
328
322
|
stack, str = minc_sub0([], str)
|
329
|
-
(minc_sub(stack, str, left_associative)[1]-1)*3
|
323
|
+
(minc_sub(stack, str, opt.left_associative)[1]-1)*3
|
330
324
|
end
|
331
325
|
private def minc_sub0(stack, str)
|
332
326
|
SystemEquip.each do |k, v|
|
333
|
-
if
|
327
|
+
if SystemEquipRegexp[k].match(str)
|
334
328
|
stack << v.star
|
335
329
|
str = str.gsub(k, "<#{stack.length-1}>")
|
336
330
|
end
|
@@ -352,14 +346,15 @@ module Mgmg
|
|
352
346
|
end
|
353
347
|
end
|
354
348
|
|
355
|
-
def min_smith(str,
|
349
|
+
def min_smith(str, opt: Option.new)
|
356
350
|
str = Mgmg.check_string(str)
|
357
351
|
stack, str = mins_sub0([], str)
|
358
|
-
(([mins_sub(stack, str, left_associative)]+stack).max-1)*3
|
352
|
+
ret = (([mins_sub(stack, str, opt.left_associative)]+stack).max-1)*3
|
353
|
+
ret < 0 ? -1 : ret
|
359
354
|
end
|
360
355
|
private def mins_sub0(stack, str)
|
361
356
|
SystemEquip.each do |k, v|
|
362
|
-
if
|
357
|
+
if SystemEquipRegexp[k].match(str)
|
363
358
|
stack << 0
|
364
359
|
str = str.gsub(k, "<#{stack.length-1}>")
|
365
360
|
end
|
@@ -373,7 +368,7 @@ module Mgmg
|
|
373
368
|
elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
|
374
369
|
[mins_sub(stack, m[1], lassoc), mins_sub(stack, m[2], lassoc)].max
|
375
370
|
elsif m = /\A\<(\d+)\>\Z/.match(str)
|
376
|
-
|
371
|
+
0
|
377
372
|
else
|
378
373
|
mins_sub2(str)
|
379
374
|
end
|
data/lib/mgmg/ir.rb
CHANGED
@@ -31,7 +31,7 @@ module Mgmg
|
|
31
31
|
((s+@sub9)*@coef).div(@den)
|
32
32
|
end
|
33
33
|
def evaluate3(s, a, c)
|
34
|
-
if sa==:a
|
34
|
+
if @sa==:a
|
35
35
|
((a+@sub9)*@coef).div(@den)
|
36
36
|
else
|
37
37
|
((s+@sub9)*@coef).div(@den)
|
@@ -152,7 +152,7 @@ module Mgmg
|
|
152
152
|
attr_accessor :kind, :star, :main, :sub, :para, :rein
|
153
153
|
def initialize_copy(other)
|
154
154
|
@kind = other.kind
|
155
|
-
@star = other.star
|
155
|
+
@star = other.star.dup
|
156
156
|
@main = other.main
|
157
157
|
@sub = other.sub
|
158
158
|
@para = other.para.dup
|
@@ -313,14 +313,8 @@ module Mgmg
|
|
313
313
|
def +(other)
|
314
314
|
self.dup.add!(other)
|
315
315
|
end
|
316
|
-
|
317
|
-
|
318
|
-
zero = self.class.new(28, Vec.new(6, 0), 12, 12, Array.new(9){Const.new(0)})
|
319
|
-
[zero, self]
|
320
|
-
else
|
321
|
-
raise TypeError, "Mgmg::IR can't be coerced into other than 0"
|
322
|
-
end
|
323
|
-
end
|
316
|
+
Zero = self.new(28, Vec.new(6, 0).freeze, 12, 12, Array.new(9){Const.new(0)}.freeze)
|
317
|
+
Zero.rein.freeze; Zero.freeze
|
324
318
|
end
|
325
319
|
class << IR
|
326
320
|
def build(str, left_associative: true, reinforcement: [])
|
@@ -330,7 +324,7 @@ module Mgmg
|
|
330
324
|
end
|
331
325
|
private def build_sub0(stack, str)
|
332
326
|
SystemEquip.each do |k, v|
|
333
|
-
if
|
327
|
+
if SystemEquipRegexp[k].match(str)
|
334
328
|
stack << from_equip(v)
|
335
329
|
str = str.gsub(k, "<#{stack.length-1}>")
|
336
330
|
end
|
data/lib/mgmg/optimize.rb
CHANGED
@@ -2,8 +2,12 @@ module Mgmg
|
|
2
2
|
module Optimize; end
|
3
3
|
class << Optimize
|
4
4
|
InvList = [%w|帽子 フード サンダル|.freeze, %w|宝1 骨1 木1 木2 骨2|.freeze, %w|宝1 骨1 木1|.freeze].freeze
|
5
|
-
def phydef_optimize(str, smith, comp=smith,
|
6
|
-
best =
|
5
|
+
def phydef_optimize(str, smith, comp=smith, opt: Option.new)
|
6
|
+
best = if smith.nil? then
|
7
|
+
[str, str.poly(:phydef, opt:), str.poly(:magdef, opt:), str.poly(:cost, opt:)]
|
8
|
+
else
|
9
|
+
[str, str.build(smith, comp, opt:)]
|
10
|
+
end
|
7
11
|
str = Mgmg.check_string(str)
|
8
12
|
ai = 0
|
9
13
|
while str.sub!(/(帽子|フード|サンダル)\([宝木骨][12][宝木骨]1\)/){
|
@@ -19,7 +23,7 @@ module Mgmg
|
|
19
23
|
m = /([^\+]*\([^\(]+[綿皮]1\))\]*\Z/.match(str)
|
20
24
|
if m
|
21
25
|
if smith
|
22
|
-
if m[1].sub(/綿1\)/, '皮1)').build(smith).weight == m[1].sub(/皮1\)/, '綿1)').build(smith).weight
|
26
|
+
if m[1].sub(/綿1\)/, '皮1)').build(smith, opt:).weight == m[1].sub(/皮1\)/, '綿1)').build(smith, opt:).weight
|
23
27
|
skin = true
|
24
28
|
end
|
25
29
|
else
|
@@ -35,7 +39,11 @@ module Mgmg
|
|
35
39
|
b = b0
|
36
40
|
while b
|
37
41
|
r = pd_apply_idx(str, a, b)
|
38
|
-
best =
|
42
|
+
best = if smith.nil? then
|
43
|
+
pd_better(best, [r, r.poly(:phydef, opt:), r.poly(:magdef, opt:), r.poly(:cost, opt:)], opt.magdef_maximize)
|
44
|
+
else
|
45
|
+
pd_better(best, [r, r.build(smith, comp, opt:)], opt.magdef_maximize)
|
46
|
+
end
|
39
47
|
b = pd_next_b(b)
|
40
48
|
end
|
41
49
|
a = pd_next_a(a)
|
@@ -49,7 +57,11 @@ module Mgmg
|
|
49
57
|
b = b0
|
50
58
|
while b
|
51
59
|
r = pd_apply_idx(str, a, b)
|
52
|
-
best =
|
60
|
+
best = if smith.nil? then
|
61
|
+
pd_better(best, [r, r.poly(:phydef, opt:), r.poly(:magdef, opt:), r.poly(:cost, opt:)], opt.magdef_maximize)
|
62
|
+
else
|
63
|
+
pd_better(best, [r, r.build(smith, comp, opt:)], opt.magdef_maximize)
|
64
|
+
end
|
53
65
|
b = pd_next_b(b)
|
54
66
|
end
|
55
67
|
a = pd_next_a(a)
|
@@ -102,7 +114,7 @@ module Mgmg
|
|
102
114
|
end
|
103
115
|
return pre
|
104
116
|
else
|
105
|
-
raise
|
117
|
+
raise UnexpectedError
|
106
118
|
end
|
107
119
|
end
|
108
120
|
private def pd_apply_idx(str, a, b)
|
@@ -146,8 +158,8 @@ module Mgmg
|
|
146
158
|
end
|
147
159
|
|
148
160
|
MwList = %w|綿 皮 骨 木 水|.freeze
|
149
|
-
def buster_optimize(str, smith, comp=smith,
|
150
|
-
best = ( smith.nil? ? [str, str.poly(:mag_das)] : [str, str.build(smith, comp)] )
|
161
|
+
def buster_optimize(str, smith, comp=smith, opt: Option.new)
|
162
|
+
best = ( smith.nil? ? [str, str.poly(:mag_das, opt:)] : [str, str.build(smith, comp, opt:)] )
|
151
163
|
str = Mgmg.check_string(str)
|
152
164
|
ai = -1
|
153
165
|
org = nil
|
@@ -162,7 +174,7 @@ module Mgmg
|
|
162
174
|
a = Array.new(ai){ [0, 0, 0] }
|
163
175
|
while a
|
164
176
|
r = bus_apply_idx(str, a)
|
165
|
-
best = bus_better(best, ( smith.nil? ? [r, r.poly(:mag_das)] : [r, r.build(smith, comp)] ))
|
177
|
+
best = bus_better(best, ( smith.nil? ? [r, r.poly(:mag_das, opt:)] : [r, r.build(smith, comp, opt:)] ))
|
166
178
|
a = bus_next_a(a)
|
167
179
|
end
|
168
180
|
best[0]
|
data/lib/mgmg/option.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
module Mgmg
|
2
|
+
class Option
|
3
|
+
def initialize(
|
4
|
+
left_associative: true,
|
5
|
+
smith_min: nil, armor_min:nil, comp_min: nil, smith_max: 10000, armor_max: 10000, comp_max: 10000,
|
6
|
+
step: 1, magdef_maximize: true,
|
7
|
+
target_weight: 0, reinforcement: [], buff: nil,
|
8
|
+
irep: nil, cut_exp: Float::INFINITY
|
9
|
+
)
|
10
|
+
@left_associative = left_associative
|
11
|
+
@smith_min = smith_min
|
12
|
+
@armor_min = armor_min
|
13
|
+
@comp_min = comp_min
|
14
|
+
@smith_max = smith_max
|
15
|
+
@armor_max = armor_max
|
16
|
+
@comp_max = comp_max
|
17
|
+
@step = step
|
18
|
+
@magdef_maximize = magdef_maximize
|
19
|
+
@target_weight = target_weight
|
20
|
+
@reinforcement = reinforcement
|
21
|
+
unless buff.nil?
|
22
|
+
if @reinforcement.empty?
|
23
|
+
@reinforcement = buff
|
24
|
+
else
|
25
|
+
raise ArgumentError, "reinforcement and buff are exclusive"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@irep = irep
|
29
|
+
@cut_exp = cut_exp
|
30
|
+
end
|
31
|
+
attr_accessor :left_associative, :smith_min, :armor_min, :comp_min, :smith_max, :armor_max, :comp_max
|
32
|
+
attr_accessor :step, :magdef_maximize, :target_weight, :reinforcement, :irep, :cut_exp
|
33
|
+
def initialize_copy(other)
|
34
|
+
@left_associative = other.left_associative
|
35
|
+
@smith_min = other.smith_min
|
36
|
+
@armor_min = other.armor_min
|
37
|
+
@comp_min = other.comp_min
|
38
|
+
@smith_max = other.smith_max
|
39
|
+
@armor_max = other.armor_max
|
40
|
+
@comp_max = other.comp_max
|
41
|
+
@step = other.step
|
42
|
+
@magdef_maximize = other.magdef_maximize
|
43
|
+
@target_weight = other.target_weight
|
44
|
+
@reinforcement = other.reinforcement.dup
|
45
|
+
@irep = other.irep
|
46
|
+
@cut_exp = other.cut_exp
|
47
|
+
end
|
48
|
+
def update_sa_min(recipe, force=true)
|
49
|
+
case recipe
|
50
|
+
when String
|
51
|
+
if @smith_min.nil? && @armor_min
|
52
|
+
@smith_min = @armor_min
|
53
|
+
end
|
54
|
+
if force || @smith_min.nil?
|
55
|
+
s = recipe.min_level(@target_weight, opt: self)
|
56
|
+
@smith_min = s if force || @smith_min.nil?
|
57
|
+
@armor_min = s if force || @armor_min.nil?
|
58
|
+
end
|
59
|
+
when Enumerable
|
60
|
+
if force || @smith_min.nil? || @armor_min.nil?
|
61
|
+
@target_weight = [@target_weight, @target_weight] if @target_weight.kind_of? Numeric
|
62
|
+
s, a = recipe.min_level(*@target_weight, opt: self)
|
63
|
+
@smith_min = s if force || @smith_min.nil?
|
64
|
+
@armor_min = a if force || @armor_min.nil?
|
65
|
+
end
|
66
|
+
else
|
67
|
+
raise ArgumentError, 'recipe should be String or Enumerable'
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
def set_default(recipe, force: false)
|
72
|
+
update_sa_min(recipe, force)
|
73
|
+
@comp_min = recipe.min_comp(opt: self) if force || @comp_min.nil?
|
74
|
+
@irep = recipe.ir(opt: self) if force || @irep.nil?
|
75
|
+
self
|
76
|
+
end
|
77
|
+
def buff
|
78
|
+
@reinforcement
|
79
|
+
end
|
80
|
+
def buff=(v)
|
81
|
+
@reinforcement = v
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/mgmg/recipe.rb
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
module Mgmg
|
2
|
+
class Recipe
|
3
|
+
def initialize(recipe, para=:power, **kw)
|
4
|
+
@recipe = recipe
|
5
|
+
@recipe.each(&:freeze) if @recipe.kind_of?(Enumerable)
|
6
|
+
@recipe.freeze
|
7
|
+
@para = para
|
8
|
+
@option = Option.new(**kw).set_default(@recipe)
|
9
|
+
end
|
10
|
+
attr_reader :recipe
|
11
|
+
attr_accessor :para
|
12
|
+
def initialize_copy(other)
|
13
|
+
@recipe = other.recipe.dup
|
14
|
+
@option = other.option.dup
|
15
|
+
end
|
16
|
+
private def temp_opt(**kw)
|
17
|
+
if kw.empty?
|
18
|
+
@option
|
19
|
+
else
|
20
|
+
ret = @option.dup
|
21
|
+
kw.each do |key, value|
|
22
|
+
ret.method((key.to_s+'=').to_sym).call(value)
|
23
|
+
ret.update_sa_min(@recipe) if key == :target_weight
|
24
|
+
ret.irep.add_reinforcement(value) if key == :reinforcement || key == :buff
|
25
|
+
if key == :left_associative
|
26
|
+
ret.irep = @recipe.ir(opt: ret).add_reinforcement(ret.reinforcement)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
ret
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def option(**kw)
|
33
|
+
@option = temp_opt(*kw)
|
34
|
+
@option
|
35
|
+
end
|
36
|
+
def option=(new_option)
|
37
|
+
@option = new_option.set_default(@recipe)
|
38
|
+
end
|
39
|
+
def replace(new_recipe, para: @para, **kw)
|
40
|
+
@recipe = new_recipe
|
41
|
+
@recipe.each(&:freeze) if @recipe.kind_of?(Enumerable)
|
42
|
+
@recipe.freeze
|
43
|
+
@para = para
|
44
|
+
@option = Option.new(**kw).set_default(@recipe)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
def min_weight
|
48
|
+
@recipe.min_weight(opt: @option)
|
49
|
+
end
|
50
|
+
def max_weight(include_outsourcing=false)
|
51
|
+
@recipe.max_weight(opt: @option)
|
52
|
+
end
|
53
|
+
def min_level(w=@option.target_weight, include_outsourcing=false)
|
54
|
+
@recipe.min_level(w, include_outsourcing, opt: @option)
|
55
|
+
end
|
56
|
+
def min_levels(w=1)
|
57
|
+
@recipe.min_levels(w, opt: @option)
|
58
|
+
end
|
59
|
+
def min_levels_max(w=1)
|
60
|
+
@recipe.min_levels_max(w, opt: @option)
|
61
|
+
end
|
62
|
+
def min_smith
|
63
|
+
@recipe.min_smith
|
64
|
+
end
|
65
|
+
def min_comp
|
66
|
+
@recipe.min_comp
|
67
|
+
end
|
68
|
+
def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, **kw)
|
69
|
+
opt = temp_opt(**kw)
|
70
|
+
smith, armor, comp = opt.smith_min, opt.armor_min, opt.comp_min if smith.nil?
|
71
|
+
case @recipe
|
72
|
+
when String
|
73
|
+
recipe.build(smith, comp, opt:)
|
74
|
+
when Enumerable
|
75
|
+
recipe.build(smith, armor, comp, opt:)
|
76
|
+
else
|
77
|
+
raise BrokenRecipeError
|
78
|
+
end
|
79
|
+
end
|
80
|
+
def show(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: @para, **kw)
|
81
|
+
opt = temp_opt(**kw)
|
82
|
+
smith, armor, comp = opt.smith_min, opt.armor_min, opt.comp_min if smith.nil?
|
83
|
+
case @recipe
|
84
|
+
when String
|
85
|
+
recipe.show(smith, comp, para:, opt:)
|
86
|
+
when Enumerable
|
87
|
+
recipe.show(smith, armor, comp, para:, opt:)
|
88
|
+
else
|
89
|
+
raise BrokenRecipeError
|
90
|
+
end
|
91
|
+
end
|
92
|
+
def search(target, para: @para, **kw)
|
93
|
+
opt = temp_opt(**kw)
|
94
|
+
@recipe.search(para, target, opt:)
|
95
|
+
end
|
96
|
+
private def correct_level(s, ac, x, opt)
|
97
|
+
if s.nil?
|
98
|
+
if x.equal?(false)
|
99
|
+
s, ac, x = opt.smith_min, opt.comp_min, nil
|
100
|
+
else
|
101
|
+
s, ac, x = opt.smith_min, opt.armor_min, opt.comp_min
|
102
|
+
end
|
103
|
+
else
|
104
|
+
s = 0 if s < 0
|
105
|
+
ac = 0 if ac < 0
|
106
|
+
if x.equal?(false)
|
107
|
+
x = nil
|
108
|
+
else
|
109
|
+
x = 0 if x < 0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
[s, ac, x]
|
113
|
+
end
|
114
|
+
def para_call(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: @para, **kw)
|
115
|
+
opt = temp_opt(**kw)
|
116
|
+
smith, armor, comp = correct_level(smith, armor, comp, opt)
|
117
|
+
case @recipe
|
118
|
+
when String
|
119
|
+
opt.irep.para_call(para, smith, comp)
|
120
|
+
when Enumerable
|
121
|
+
opt.irep.para_call(para, smith, armor, comp)
|
122
|
+
else
|
123
|
+
raise InvalidRecipeError
|
124
|
+
end
|
125
|
+
end
|
126
|
+
def ir(**kw)
|
127
|
+
temp_opt(**kw).irep
|
128
|
+
end
|
129
|
+
%i|attack phydef magdef hp mp str dex speed magic atkstr atk_sd dex_as mag_das magic2 magmag pmdef|.each do |sym|
|
130
|
+
define_method(sym) do |s, ac=s, x=false, **kw|
|
131
|
+
s, ac, x = correct_level(s, ac, x, temp_opt(**kw))
|
132
|
+
ir(**kw).method(sym).call(s, ac, x)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
%i|power fpower|.each do |sym|
|
136
|
+
define_method(sym) do |s, a=s, c=a.tap{a=s}, **kw|
|
137
|
+
s, a, c = correct_level(s, a, c, temp_opt(**kw))
|
138
|
+
ir(**kw).method(sym).call(s, a, c)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
%i|smith_cost comp_cost cost|.each do |sym|
|
142
|
+
define_method(sym) do |s, c=s, outsourcing=false, **kw|
|
143
|
+
s, c, x = correct_level(s, c, false, temp_opt(**kw))
|
144
|
+
ir(**kw).method(sym).call(s, c, out_sourcing)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
def poly(para=@para, **kw)
|
148
|
+
opt = temp_opt(**kw)
|
149
|
+
if @recipe.kind_of?(String)
|
150
|
+
@recipe.poly(para, opt:)
|
151
|
+
else
|
152
|
+
raise InvalidRecipeError, "Mgmg::Recipe#poly is available only for String recipes."
|
153
|
+
end
|
154
|
+
end
|
155
|
+
def phydef_optimize(smith=nil, comp=smith, **kw)
|
156
|
+
opt = temp_opt(**kw)
|
157
|
+
if @recipe.kind_of?(String)
|
158
|
+
@recipe.phydef_optimize(smith, comp, opt:)
|
159
|
+
else
|
160
|
+
raise InvalidRecipeError, "Mgmg::Recipe#phydef_optimize is available only for String recipes."
|
161
|
+
end
|
162
|
+
end
|
163
|
+
def buster_optimize(smith=nil, comp=smith, **kw)
|
164
|
+
opt = temp_opt(**kw)
|
165
|
+
if @recipe.kind_of?(String)
|
166
|
+
@recipe.buster_optimize(smith, comp, opt:)
|
167
|
+
else
|
168
|
+
raise InvalidRecipeError, "Mgmg::Recipe#buster_optimize is available only for String recipes."
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
data/lib/mgmg/reinforce.rb
CHANGED
@@ -14,7 +14,7 @@ module Mgmg
|
|
14
14
|
alias :inspect :to_s
|
15
15
|
end
|
16
16
|
|
17
|
-
#
|
17
|
+
# スキル名 攻 物 防 HP MP 腕 器 速 魔
|
18
18
|
Skill = {
|
19
19
|
'物防御UP' => Reinforcement.new( Vec[ 0, 10, 0, 0, 0, 0, 0, 0, 0] ),
|
20
20
|
'魔防御UP' => Reinforcement.new( Vec[ 0, 0, 10, 0, 0, 0, 0, 0, 0] ),
|
@@ -42,9 +42,9 @@ module Mgmg
|
|
42
42
|
if Skill.has_key?(arg)
|
43
43
|
Skill[arg]
|
44
44
|
elsif SystemCuisine.has_key?(arg)
|
45
|
-
SystemCuisine[arg]
|
45
|
+
cuisine(SystemCuisine[arg])
|
46
46
|
else
|
47
|
-
raise
|
47
|
+
raise InvalidReinforcementNameError, arg
|
48
48
|
end
|
49
49
|
else
|
50
50
|
raise ArgumentError, "The argument should be Mgmg::Cuisine or skill name String. (`#{arg}' is given)"
|