mgmg 1.2.3 → 1.3.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 +28 -1
- data/README.md +117 -23
- data/lib/mgmg.rb +81 -145
- data/lib/mgmg/const.rb +0 -995
- data/lib/mgmg/equip.rb +396 -0
- data/lib/mgmg/optimize.rb +213 -0
- data/lib/mgmg/poly.rb +347 -0
- data/lib/mgmg/search.rb +254 -0
- data/lib/mgmg/system_equip.rb +326 -0
- data/lib/mgmg/utils.rb +315 -0
- data/lib/mgmg/version.rb +1 -1
- data/mgmg.gemspec +3 -3
- metadata +24 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d35a19c90c58e70a8410540581af727523ea22584580bbf5ccf3b50fd19cbe4c
|
4
|
+
data.tar.gz: ca9c6122b4d7d84389787a10ac7073e5f3f633d1c1fffab58be1ad693e3613d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab690d14c5d159646fa354b551eefe5a2afb7ab8c227769cdd5397262c5b810776611c3171c88af3143a96b18eac10050348c80c9b9801fc809544ec7291414d
|
7
|
+
data.tar.gz: a17fafc6c8eefdca6a137b0311f2e8ca1e44c71a8ea8a6341359ab6929d6b25228b8d0be96ef06ee29be514e0abfaa93cbc1a0f45ae1cb746175d39ad7a3207d
|
data/CHANGELOG.md
CHANGED
@@ -30,7 +30,7 @@
|
|
30
30
|
- マニュアル等の不備を修正.
|
31
31
|
|
32
32
|
## 1.0.9 2019/05/30
|
33
|
-
- 丸めを無視した多項式近似(変数は製作レベル)
|
33
|
+
- 丸めを無視した多項式近似(変数は製作レベル)を表す`Mgmg::TPolynomial`およびこれを生成するメソッド`String#poly`を追加.
|
34
34
|
|
35
35
|
## 1.0.10 2019/06/29
|
36
36
|
- 消費エレメント量を返す`Mgmg::Equip#total_cost`を追加.
|
@@ -72,3 +72,30 @@
|
|
72
72
|
|
73
73
|
## 1.2.3 2019/11/10
|
74
74
|
- typoに基づくバグの修正.
|
75
|
+
|
76
|
+
## 1.2.4 2020/03/01
|
77
|
+
- 開発用のgemのバージョンを更新(ライブラリ本体は更新なし).
|
78
|
+
|
79
|
+
## 1.2.5 2020/08/22
|
80
|
+
- `Mgmg::TPolynomial#leading(fmt=nil)`, `Mgmg::TPolynomial#[](i, j)`を追加.
|
81
|
+
- `Mgmg::Equip#history`, `Mgmg::Equip#min_levels`, `Mgmg::Equip#min_level`を追加.
|
82
|
+
- ソースコードのファイル配置を整理.
|
83
|
+
|
84
|
+
## 1.3.0 2020/08/26
|
85
|
+
- 既製品に対する`Mgmg::Equip#min_level`の返り値を`nil`から`0`に変更.
|
86
|
+
- `String#build`において,第1引数にもデフォルト値`-1`を設定し,引数なしで委託製作相当とするように変更.
|
87
|
+
- `String#poly`のデフォルト引数を`:cost`に設定.
|
88
|
+
- `Mgmg.#exp`,`String#eff`,`String#peff`,`String#min_levels`を追加.
|
89
|
+
- `String#smith_search`, `String#comp_search`, `String#min_smith`, `String#min_comp`を追加.
|
90
|
+
|
91
|
+
## 1.3.1 2020/08/31
|
92
|
+
- `String#poly`のキーワード引数`left_associative`が無視される場合があったバグを修正.
|
93
|
+
- `Mgmg.#exp`に3引数を与えられるように修正.
|
94
|
+
- `String#search`,`Enumerable#search`を追加.
|
95
|
+
- `Enumerable#min_levels`,`Enumerable#min_level`,`Enumerable#min_smith`,`Enumerable#min_comp`を追加.
|
96
|
+
|
97
|
+
## 1.3.2 2021/05/18
|
98
|
+
- `Mgmg::TPolynomial`に比較演算子を追加.
|
99
|
+
- `String#phydef_optimize`,`String#buster_optimize`を追加.
|
100
|
+
- (`Enumerable#search`から呼び出される)`Enumerable#comp_search`における最大道具製作レベルチェックが間違っていたバグを修正.
|
101
|
+
- `String#search`および`Enumerable#search`において,総経験値量が等しい組み合わせの場合,目標パラメータが大きくなる製作Lvの組み合わせを返すように修正.
|
data/README.md
CHANGED
@@ -35,17 +35,26 @@ puts '[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.b
|
|
35
35
|
複数装備を製作し,そのすべてを装備した場合の合計値を標準出力に出力.
|
36
36
|
|
37
37
|
```ruby
|
38
|
-
|
38
|
+
ary = %w|本(金3骨1)+[弓(骨1綿1)+[杖(金3金3)+[弓(綿1綿1)+[杖(宝10金6)+本(骨9鉄2)]]]] フード(石10骨9) 首飾り(宝10水10) 指輪(木10金10)|
|
39
|
+
puts ary.build(122, 139, 232)
|
39
40
|
#=> 複数装備9(武:1, 頭:1, 飾:2)[攻撃:15, 物防:34, 魔防:28, HP:241, MP:71, 器用:223, 素早:222, 魔力:6,604]
|
40
41
|
```
|
41
42
|
|
42
|
-
重量1または2で作るのに必要な防具製作Lv
|
43
|
+
重量1または2で作るのに必要な防具製作Lvを確認.
|
43
44
|
|
44
45
|
```ruby
|
45
46
|
p ['重鎧(皮10金10)'.min_level, '重鎧(皮10金10)'.min_level(2)]
|
46
47
|
#=> [162, 42]
|
47
48
|
```
|
48
49
|
|
50
|
+
合成レシピから必要製作Lvを確認.
|
51
|
+
```ruby
|
52
|
+
p '[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.min_levels
|
53
|
+
#=> {"杖(水玉10火玉5)"=>92, "本(骨10鉄1)"=>48, "本(水玉5綿2)"=>12, "杖(骨10鉄1)"=>28}
|
54
|
+
p '[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.build.min_level
|
55
|
+
#=> 92
|
56
|
+
```
|
57
|
+
|
49
58
|
近似多項式を得る.
|
50
59
|
|
51
60
|
```ruby
|
@@ -56,7 +65,7 @@ puts '[斧(牙10金10)+剣(鉄10皮1)]+剣(鉄10皮1)'.poly(:attack).to_s('%.4g'
|
|
56
65
|
既成品の性能を確認.
|
57
66
|
|
58
67
|
```ruby
|
59
|
-
puts '小竜咆哮'.build
|
68
|
+
puts '小竜咆哮'.build
|
60
69
|
#=> 弓1☆10(木骨)[攻撃:50, 器用:120, 素早:50]
|
61
70
|
```
|
62
71
|
|
@@ -78,26 +87,47 @@ puts '小竜咆哮'.build(-1)
|
|
78
87
|
## リファレンス
|
79
88
|
本ライブラリで定義される主要なメソッドを以下に解説します.
|
80
89
|
|
81
|
-
### `String#build(smith, comp=smith, left_associative: true)`
|
90
|
+
### `String#build(smith=-1, comp=smith, left_associative: true)`
|
82
91
|
レシピ文字列である`self`を解釈し,鍛冶・防具製作Lvを`smith`,道具製作Lvを`comp`として鍛冶・防具製作及び武器・防具合成を行った結果を後述の`Mgmg::Equip`クラスのインスタンスとして生成し,返します.例えば,
|
83
92
|
```ruby
|
84
93
|
'[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.build(112, 176)
|
85
94
|
```
|
86
95
|
のようにします.基本的に`[]`による合成順序の指定が必要ですが,不確定の場合,`left_associative`が真なら左結合,偽なら右結合として解釈します.
|
87
96
|
```ruby
|
88
|
-
'
|
97
|
+
'法衣(綿10皮10)+歴戦の服'
|
89
98
|
```
|
90
99
|
のように,既成品を含む合成レシピも解釈します.キャラクリ初期装備の劣悪な服,劣悪な小手以外のあらゆる装備を網羅しています.劣悪な服,劣悪な小手はキャラクリ以外での初期装備品として解釈します.`comp`を省略した場合,`smith`と同じ値として処理します.
|
91
100
|
|
92
101
|
`self`が解釈不能な場合,例外が発生します.また,製作Lvや完成品の☆制限のチェックを行っていないほか,本ライブラリでは`武器+防具`や`防具+武器`の合成も可能になっています.街の鍛冶・防具製作・道具製作屋に任せた場合をシミュレートする場合は製作Lvを負の値(`-1`など,負であれば何でもよい)にします(製作Lv0相当の性能を計算し,消費エレメント量は委託仕様となります).
|
93
102
|
|
103
|
+
### `Enumerable#build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)`
|
104
|
+
複数のレシピ文字列からなる`self`の各要素を製作し,そのすべてを装備したときの`Mgmg::Equip`を返します.製作では`鍛冶Lv=smith`, `防具製作Lv=armor`, `道具製作Lv=comp`とします.1つしか指定しなければすべてそのLv,2つなら1つ目を`smith=armor`,2つ目を`comp`に,3つならそれぞれの値とします.`left_associative`はそのまま`String#build`に渡されます.製作Lvが負の場合,製作Lv0として計算した上で,消費エレメント量は街の製作屋に頼んだ場合の値を計算します.武器複数など,同時装備が不可能な場合でも,特にチェックはされません.
|
105
|
+
|
94
106
|
### `String#min_level(weight=1)`
|
95
|
-
`self`を`weight`以下で作るための最低製作Lvを返します.`build`と異なり,合成や既成品は解釈できません.また,素材の☆による最低製作Lvとのmaxを返すため,街の鍛冶・防具製作屋に頼んだ場合の重量は`self.build
|
107
|
+
`self`を`weight`以下で作るための最低製作Lvを返します.`build`と異なり,合成や既成品は解釈できません.また,素材の☆による最低製作Lvとのmaxを返すため,街の鍛冶・防具製作屋に頼んだ場合の重量は`self.build.weight`で確認する必要があります.`weight`を省略した場合,重量1となる製作Lvを返します.
|
96
108
|
|
97
|
-
### `
|
98
|
-
|
109
|
+
### `String#min_levels(left_associative: true)`
|
110
|
+
合成レシピの各鍛冶・防具製作品に対して,レシピ文字列をキー,重量1で作製するために必要な製作Lvを値とした`Hash`を返します.重量1以外は指定できません.
|
111
|
+
最大値は,`self.build.min_level`によって得られます.
|
112
|
+
|
113
|
+
### `Enumerable#min_levels(left_associative: true)`
|
114
|
+
すべての要素`str`に対する`str.min_levels`をマージした`Hash`を返します.
|
115
|
+
|
116
|
+
### `Enumerable#min_level(left_associative: true)`
|
117
|
+
`self.min_levels`から武器,防具それぞれに対する最大値を求め,`[必要最小鍛冶Lv, 必要最小防具製作Lv]`を返します.武器,防具の一方のみが含まれる場合,もう一方は`0`になります.
|
118
|
+
`String#min_level`と異なり,重量1以外は指定できません.
|
119
|
+
|
120
|
+
### `String#min_comp(left_associative: true)`,`Enumerable#min_comp(left_associative: true)`
|
121
|
+
レシピ通りに合成するのに必要な道具製作Lvを返します.ただし,全体が「[]」で囲われているか,非合成レシピの場合,代わりに`0`を返します.
|
122
|
+
|
123
|
+
`Enumerable`の場合,すべての要素に対する最大値を返します.
|
124
|
+
|
125
|
+
### `String#min_smith(left_associative: true)`,`Enumerable#min_smith(left_associative: true)`
|
126
|
+
レシピ通りに製作するのに必要な鍛冶・防具製作Lvを返します.製作物の重量については考慮せず,鍛冶・防具製作に必要な☆条件を満たすために必要な製作Lvを返します.
|
127
|
+
|
128
|
+
`Enumerable`の場合,すべての要素に対し,武器,防具それぞれの最大値を求め,`[必要最小鍛冶Lv, 必要最小防具製作Lv]`を返します.
|
99
129
|
|
100
|
-
### `String#poly(para, left_associative: true)`
|
130
|
+
### `String#poly(para=:cost, left_associative: true)`
|
101
131
|
レシピ文字列である`self`を解釈し,`para`で指定した9パラ値について,丸めを無視した鍛冶・防具製作Lvと道具製作Lvの2変数からなる多項式関数を示す`Mgmg::TPolynomial`クラスのインスタンスを生成し,返します.`para`は次のシンボルのいずれかを指定します.
|
102
132
|
```ruby
|
103
133
|
:attack, :phydef, :magdef, :hp, :mp, :str, :dex, :speed, :magic
|
@@ -112,6 +142,47 @@ puts '小竜咆哮'.build(-1)
|
|
112
142
|
|
113
143
|
また,`:cost`を渡すことで,消費エレメント量に関する近似多項式を得られます.`self`に`"+"`が含まれていれば合成品とみなし,最後の合成に必要な地エレメント量を,それ以外では,武器なら消費火エレメント量を,防具なら消費水エレメント量を返します.ただし,`self`が既成品そのものの場合,零多項式を返します.
|
114
144
|
|
145
|
+
### `String#smith_seach(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)`
|
146
|
+
`para`の値が`target`以上となるのに必要な最小の鍛冶・防具製作Lvを二分探索で探索して返します.
|
147
|
+
道具製作Lvは`comp`で固定,鍛冶・防具製作Lvを`smith_min`と`smith_max`で挟み込んで探索します.
|
148
|
+
`smith_min`が`nil`のとき,`min_smith`が真なら重量を問わず☆的に必要な最小の鍛冶・防具製作Lv (`self.min_smith`),偽なら最小重量で製作するのに必要な鍛冶・防具製作Lv (`self.build.min_level`)を使用します.
|
149
|
+
`smith_min<smith_max`でないとき,`smith_max`で`para`が`target`以上でないときは`ArgumentError`となります.
|
150
|
+
`para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
|
151
|
+
反転などの影響で,探索範囲において`para`の値が(広義)単調増加になっていない場合,正しい結果を返しません.
|
152
|
+
`cut_exp`以下の経験値で`target`以上を達成できない場合,`Mgmg::SearchCutException`を発生します.
|
153
|
+
|
154
|
+
### `String#comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)`
|
155
|
+
`String#smith_seach`とは逆に,鍛冶・防具製作Lvを固定して最小の道具製作Lvを探索します.
|
156
|
+
`comp_min`が`nil`のときは,製作に必要な最小の道具製作Lv (`self.min_comp`)を使用します.
|
157
|
+
その他は`String#smith_seach`と同様です.
|
158
|
+
|
159
|
+
### `String#search(para, target, smith_min=nil, comp_min=nil, smith_max=10000, comp_max=10000, left_associative: true, step: 1, cut_exp: Float::INFINITY, min_smith: false)`
|
160
|
+
`c_min=comp_search(para, target, smith_max, comp_min, comp_max)` から `c_max=comp_search(para, target, smith_max, comp_min, comp_max)` まで,`step`ずつ動かして,
|
161
|
+
`smith_search`を行い,その過程で得られた最小経験値の鍛冶・防具製作Lvと道具製作Lvからなる配列を返します.
|
162
|
+
レシピ中の,対象パラメータの種別値がすべて奇数,または全て偶数であるなら,`step`を`2`にしても探索すべき範囲を網羅できます.
|
163
|
+
`cut_exp`以下の経験値で`target`以上を達成できない場合,`Mgmg::SearchCutException`を発生します.
|
164
|
+
|
165
|
+
### `Enumerable#search(para, target, smith_min=nil, armor_min=nil, comp_min=nil, smith_max=10000, armor_max=10000, comp_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)`
|
166
|
+
複数装備の組について,`para`の値が`target`以上となる最小経験値の`[鍛冶Lv,防具製作Lv,道具製作Lv]`を返します.
|
167
|
+
武器のみなら防具製作Lvは`0`,防具のみなら鍛冶Lvは`0`,合成なしなら道具製作Lvは`0`となります.
|
168
|
+
`cut_exp`以下の経験値で`target`以上を達成できない場合,`Mgmg::SearchCutException`を発生します.
|
169
|
+
|
170
|
+
### `String#eff(para, smith, comp=smith, left_associative: true)`
|
171
|
+
[`smith`を1上げたときの`para`値/(`smith`を1上げるのに必要な経験値), `comp`を1上げたときの`para`値/(`comp`を2上げるのに必要な経験値)]を返します.
|
172
|
+
`para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
|
173
|
+
|
174
|
+
### `String#peff(para, smith, comp=smith, left_associative: true)`
|
175
|
+
近似多項式における偏微分値を使用した場合の,`String#eff`と同様の値を返します.`self.poly(para, left_associative: left_associative).eff(smith, comp)`と等価です.
|
176
|
+
|
177
|
+
### `String#phydef_optimize(smith=nil, comp=smith, left_associative: true, magdef_maximize: true)`
|
178
|
+
反転物防装備の反転材の種別,素材の最適化を行い,修正したレシピを返します.
|
179
|
+
`smith`,`comp`は探索を行う製作レベルを表し,`smith`が`nil`の場合,近似多項式で最適化を行います.近似多項式では,道具製作レベルの次数が高い項の係数を最適化します.
|
180
|
+
物防を最大化するレシピのうち,`magdef_maximize`が真なら魔防を最大化する組み合わせ,偽ならコストを最小化(≒魔防を最小化)する組み合わせを探索します.
|
181
|
+
ある範囲での全数探索を行うため,段数の多いレシピでは計算量が膨大になるほか,厳密な最適化を保証するものではなく,今後のアップデートで解が変わるような変更が入る可能性があります.
|
182
|
+
|
183
|
+
### `String#buster_optimize(smith=nil, comp=smith, left_associative: true)`
|
184
|
+
`String#phydef_optimize`の魔力弓版で,反転材の素材の最適化を行い,修正したレシピを返します.
|
185
|
+
|
115
186
|
### `Mgmg::Equip`
|
116
187
|
前述の`String#build`によって生成される装備品のクラスです.複数装備の合計値を表す「複数装備」という種別の装備品の場合もあります.以下のようなインスタンスメソッドが定義されています.
|
117
188
|
|
@@ -135,6 +206,10 @@ puts '小竜咆哮'.build(-1)
|
|
135
206
|
### `Mgmg::Equip#weight, star`
|
136
207
|
それぞれ重量,☆数を整数値で返します.「複数装備」の場合,`weight`は総重量,`star`は装備数に関する値が返ります.
|
137
208
|
|
209
|
+
### `Mgmg::Equip#total_cost`
|
210
|
+
製作に必要な総エレメント量を,火,地,水の順のベクトルとして返します.ケージの十分性の確認には,下記の`comp_cost`を用います.
|
211
|
+
ver2.00β12以降では,合成時の消費エレメントが,武器なら火,防具なら水エレメントと半々の消費に変更されていますが,現在,この変更には対応していません.
|
212
|
+
|
138
213
|
### `Mgmg::Equip#attack, phydef, magdef, hp, mp, str, dex, speed, magic, fire, earth, water`
|
139
214
|
それぞれ
|
140
215
|
```
|
@@ -142,17 +217,6 @@ puts '小竜咆哮'.build(-1)
|
|
142
217
|
```
|
143
218
|
の値を`Integer`で返します.
|
144
219
|
|
145
|
-
### `Mgmg::Equip#atkstr, atk_sd, dex_as, mag_das`
|
146
|
-
それぞれ
|
147
|
-
```
|
148
|
-
攻撃+腕力,攻撃x2+腕力+器用,器用x2+攻撃+腕力,魔力x4+器用x2+攻撃+腕力
|
149
|
-
```
|
150
|
-
の値を返します.これらはそれぞれ
|
151
|
-
```
|
152
|
-
(剣,斧,杖,本),(短剣,双短剣),(弓,弩),(バスターアロー)
|
153
|
-
```
|
154
|
-
の威力の定数倍の値です.トリックプレーやディバイドには対応していません.
|
155
|
-
|
156
220
|
### `Mgmg::Equip#power`
|
157
221
|
武器種別ごとに適した威力計算値の4倍の値を返します.具体的には以下の値です.
|
158
222
|
|
@@ -175,14 +239,23 @@ puts '小竜咆哮'.build(-1)
|
|
175
239
|
### `Mgmg::Equip#fpower`
|
176
240
|
武器または複数装備の場合,`Mgmg::Equip#power.fdiv(4)`を返します.防具の場合,`Mgmg::Equip#power.fdiv(2)`を返します.
|
177
241
|
|
242
|
+
### `Mgmg::Equip#atkstr, atk_sd, dex_as, mag_das`
|
243
|
+
それぞれ
|
244
|
+
```
|
245
|
+
攻撃+腕力,攻撃x2+腕力+器用,器用x2+攻撃+腕力,魔力x4+器用x2+攻撃+腕力
|
246
|
+
```
|
247
|
+
の値を返します.これらはそれぞれ
|
248
|
+
```
|
249
|
+
(剣,斧,杖,本),(短剣,双短剣),(弓,弩),(バスターアロー)
|
250
|
+
```
|
251
|
+
の威力の定数倍の値です.トリックプレーやディバイドには対応していません.
|
252
|
+
|
178
253
|
### `Mgmg::Equip#magmag`
|
179
254
|
「魔防x2+魔力」の値を返します.魔力の半分が魔防に加算されることから,実際の魔防性能に比例した値となります.
|
180
255
|
|
181
|
-
### `Mgmg::Equip#total_cost`
|
182
|
-
製作に必要な総エレメント量を,火,地,水の順のベクトルとして返します.ケージの十分性の確認には,下記の`comp_cost`を用います.
|
183
|
-
|
184
256
|
### `Mgmg::Equip#comp_cost(outsourcing=false)`
|
185
257
|
`self`が合成によって作られたものだとした場合の消費地エレメント量を返します.地ケージ確保のための確認用途が多いと思うので短い`cost`をエイリアスとしています.`outsourcing`が真の場合,街の道具製作屋に頼んだ場合のコストを返します.
|
258
|
+
ver2.00β12以降では武器なら火,防具なら水エレメントと半々の消費に変更されていますが,現在,この変更には対応していません.
|
186
259
|
|
187
260
|
### `Mgmg::Equip#smith_cost(outsourcing=false)`
|
188
261
|
`self`が鍛冶・防具製作によって作られたものだったものだとした場合の消費火・水エレメント量を返します.`outscourcing`が真の場合,街の鍛冶屋・防具製作屋に頼んだ場合のコストを返します.
|
@@ -190,6 +263,17 @@ puts '小竜咆哮'.build(-1)
|
|
190
263
|
### `Mgmg::Equip#+(other)`
|
191
264
|
`self`と`other`を装備した「複数装備」の`Mgmg::Equip`を返します.`self`と`other`はいずれも単品でも「複数装備」でも構いません.武器複数などの装備可否チェックはされません.
|
192
265
|
|
266
|
+
### `Mgmg::Equip#history`
|
267
|
+
多段階の合成におけるすべての中間生成物からなる配列を返します.
|
268
|
+
「複数装備」の場合,各装備の`history`を連結した配列を返します.
|
269
|
+
|
270
|
+
### `Mgmg::Equip#min_levels`
|
271
|
+
レシピ中の,鍛冶・防具製作物の文字列をキー,重量1で生成するのに必要な最小レベルを値とした`Hash`を返します.
|
272
|
+
「複数装備」の場合,各装備の`min_levels`をマージした`Hash`を返します.
|
273
|
+
|
274
|
+
### `Mgmg::Equip#min_level`
|
275
|
+
`min_levels`の値の最大値を返します.「複数装備」の場合,`[鍛冶の必要レベル,防具製作の必要レベル]`を返します.
|
276
|
+
|
193
277
|
### `Mgmg::TPolynomial`
|
194
278
|
前述の`String#poly`によって生成される二変数多項式のクラスです.最初のTはtwo-variableのTです.以下のようなメソッドが定義されています.
|
195
279
|
|
@@ -208,6 +292,12 @@ puts '小竜咆哮'.build(-1)
|
|
208
292
|
### `Mgmg::TPolynomial#inspect(fmt=->(r){"Rational(#{r.numerator}, #{r.denominator})"})`
|
209
293
|
`Mgmg::TPolynomial#to_s`と同様ですが,鍛冶・防具製作Lvを`s`,道具製作Lvを`c`としたRubyの式として解釈可能な文字列を返します.つまり,係数をリテラル,掛け算を`*`で表現しています.`fmt`は`Mgmg::TPolynomial#to_s`と同様で,適当な値を指定することでRuby以外の言語でも解釈可能になります.例えば,精度が問題でないならば,`'%e'`とすると,大抵の言語で解釈可能な文字列を生成できます.
|
210
294
|
|
295
|
+
### `Mgmg::TPolynomial#leading(fmt=nil)`
|
296
|
+
最高次係数を返します.`fmt`が`nil`なら数値(`Rational`)をそのまま,それ以外なら`Mgmg::TPolynomial#to_s`と同様の方式で文字列に変換して返します.ただし,レシピの段数に応じた最高次数を返すため,レシピ次第では本メソッドの返り値が`0`となり,それより低い次数の項が最高次となることもあり得ます.そのようなケースでの真の最高次の探索はしません.
|
297
|
+
|
298
|
+
### `Mgmg::TPolynomial#[](i, j)`
|
299
|
+
鍛冶・防具製作Lvをs,道具製作Lvをcとして,s<sup>i</sup>c<sup>j</sup> の係数を返します.負の値を指定すると,最高次から降順に数えた次数の項の係数を返します.例えば`i, j = -1, -1`なら,最高次の係数となります.引数が正で範囲外なら`0`を返し,負で範囲外なら`IndexError`を上げます.
|
300
|
+
|
211
301
|
### `Mgmg::TPolynomial#evaluate(smith, comp=smith)`
|
212
302
|
鍛冶・防具製作Lvを`smith`,道具製作Lvを`comp`として値を計算します.丸めを無視しているため,実際の合成結果以上の値が返ります.
|
213
303
|
|
@@ -226,6 +316,10 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
|
|
226
316
|
多項式として偏微分し,その微分係数を返します.
|
227
317
|
`variable`はどの変数で偏微分するかを指定するもので,`"s"`なら鍛冶・防具製作Lv,`"c"`なら道具製作Lvで偏微分します.
|
228
318
|
|
319
|
+
### `Mgmg::TPolynomial#eff(smith, comp=smith)`
|
320
|
+
製作Lv(`smith`, `comp`)における鍛冶・防具製作Lv効率と道具製作Lv効率からなる配列を返します.
|
321
|
+
一方のみが欲しい場合,`Mgmg::TPolynomial#smith_eff(smith, comp=smith)`,`Mgmg::TPolynomial#smith_eff(smith, comp=smith)`が使えます.
|
322
|
+
|
229
323
|
## 謝辞
|
230
324
|
面白いゲームを作ってくださった耕様および,高精度なシミュレータを作製し,本ライブラリの作製を可能とした,Excel版装備計算機の作者様に感謝いたします.
|
231
325
|
|
data/lib/mgmg.rb
CHANGED
@@ -1,171 +1,68 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
build_sub(stack, str, s_level, c_level, left_associative)
|
10
|
-
end
|
11
|
-
private def build_sub0(stack, str)
|
12
|
-
SystemEquip.each do |k, v|
|
13
|
-
if Regexp.compile(k).match(str)
|
14
|
-
stack << v
|
15
|
-
str = str.gsub(k, "<#{stack.length-1}>")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
[stack, str]
|
19
|
-
end
|
20
|
-
private def build_sub(stack, str, s_level, c_level, lassoc)
|
21
|
-
if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
|
22
|
-
stack << build_sub(stack, m[2], s_level, c_level, lassoc)
|
23
|
-
build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", s_level, c_level, lassoc)
|
24
|
-
elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
|
25
|
-
if c_level < 0
|
26
|
-
compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), 0, true)
|
27
|
-
else
|
28
|
-
compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), c_level, false)
|
29
|
-
end
|
30
|
-
elsif m = /\A\<(\d+)\>\Z/.match(str)
|
31
|
-
stack[m[1].to_i]
|
32
|
-
else
|
33
|
-
if s_level < 0
|
34
|
-
smith(str, 0, true)
|
35
|
-
else
|
36
|
-
smith(str, s_level, false)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def compose(main, sub, level, outsourcing)
|
42
|
-
main_k, sub_k = main.kind, sub.kind
|
43
|
-
main_s, sub_s = main.star, sub.star
|
44
|
-
main_main, sub_main = main.main, sub.main
|
45
|
-
main_sub, sub_sub = main.sub, sub.sub
|
46
|
-
para = Vec.new(9, 0)
|
47
|
-
ele = Vec.new(3, 0)
|
48
|
-
|
49
|
-
# 9パラメータ
|
50
|
-
coef = Equip9[main_k].dup
|
51
|
-
para[] = coef
|
52
|
-
para.add!(level).e_div!(2)
|
53
|
-
para.e_mul!(sub.para).e_div!(100)
|
54
|
-
coef.sub!(Equip9[sub_k])
|
55
|
-
coef.add!( 100 + (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) )
|
56
|
-
coef.add!(Material9[main_main]).sub!(Material9[sub_main])
|
57
|
-
coef.e_mul!(EquipFilter[main_k])
|
58
|
-
para.e_mul!(coef).e_div!( main_k==sub_k ? 200 : 100 )
|
59
|
-
para.add!(main.para)
|
60
|
-
|
61
|
-
# エレメント
|
62
|
-
ele[] = sub.element
|
63
|
-
ele.e_mul!([75, level].min).e_div!( main_k==sub_k ? 200 : 100 )
|
64
|
-
ele.add!(main.element)
|
65
|
-
|
66
|
-
ret = new(main_k, main.weight+sub.weight, main_s+sub_s, main_sub, sub_main, para, ele)
|
67
|
-
ret.total_cost.add!(main.total_cost).add!(sub.total_cost)
|
68
|
-
ret.total_cost[1] += ret.comp_cost(outsourcing)
|
69
|
-
ret
|
70
|
-
end
|
71
|
-
|
72
|
-
def smith(str, level, outsourcing)
|
73
|
-
str = Mgmg.check_string(str)
|
74
|
-
unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
|
75
|
-
raise InvalidSmithError.new(str)
|
76
|
-
end
|
77
|
-
kind = EquipIndex[m[1].to_sym]
|
78
|
-
unless kind
|
79
|
-
raise InvalidEquipClassError.new(m[1])
|
80
|
-
end
|
81
|
-
main_m, main_s, main_mc = parse_material(m[2])
|
82
|
-
sub_m, sub_s, sub_mc = parse_material(m[3])
|
83
|
-
para = Vec.new(9, 0)
|
84
|
-
ele = Vec.new(3, 0)
|
85
|
-
|
86
|
-
# 9パラメータ
|
87
|
-
para[] = Equip9[kind]
|
88
|
-
para.e_mul!(Main9[main_m]).e_div!(100)
|
89
|
-
coef = Sub9[sub_m].dup
|
90
|
-
coef.add!(level)
|
91
|
-
para.e_mul!(coef).e_div!( main_mc==sub_mc ? 200 : 100 )
|
92
|
-
|
93
|
-
# エレメント
|
94
|
-
ele[] = MainEL[main_m]
|
95
|
-
ele.e_mul!(SubEL[sub_m]).e_div!(6)
|
96
|
-
|
97
|
-
# 重量
|
98
|
-
weight = ( ( EquipWeight[kind] + SubWeight[sub_m] - level.div(2) ) * ( MainWeight[main_m] ) ).div(10000)
|
99
|
-
|
100
|
-
ret = new(kind, ( weight<1 ? 1 : weight ), (main_s+sub_s).div(2), main_mc, sub_mc, para, ele)
|
101
|
-
if kind < 8
|
102
|
-
ret.total_cost[0] = ret.smith_cost(outsourcing)
|
103
|
-
else
|
104
|
-
ret.total_cost[2] = ret.smith_cost(outsourcing)
|
105
|
-
end
|
106
|
-
ret
|
107
|
-
end
|
108
|
-
|
109
|
-
def min_level(str, weight=1)
|
110
|
-
str = Mgmg.check_string(str)
|
111
|
-
unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
|
112
|
-
raise InvalidSmithError.new(str)
|
113
|
-
end
|
114
|
-
kind = EquipIndex[m[1].to_sym]
|
115
|
-
main_m, main_s, = parse_material(m[2])
|
116
|
-
sub_m, sub_s, = parse_material(m[3])
|
117
|
-
|
118
|
-
q, r = ((weight+1)*10000).divmod(MainWeight[main_m])
|
119
|
-
l = ( EquipWeight[kind] + SubWeight[sub_m] - q + ( r==0 ? 1 : 0 ) )*2
|
120
|
-
[(main_s-1)*3, (sub_s-1)*3, l].max
|
121
|
-
end
|
122
|
-
|
123
|
-
private def parse_material(str)
|
124
|
-
m = /\A.+?(\d+)\Z/.match(str)
|
125
|
-
mat = MaterialIndex[str.to_sym]
|
126
|
-
if m.nil? || mat.nil?
|
127
|
-
raise InvalidMaterialError.new(str)
|
128
|
-
end
|
129
|
-
[mat, m[1].to_i, mat<90 ? mat.div(10): 9]
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
1
|
+
require_relative './mgmg/version'
|
2
|
+
require_relative './mgmg/utils'
|
3
|
+
require_relative './mgmg/const'
|
4
|
+
require_relative './mgmg/equip'
|
5
|
+
require_relative './mgmg/poly'
|
6
|
+
require_relative './mgmg/system_equip'
|
7
|
+
require_relative './mgmg/search'
|
8
|
+
require_relative './mgmg/optimize'
|
133
9
|
|
134
10
|
class String
|
135
11
|
def min_level(w=1)
|
136
12
|
Mgmg::Equip.min_level(self, w)
|
137
13
|
end
|
138
|
-
def
|
14
|
+
def min_levels(left_associative: true)
|
15
|
+
build(-1, -1, left_associative: left_associative).min_levels
|
16
|
+
end
|
17
|
+
def min_smith(left_associative: true)
|
18
|
+
Mgmg::Equip.min_smith(self, left_associative: left_associative)
|
19
|
+
end
|
20
|
+
def min_comp(left_associative: true)
|
21
|
+
Mgmg::Equip.min_comp(self, left_associative: left_associative)
|
22
|
+
end
|
23
|
+
def build(smith=-1, comp=smith, left_associative: true)
|
139
24
|
Mgmg::Equip.build(self, smith, comp, left_associative: left_associative)
|
140
25
|
end
|
141
|
-
def poly(para, left_associative: true)
|
26
|
+
def poly(para=:cost, left_associative: true)
|
27
|
+
la = left_associative
|
142
28
|
case para
|
143
29
|
when :atkstr
|
144
|
-
self.poly(:attack) + self.poly(:str)
|
30
|
+
self.poly(:attack, left_associative: la) + self.poly(:str, left_associative: la)
|
145
31
|
when :atk_sd
|
146
|
-
self.poly(:attack) + self.poly(:str).quo(2) + self.poly(:dex).quo(2)
|
32
|
+
self.poly(:attack) + self.poly(:str, left_associative: la).quo(2) + self.poly(:dex, left_associative: la).quo(2)
|
147
33
|
when :dex_as
|
148
|
-
self.poly(:dex) + self.poly(:attack).quo(2) + self.poly(:str).quo(2)
|
34
|
+
self.poly(:dex) + self.poly(:attack, left_associative: la).quo(2) + self.poly(:str, left_associative: la).quo(2)
|
149
35
|
when :mag_das
|
150
|
-
self.poly(:magic) + self.poly(:dex_as).quo(2)
|
36
|
+
self.poly(:magic) + self.poly(:dex_as, left_associative: la).quo(2)
|
151
37
|
when :magmag
|
152
|
-
self.poly(:magdef) + self.poly(:magic).quo(2)
|
38
|
+
self.poly(:magdef) + self.poly(:magic, left_associative: la).quo(2)
|
153
39
|
when :cost
|
154
40
|
if Mgmg::SystemEquip.keys.include?(self)
|
155
41
|
return Mgmg::TPolynomial.new(Mgmg::Mat.new(1, 1, 0.quo(1)), 28, 0, 12, 12)
|
156
42
|
end
|
157
43
|
built = self.build(-1)
|
158
44
|
const = (built.star**2) * ( /\+/.match(self) ? 5 : ( built.kind < 8 ? 2 : 1 ) )
|
159
|
-
ret = poly(:attack) + poly(:phydef) + poly(:magdef)
|
160
|
-
ret += poly(:hp).quo(4) + poly(:mp).quo(4)
|
161
|
-
ret += poly(:str) + poly(:dex) + poly(:speed) + poly(:magic)
|
45
|
+
ret = poly(:attack, left_associative: la) + poly(:phydef, left_associative: la) + poly(:magdef, left_associative: la)
|
46
|
+
ret += poly(:hp, left_associative: la).quo(4) + poly(:mp, left_associative: la).quo(4)
|
47
|
+
ret += poly(:str, left_associative: la) + poly(:dex, left_associative: la) + poly(:speed, left_associative: la) + poly(:magic, left_associative: la)
|
162
48
|
ret.mat.body[0][0] += const
|
163
49
|
ret
|
164
50
|
else
|
165
|
-
Mgmg::TPolynomial.build(self, para, left_associative:
|
51
|
+
Mgmg::TPolynomial.build(self, para, left_associative: la)
|
166
52
|
end
|
167
53
|
end
|
168
|
-
def
|
54
|
+
def eff(para, smith, comp=smith, left_associative: true)
|
55
|
+
a = build(smith, comp, left_associative: left_associative).para_call(para)
|
56
|
+
b = build(smith+1, comp, left_associative: left_associative).para_call(para)
|
57
|
+
c = build(smith, comp+2, left_associative: left_associative).para_call(para)
|
58
|
+
sden = smith==0 ? 1 : 2*smith-1
|
59
|
+
cden = comp==0 ? 4 : 8*comp
|
60
|
+
[(b-a).quo(sden), (c-a).quo(cden)]
|
61
|
+
end
|
62
|
+
def peff(para, smith, comp=smith, left_associative: true)
|
63
|
+
poly(para, left_associative: left_associative).eff(smith, comp)
|
64
|
+
end
|
65
|
+
def show(smith=-1, comp=smith, left_associative: true)
|
169
66
|
built = self.build(smith, comp, left_associative: left_associative)
|
170
67
|
pstr = '%.3f' % built.fpower
|
171
68
|
pstr.sub!(/\.?0+\Z/, '')
|
@@ -174,9 +71,15 @@ class String
|
|
174
71
|
puts "with levels (#{smith}, #{comp}) yields (#{pstr}, #{built.total_cost})"
|
175
72
|
puts " #{built}"
|
176
73
|
end
|
74
|
+
def phydef_optimize(smith=nil, comp=smith, left_associative: true, magdef_maximize: true)
|
75
|
+
Mgmg::Optimize.phydef_optimize(self, smith, comp, left_associative: left_associative, magdef_maximize: magdef_maximize)
|
76
|
+
end
|
77
|
+
def buster_optimize(smith=nil, comp=smith, left_associative: true)
|
78
|
+
Mgmg::Optimize.buster_optimize(self, smith, comp, left_associative: left_associative)
|
79
|
+
end
|
177
80
|
end
|
178
81
|
module Enumerable
|
179
|
-
def build(smith, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
|
82
|
+
def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
|
180
83
|
self.map do |str|
|
181
84
|
m = /\A\[*([^\+]+)/.match(str)
|
182
85
|
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
@@ -186,4 +89,37 @@ module Enumerable
|
|
186
89
|
end
|
187
90
|
end.sum
|
188
91
|
end
|
92
|
+
def min_levels(left_associative: true)
|
93
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels
|
94
|
+
end
|
95
|
+
def min_level(left_associative: true)
|
96
|
+
ret = [0, 0]
|
97
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels.each do |str, level|
|
98
|
+
m = /\A\[*([^\+]+)/.match(str)
|
99
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
100
|
+
ret[0] = [ret[0], level].max
|
101
|
+
else
|
102
|
+
ret[1] = [ret[1], level].max
|
103
|
+
end
|
104
|
+
end
|
105
|
+
ret
|
106
|
+
end
|
107
|
+
def min_smith(left_associative: true)
|
108
|
+
ret = [0, 0]
|
109
|
+
self.each do |str|
|
110
|
+
s = Mgmg::Equip.min_smith(str, left_associative: left_associative)
|
111
|
+
m = /\A\[*([^\+]+)/.match(str)
|
112
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
113
|
+
ret[0] = [ret[0], s].max
|
114
|
+
else
|
115
|
+
ret[1] = [ret[1], s].max
|
116
|
+
end
|
117
|
+
end
|
118
|
+
ret
|
119
|
+
end
|
120
|
+
def min_comp(left_associative: true)
|
121
|
+
self.map do |str|
|
122
|
+
Mgmg::Equip.min_comp(str, left_associative: left_associative)
|
123
|
+
end.max
|
124
|
+
end
|
189
125
|
end
|