mgmg 1.5.0 → 1.5.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 +7 -0
- data/README.md +25 -6
- data/lib/mgmg/equip.rb +3 -3
- data/lib/mgmg/ir.rb +3 -2
- data/lib/mgmg/option.rb +5 -6
- data/lib/mgmg/recipe.rb +172 -0
- data/lib/mgmg/search.rb +24 -2
- data/lib/mgmg/utils.rb +44 -8
- data/lib/mgmg/version.rb +1 -1
- data/lib/mgmg.rb +17 -6
- data/reference.md +59 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7cadbd5fef7941e004310c08f8ec597ce06381b0b305369d0e42afa08cb5016
|
4
|
+
data.tar.gz: a0d9d53d2e0284274e4558c7d27f26aeb2af6eb2649faaa07d840a5cd4f5aed8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe3d521ee8e90ae3253dacf5389035a53e40d58d0a9e574c0685d346765fdef35de371412d772b77476809cf80a2bb384e1e0b20c0ada8c265f6155ad27fcf3a
|
7
|
+
data.tar.gz: 77638a9c41f22fa7a509f409645307d2a452822bd557aa83e5d0c8e96ac8e84c93f6d9fd3df265a04dc1e91abde3f143561f410c6b397a89fe599a0ee2dcc8f7
|
data/CHANGELOG.md
CHANGED
@@ -131,3 +131,10 @@
|
|
131
131
|
- 関連して,`String#max_weight`,`String#min_weight`,`Enumerable#max_weight`,`Enumerable#min_weight`,`Enumerable#max_weights`,`Enumerable#min_weights`を追加した.
|
132
132
|
- `Mgmg::Option#smith_min`,`Mgmg::Option#armor_min`のデフォルト値を,`String#min_level`,`Enumerable#min_level`を用いて設定する仕様とし,その目標重量を`Mgmg::Option#target_weight`で指定するようにした.
|
133
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
|
+
- 計算を繰り返した際,複数装備の装備数が増加していってしまうバグを修正した.
|
data/README.md
CHANGED
@@ -54,6 +54,7 @@ puts r.build(122, 139, 232)
|
|
54
54
|
```
|
55
55
|
|
56
56
|
製作品の重量及び特定の重量にするために必要な鍛冶・防具製作Lvを確認する.
|
57
|
+
|
57
58
|
```ruby
|
58
59
|
r = 'サンダル(骨2皮1)+[重鎧(金3金3)+[フード(骨2宝1)+[重鎧(皮10金10)+軽鎧(鉄10皮1)]]]'
|
59
60
|
p r.min_levels # 各材料装備を重量1で作るのに必要な防具製作Lv
|
@@ -61,7 +62,7 @@ p r.min_levels # 各材料装備を重量1で作るのに必要
|
|
61
62
|
p r.min_levels(2) # 同重量2以下
|
62
63
|
#=> {"サンダル(骨2皮1)"=>3, "重鎧(金3金3)"=>102, "フード(骨2宝1)"=>3, "重鎧(皮10金10)"=>42, "軽鎧(鉄10皮1)"=>27}
|
63
64
|
p [r.min_weight, r.max_weight] # 最小重量と最大重量
|
64
|
-
#=> [5,
|
65
|
+
#=> [5, 10]
|
65
66
|
p r.min_level # 最小重量で作るのに必要な防具製作Lv
|
66
67
|
#=> 202
|
67
68
|
p r.min_level(7) # 重量7以下で作るのに必要な防具製作Lv
|
@@ -70,6 +71,20 @@ p r.min_level(-1) # 最小重量+1=重量6以下で作るのに必
|
|
70
71
|
#=> 162
|
71
72
|
```
|
72
73
|
|
74
|
+
注目パラメータやオプションパラメータを,レシピ文字列とセットにして取り回す.
|
75
|
+
```ruby
|
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) で製作
|
86
|
+
```
|
87
|
+
|
73
88
|
近似多項式を得る.
|
74
89
|
|
75
90
|
```ruby
|
@@ -97,22 +112,26 @@ p [sc, Mgmg.exp(*sc)]
|
|
97
112
|
|
98
113
|
```ruby
|
99
114
|
r = '双短剣(金3皮1)+[杖(水1綿1)+[斧(玉5水1)+[杖(鉄1綿1)+[[斧(木2金3)+剣(鉄10皮1)]+[剣(木2綿1)+双短剣(鉄10皮1)]]]]]'
|
100
|
-
|
115
|
+
r = r.to_recipe(:atk_sd, target_weight: 9)
|
116
|
+
sc = r.search(2000) # to_recipe で注目パラメータを入れているので,ここでは不要
|
101
117
|
p [sc, Mgmg.exp(*sc)]
|
102
|
-
#=> [[70, 130], 38046]
|
103
|
-
# オプションなしの場合は鍛冶Lv100以上を探索するため,[[100, 126], 41054] になる
|
118
|
+
#=> [[70, 130], 38046] # オプションなしの場合は鍛冶Lv100以上を探索するため,[[100, 126], 41054] になる
|
104
119
|
```
|
105
120
|
|
106
121
|
探索の際,スキル及び料理を考慮する.
|
107
122
|
|
108
123
|
```ruby
|
109
124
|
r = '重鎧(皮2綿1)+[帽子(宝1宝1)+[重鎧(玉5金3)+[帽子(宝1宝1)+[重鎧(玉5金6)+[軽鎧(金3骨1)+[重鎧(皮2骨1)+軽鎧(鉄10綿1)]]]]]]'
|
110
|
-
|
125
|
+
r = r.to_recipe(:phydef, buff: %w|物防御UP アースドランと氷河酒の蒸し焼き ガードアップ|)
|
126
|
+
sc = r.search(100_000)
|
111
127
|
p [sc, Mgmg.exp(*sc)]
|
112
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]
|
113
133
|
```
|
114
134
|
|
115
|
-
|
116
135
|
各メソッドの詳しい説明等は [リファレンス](./reference.md) を参照されたい.
|
117
136
|
|
118
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
|
@@ -193,8 +193,8 @@ module Mgmg
|
|
193
193
|
def +(other)
|
194
194
|
self.dup.add!(other)
|
195
195
|
end
|
196
|
-
Zero = self.new(28, 0, Vec.new(6, 0), 12, 12, Vec.new(9, 0), Vec.new(3, 0))
|
197
|
-
Zero.history.clear
|
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
198
|
Zero.freeze
|
199
199
|
end
|
200
200
|
|
data/lib/mgmg/ir.rb
CHANGED
@@ -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,7 +313,8 @@ module Mgmg
|
|
313
313
|
def +(other)
|
314
314
|
self.dup.add!(other)
|
315
315
|
end
|
316
|
-
Zero = self.new(28, Vec.new(6, 0), 12, 12, Array.new(9){Const.new(0)})
|
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
|
317
318
|
end
|
318
319
|
class << IR
|
319
320
|
def build(str, left_associative: true, reinforcement: [])
|
data/lib/mgmg/option.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
module Mgmg
|
2
|
-
module_function def option(recipe=nil, **kw)
|
3
|
-
ret = Option.new(**kw)
|
4
|
-
ret.set_default(recipe) unless recipe.nil?
|
5
|
-
ret
|
6
|
-
end
|
7
2
|
class Option
|
8
3
|
def initialize(
|
9
4
|
left_associative: true,
|
@@ -50,7 +45,7 @@ module Mgmg
|
|
50
45
|
@irep = other.irep
|
51
46
|
@cut_exp = other.cut_exp
|
52
47
|
end
|
53
|
-
def
|
48
|
+
def update_sa_min(recipe, force=true)
|
54
49
|
case recipe
|
55
50
|
when String
|
56
51
|
if @smith_min.nil? && @armor_min
|
@@ -71,6 +66,10 @@ module Mgmg
|
|
71
66
|
else
|
72
67
|
raise ArgumentError, 'recipe should be String or Enumerable'
|
73
68
|
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
def set_default(recipe, force: false)
|
72
|
+
update_sa_min(recipe, force)
|
74
73
|
@comp_min = recipe.min_comp(opt: self) if force || @comp_min.nil?
|
75
74
|
@irep = recipe.ir(opt: self) if force || @irep.nil?
|
76
75
|
self
|
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: opt)
|
74
|
+
when Enumerable
|
75
|
+
recipe.build(smith, armor, comp, opt: 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: para, opt: opt)
|
86
|
+
when Enumerable
|
87
|
+
recipe.show(smith, armor, comp, para: para, opt: 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: 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: 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: 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: 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/search.rb
CHANGED
@@ -228,7 +228,18 @@ module Mgmg
|
|
228
228
|
if term <= start
|
229
229
|
raise ArgumentError, "start < term is needed, (start, term) = (#{start}, #{term}) are given"
|
230
230
|
end
|
231
|
-
|
231
|
+
if a.kind_of?(Recipe)
|
232
|
+
opt_a = a.option.dup
|
233
|
+
a = a.recipe
|
234
|
+
else
|
235
|
+
opt_a = opt_a.dup.set_default(a)
|
236
|
+
end
|
237
|
+
if b.kind_of?(Recipe)
|
238
|
+
opt_b = b.option.dup
|
239
|
+
b = b.recipe
|
240
|
+
else
|
241
|
+
opt_b = opt_b.dup.set_default(b)
|
242
|
+
end
|
232
243
|
sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
|
233
244
|
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
234
245
|
if eb < ea || ( ea == eb && opt_a.irep.para_call(para, *sca) < opt_b.irep.para_call(para, *scb) )
|
@@ -263,7 +274,18 @@ module Mgmg
|
|
263
274
|
if start <= term
|
264
275
|
raise ArgumentError, "term < start is needed, (start, term) = (#{start}, #{term}) are given"
|
265
276
|
end
|
266
|
-
|
277
|
+
if a.kind_of?(Recipe)
|
278
|
+
opt_a = a.option.dup
|
279
|
+
a = a.recipe
|
280
|
+
else
|
281
|
+
opt_a = opt_a.dup.set_default(a)
|
282
|
+
end
|
283
|
+
if b.kind_of?(Recipe)
|
284
|
+
opt_b = b.option.dup
|
285
|
+
b = b.recipe
|
286
|
+
else
|
287
|
+
opt_b = opt_b.dup.set_default(b)
|
288
|
+
end
|
267
289
|
sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
|
268
290
|
ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
|
269
291
|
if ea < eb || ( ea == eb && opt_b.irep.para_call(para, *scb) < opt_a.irep.para_call(para, *sca) )
|
data/lib/mgmg/utils.rb
CHANGED
@@ -17,16 +17,33 @@ module Mgmg
|
|
17
17
|
refine Float do
|
18
18
|
alias :cdiv :quo # Floatの場合は普通の割り算
|
19
19
|
def comma3
|
20
|
-
s = self.to_s
|
21
|
-
|
22
|
-
|
23
|
-
s
|
24
|
-
when %r|\.|
|
25
|
-
ary = s.split('.')
|
26
|
-
ary[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,') + '.' + ary[1]
|
20
|
+
s = (self*100).round.to_s
|
21
|
+
if s[0] == '-'
|
22
|
+
g, s = '-', s[1..(-1)]
|
27
23
|
else
|
28
|
-
|
24
|
+
g = ''
|
29
25
|
end
|
26
|
+
raise unless %r|\A\d+\Z|.match(s)
|
27
|
+
case s.length
|
28
|
+
when 1
|
29
|
+
if s == '0'
|
30
|
+
'0.0'
|
31
|
+
else
|
32
|
+
g+'0.0'+s
|
33
|
+
end
|
34
|
+
when 2
|
35
|
+
if s[1] == '0'
|
36
|
+
g+'0.'+s[0]
|
37
|
+
else
|
38
|
+
g+'0.'+s
|
39
|
+
end
|
40
|
+
else
|
41
|
+
i, d = s[0..(-3)], s[(-2)..(-1)]
|
42
|
+
d = d[0] if d[1] == '0'
|
43
|
+
g+i.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,') + '.' + d
|
44
|
+
end
|
45
|
+
rescue
|
46
|
+
self.to_s
|
30
47
|
end
|
31
48
|
end
|
32
49
|
refine Rational do
|
@@ -78,6 +95,20 @@ module Mgmg
|
|
78
95
|
end
|
79
96
|
attr_accessor :name
|
80
97
|
end
|
98
|
+
class InvalidRecipeError < StandardError
|
99
|
+
def initialize(msg=nil)
|
100
|
+
if msg.nil?
|
101
|
+
super("Neither String nor Enumerable recipe was set.")
|
102
|
+
else
|
103
|
+
super(msg)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
class Over20Error < StandardError
|
108
|
+
def initialize(star)
|
109
|
+
super("The star of given recipe is #{star}. It can't be built since the star is over 20.")
|
110
|
+
end
|
111
|
+
end
|
81
112
|
class SearchCutException < StandardError; end
|
82
113
|
class UnexpectedError < StandardError
|
83
114
|
def initialize()
|
@@ -122,6 +153,11 @@ module Mgmg
|
|
122
153
|
module_function def invexp3(exp, sa, comp)
|
123
154
|
Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).round + 1
|
124
155
|
end
|
156
|
+
module_function def option(recipe=nil, **kw)
|
157
|
+
ret = Option.new(**kw)
|
158
|
+
ret.set_default(recipe) unless recipe.nil?
|
159
|
+
ret
|
160
|
+
end
|
125
161
|
|
126
162
|
CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/.freeze
|
127
163
|
module_function def check_string(str)
|
data/lib/mgmg/version.rb
CHANGED
data/lib/mgmg.rb
CHANGED
@@ -8,10 +8,17 @@ require_relative './mgmg/system_equip'
|
|
8
8
|
require_relative './mgmg/cuisine'
|
9
9
|
require_relative './mgmg/reinforce'
|
10
10
|
require_relative './mgmg/option'
|
11
|
+
require_relative './mgmg/recipe'
|
11
12
|
require_relative './mgmg/search'
|
12
13
|
require_relative './mgmg/optimize'
|
13
14
|
|
14
15
|
class String
|
16
|
+
using Mgmg::Refiner
|
17
|
+
def to_recipe(para=:power, allow_over20: false, **kw)
|
18
|
+
ret = Mgmg::Recipe.new(self, para, **kw)
|
19
|
+
raise Mgmg::Over20Error, ret.ir.star if (!allow_over20 and 20<ret.ir.star)
|
20
|
+
ret
|
21
|
+
end
|
15
22
|
def min_weight(opt: Mgmg::Option.new)
|
16
23
|
build(build(opt: opt).min_levels_max, opt: opt).weight
|
17
24
|
end
|
@@ -109,10 +116,10 @@ class String
|
|
109
116
|
built = build(smith, comp, opt: opt)
|
110
117
|
pstr = '%.3f' % built.para_call(para)
|
111
118
|
pstr.sub!(/\.?0+\Z/, '')
|
112
|
-
puts "
|
119
|
+
puts "With levels (#{smith}, #{comp}: #{Mgmg.exp(smith, comp).comma3}), building"
|
113
120
|
puts " #{self}"
|
114
|
-
rein = rein.empty? ? '' : "
|
115
|
-
puts "
|
121
|
+
rein = rein.empty? ? '' : "reinforced by {#{rein.join(',')}} "
|
122
|
+
puts "#{rein}yields (#{pstr}, #{built.total_cost})"
|
116
123
|
puts " #{built}"
|
117
124
|
end
|
118
125
|
def phydef_optimize(smith=nil, comp=smith, opt: Mgmg::Option.new)
|
@@ -123,6 +130,10 @@ class String
|
|
123
130
|
end
|
124
131
|
end
|
125
132
|
module Enumerable
|
133
|
+
using Mgmg::Refiner
|
134
|
+
def to_recipe(para=:power, **kw)
|
135
|
+
Mgmg::Recipe.new(self, para, **kw)
|
136
|
+
end
|
126
137
|
def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, opt: Mgmg::Option.new)
|
127
138
|
opt = opt.dup
|
128
139
|
rein = opt.reinforcement
|
@@ -150,10 +161,10 @@ module Enumerable
|
|
150
161
|
built = self.build(smith, armor, comp, opt: opt)
|
151
162
|
pstr = '%.3f' % built.para_call(para)
|
152
163
|
pstr.sub!(/\.?0+\Z/, '')
|
153
|
-
puts "
|
164
|
+
puts "With levels (#{smith}, #{armor}, #{comp}: #{Mgmg.exp(smith, armor, comp).comma3}), building"
|
154
165
|
puts " #{self.join(', ')}"
|
155
|
-
rein = rein.empty? ? '' : "
|
156
|
-
puts "
|
166
|
+
rein = rein.empty? ? '' : "reinforced by {#{rein.join(',')}} "
|
167
|
+
puts "#{rein}yields (#{pstr}, #{built.total_cost})"
|
157
168
|
puts " #{built}"
|
158
169
|
end
|
159
170
|
def min_weight(opt: Mgmg::Option.new)
|
data/reference.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
# リファレンス
|
2
2
|
本ライブラリで定義される主要なメソッドを以下に解説します.
|
3
3
|
|
4
|
+
## `String#to_recipe(para=:power, allow_over20: false, **kw)`,`Enumerable#to_recipe(para=:power, **kw)`
|
5
|
+
レシピ文字列である`self`と,注目パラメータ`para`,オプション`Mgmg.option(**kw)`をセットにした[後述](#mgmgrecipe)の`Mgmg::Recipe`オブジェクトを生成して返します.デフォルト値としてセットされたパラメータを使用する以外は,レシピ文字列と同様に扱えます.
|
6
|
+
|
7
|
+
`allow_over20`が偽の場合,レシピの☆を確認し,20を超える場合は,例外`Mgmg::Over20Error`を発生します.このチェックを抑制したい場合は,真にしてください.
|
8
|
+
|
4
9
|
## `String#build(smith=-1, comp=smith, opt: Mgmg.option())`
|
5
10
|
レシピ文字列である`self`を解釈し,鍛冶・防具製作Lvを`smith`,道具製作Lvを`comp`として鍛冶・防具製作及び武器・防具合成を行った結果を[後述](#mgmgequip)の`Mgmg::Equip`クラスのインスタンスとして生成し,返します.例えば,
|
6
11
|
```ruby
|
@@ -145,7 +150,8 @@
|
|
145
150
|
返り値は`[逆転しない最大目標値, 逆転時の最小para値]`です.前者は逆転目標値の下限,後者は,目標値が前者よりも少しだけ大きいときの`para`値です.
|
146
151
|
ここで,最小経験値が小さい方,または最小経験値が同じなら,そのときの`para`値が大きい方をよりよいものと解釈します.
|
147
152
|
`term`は`start`より大きい値とします.目標値`term`における優劣が,目標値`start`における優劣と同じ場合,`Mgmg::SearchCutException`を発生します.
|
148
|
-
|
153
|
+
|
154
|
+
`a`と`b`は`String`でもその`Enumerable`でも構いません.`Mgmg::Recipe`が与えられた場合,`opt_a`,`opt_b`は無視され,代わりに`a.option`,`b.option`が使用されます.`a.para`,`b.para`は無視され,引数で与えた`para`を使用します.
|
149
155
|
|
150
156
|
`opt_a`,`opt_b`には,それぞれ`a`と`b`に関するオプションパラメータを指定します.`smith_min`,`armor_min`,`min_smith`,`left_associative`,`reinforcement`,`irep`を使用します.
|
151
157
|
|
@@ -451,3 +457,55 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
451
457
|
|irep|`recipe.ir()`|`Mgmg::IR`の使い回しによる高速化|`String#search`など,内部的に使用|
|
452
458
|
|cut_exp|`Float::INFINITY`|探索時の総経験値の打ち切り値|`String#search`など,内部的に使用|
|
453
459
|
|
460
|
+
## `Mgmg::Recipe`
|
461
|
+
レシピ文字列,注目パラメータ,オプションをセットにして扱うためのクラスです.
|
462
|
+
それぞれ`Mgmg::Recipe#recipe`,`Mgmg::Recipe#para`,`Mgmg::Recipe#option`でアクセスできます.
|
463
|
+
|
464
|
+
## `Mgmg::Recipe#option(**kw)`
|
465
|
+
オプションパラメータを`kw`で上書きして,新しい`Mgmg::Option`インスタンスを返します.
|
466
|
+
渡したバラメータだけ上書きします.パラメータを渡さない場合,単にセットになってるオプションオブジェクトを返します.
|
467
|
+
`target_weight`を上書きした場合,`smith_min`,`armor_min`は自動的に再計算されます.
|
468
|
+
|
469
|
+
与えるパラメータ以外をデフォルト値に戻したい場合,`recipe.option=Mgmg.option(**kw)`のように`Mgmg::Recipe#option=(new_option)`を使用します.
|
470
|
+
|
471
|
+
## `Mgmg::Recipe#replace(new_recipe, para: self.para, **kw)`
|
472
|
+
レシピ文字列を`new_recipe`で置き換え,`kw`でオプションを設定します.`para`を与えた場合,注目パラメータも引数で置き換えます.
|
473
|
+
レシピ文字列とオプションの対応を保つため,`Mgmg::Recipe#recipe=`メソッドは定義していません.代わりにこれを使います.
|
474
|
+
|
475
|
+
## `Mgmg::Recipe#build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, **kw)`
|
476
|
+
`self.recipe.build`を呼び出して返します.`kw`が与えられた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
|
477
|
+
|
478
|
+
`smith`に`nil`を与えた場合,製作Lvを`self.option.smith_min`,`self.option.armor_min`,`self.option.comp_min`とします.
|
479
|
+
|
480
|
+
## `Mgmg::Recipe#search(target, para: self.para, **kw)`
|
481
|
+
`self.recipe.search`を呼び出して返します.注目パラメータはセットされたものを自動的に渡しますが,別のパラメータを使いたい場合,キーワード引数で指定します.その他のキーワード引数を与えた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
|
482
|
+
|
483
|
+
## `Mgmg::Recipe#min_level(w=self.option.target_weight, include_outsourcing=false)`
|
484
|
+
`self.recipe.min_level(w, include_outsourcing)`を返します.`w`のデフォルトパラメータが`target_weight`になっている以外は`String#min_level`または`Enumerable#min_level`と同じです.
|
485
|
+
|
486
|
+
## `Mgmg::Recipe#min_weight, max_weight, min_levels, min_levels_max, min_smith, min_comp`
|
487
|
+
`self.recipe`の同名メソッドをそのまま呼び出して返します.
|
488
|
+
|
489
|
+
## `Mgmg::Recipe#ir(**kw)`
|
490
|
+
`self.recipe`に対応した`Mgmg::IR`インスタンスを返します.
|
491
|
+
|
492
|
+
`kw`を与えた場合一時的に置き換えたオプションに対応した`Mgmg::IR`インスタンスを返します.`left_associative`が与えられれば再構築し,`reinforcement`が与えられれば,スキル・料理の効果を与えた引数に差し替えます.その他のキーワードを与えても特に影響はありません.
|
493
|
+
|
494
|
+
## `Mgmg::Recipe#para_call(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: self.para, **kw)`
|
495
|
+
`self.ir.para_call`を呼び出して返します.キーワード引数が与えられた場合,与えられた分だけ一時的に上書きします.
|
496
|
+
|
497
|
+
`smith`に`nil`を与えた場合,製作Lvを`self.option.smith_min`,`self.option.armor_min`,`self.option.comp_min`とします.製作Lvに負の値が与えられた場合,`0`に修正して計算して返します.
|
498
|
+
|
499
|
+
パラメータとして,以下が指定でき,これらは直接メソッドとしても定義されています(`Mgmg::Recipe#attack`など).製作Lvの与え方は`para_call`と同様です.
|
500
|
+
|
501
|
+
```ruby
|
502
|
+
:attack, :phydef, :magdef, :hp, :mp, :str, :dex, :speed, :magic
|
503
|
+
:atkstr, :atk_sd, :dex_as, :mag_das, :magic2, :magmag, :pmdef
|
504
|
+
:power, :fpower, :smith_cost, :comp_cost, :cost
|
505
|
+
```
|
506
|
+
|
507
|
+
## `Mgmg::Recipe#poly(para=self.para, **kw)`
|
508
|
+
`self.recipe.poly(para, opt: self.option)`を返します.`kw`が与えられた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
|
509
|
+
|
510
|
+
## `Mgmg::Recipe#phydef_optimize(smith=nil, comp=smith, **kw)`,`Mgmg::Recipe#buster_optimize(smith=nil, comp=smith, **kw)`
|
511
|
+
`self.recipe.phydef_optimize(smith, comp, opt: self.option)`,`self.recipe.buster_optimize(smith, comp, opt: self.option)`を返します.`kw`が与えられた場合,オプションのうち,与えられたパラメータのみ一時的に上書きします.
|
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.
|
4
|
+
version: 1.5.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-06-
|
11
|
+
date: 2022-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,6 +75,7 @@ files:
|
|
75
75
|
- lib/mgmg/optimize.rb
|
76
76
|
- lib/mgmg/option.rb
|
77
77
|
- lib/mgmg/poly.rb
|
78
|
+
- lib/mgmg/recipe.rb
|
78
79
|
- lib/mgmg/reinforce.rb
|
79
80
|
- lib/mgmg/search.rb
|
80
81
|
- lib/mgmg/system_equip.rb
|