mgmg 1.2.5 → 1.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26c10a350028b972409920fe3aa4f57cfe8154a2b4dca70cc94342275e9fbe73
4
- data.tar.gz: b2dc70384ffa9aca8b475ce30505f091375b7d68a7cf43e925cfb9a00b0b18b8
3
+ metadata.gz: 48ad2b791e601abcf8108fcfceabed64d97b5beeb949e3b409fcb0ef7de148ed
4
+ data.tar.gz: 2154c226324c09f202a660bef0b344c3ee57a792dc14e889a9caedb79e5adfb8
5
5
  SHA512:
6
- metadata.gz: 3895e9496d5aba7be3431e1268c4bf7cb8eaa48b628fe19c6179531925e5809478d827e101cd4c6e68031c2296607818c99dd905ea33cecc9bdd51486c2c69a5
7
- data.tar.gz: 548d89140bcdf08c3d00cd7b8573c43e5de721e25a59771af9cb492a9c3dc6a26b93618d6a431ab86951ed1666ca9c6000506622105b4fb5a61716458ea02730
6
+ metadata.gz: a40d7b79dd7666a8fc1aa3985bd79f074d80f26ddd28b3c92cdef826edb28406154f3151fe1de5583a4ec3139d6710f71390f7fa60e1c896f2d9452f3dd00b70
7
+ data.tar.gz: cf7c8fe93611cad843f0bca7da77f02c24fbe5f7c2b932741f8ce94c80b73df1f355501521b6aabad99a17670d1649f5c7637721974bd096b6eb70726825d0b7
@@ -80,3 +80,10 @@
80
80
  - `Mgmg::TPolynomial#leading(fmt=nil)`, `Mgmg::TPolynomial#[](i, j)`を追加.
81
81
  - `Mgmg::Equip#history`, `Mgmg::Equip#min_levels`, `Mgmg::Equip#min_level`を追加.
82
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`を追加.
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
- puts %w|本(金3骨1)+[弓(骨1綿1)+[杖(金3金3)+[弓(綿1綿1)+[杖(宝10金6)+本(骨9鉄2)]]]] フード(石10骨9) 首飾り(宝10水10) 指輪(木10金10)|.build(122, 139, 232)
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(-1)
68
+ puts '小竜咆哮'.build
60
69
  #=> 弓1☆10(木骨)[攻撃:50, 器用:120, 素早:50]
61
70
  ```
62
71
 
@@ -78,26 +87,36 @@ 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
- 'ローブ(綿10皮10)+歴戦の服'
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(-1).weight`で確認する必要があります.`weight`を省略した場合,重量1となる製作Lvを返します.
107
+ `self`を`weight`以下で作るための最低製作Lvを返します.`build`と異なり,合成や既成品は解釈できません.また,素材の☆による最低製作Lvとのmaxを返すため,街の鍛冶・防具製作屋に頼んだ場合の重量は`self.build.weight`で確認する必要があります.`weight`を省略した場合,重量1となる製作Lvを返します.
96
108
 
97
- ### `Enumerable#build(smith, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)`
98
- 複数のレシピ文字列からなる`self`の各要素を製作し,そのすべてを装備したときの`Mgmg::Equip`を返します.製作では`鍛冶Lv=smith`, `防具製作Lv=armor`, `道具製作Lv=comp`とします.1つしか指定しなければすべてそのLv,2つなら1つ目を`smith=armor`,2つ目を`comp`に,3つならそれぞれの値とします.`left_associative`はそのまま`String#build`に渡されます.製作Lvが負の場合,製作Lv0として計算した上で,消費エレメント量は街の製作屋に頼んだ場合の値を計算します.武器複数など,同時装備が不可能な場合でも,特にチェックはされません.
109
+ ### `String#min_levels(left_associative: true)`
110
+ 合成レシピの各鍛冶・防具製作品に対して,レシピ文字列をキー,重量1で作製するために必要な製作Lvを値とした`Hash`を返します.重量1以外は指定できません.
111
+ 最大値は,`self.build.min_level`によって得られます.
112
+
113
+ ### `String#min_comp(left_associative: true)`
114
+ レシピ通りに合成するのに必要な道具製作Lvを返します.ただし,全体が「[]」で囲われているか,非合成レシピの場合,代わりに`0`を返します.
99
115
 
100
- ### `String#poly(para, left_associative: true)`
116
+ ### `String#min_smith(left_associative: true)`
117
+ レシピ通りに製作するのに必要な鍛冶・防具製作Lvを返します.製作物の重量については考慮せず,鍛冶・防具製作に必要な☆条件を満たすために必要な製作Lvを返します.
118
+
119
+ ### `String#poly(para=:cost, left_associative: true)`
101
120
  レシピ文字列である`self`を解釈し,`para`で指定した9パラ値について,丸めを無視した鍛冶・防具製作Lvと道具製作Lvの2変数からなる多項式関数を示す`Mgmg::TPolynomial`クラスのインスタンスを生成し,返します.`para`は次のシンボルのいずれかを指定します.
102
121
  ```ruby
103
122
  :attack, :phydef, :magdef, :hp, :mp, :str, :dex, :speed, :magic
@@ -112,6 +131,27 @@ puts '小竜咆哮'.build(-1)
112
131
 
113
132
  また,`:cost`を渡すことで,消費エレメント量に関する近似多項式を得られます.`self`に`"+"`が含まれていれば合成品とみなし,最後の合成に必要な地エレメント量を,それ以外では,武器なら消費火エレメント量を,防具なら消費水エレメント量を返します.ただし,`self`が既成品そのものの場合,零多項式を返します.
114
133
 
134
+ ### `String#smith_seach(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true)`
135
+ `para`の値が`target`以上となるのに必要な最小の鍛冶・防具製作Lvを二分探索で探索して返します.
136
+ 道具製作Lvは`comp`で固定,鍛冶・防具製作Lvを`smith_min`と`smith_max`で挟み込んで探索します.
137
+ `smith_min`が`nil`のとき,最小重量で製作するのに必要な鍛冶・防具製作Lv (`self.build.min_level`)を使用します.
138
+ 重量を無視して,製作に必要な最小Lvである`self.min_smith`まで探索したい場合,明示的に指定します.
139
+ `smith_min<smith_max`でないとき,`smith_max`で`para`が`target`以上でないときは`ArgumentError`となります.
140
+ `para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
141
+ 反転などの影響で,探索範囲において`para`の値が(広義)単調増加になっていない場合,正しい結果を返しません.
142
+
143
+ ### `String#comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)`
144
+ `String#smith_seach`とは逆に,鍛冶・防具製作Lvを固定して最小の道具製作Lvを探索します.
145
+ `comp_min`が`nil`のときは,製作に必要な最小の道具製作Lv (`self.min_comp`)を使用します.
146
+ その他は`String#smith_seach`と同様です.
147
+
148
+ ### `String#eff(para, smith, comp=smith, left_associative: true)`
149
+ [`smith`を1上げたときの`para`値/(`smith`を1上げるのに必要な経験値), `comp`を1上げたときの`para`値/(`comp`を2上げるのに必要な経験値)]を返します.
150
+ `para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
151
+
152
+ ### `String#peff(para, smith, comp=smith, left_associative: true)`
153
+ 近似多項式における偏微分値を使用した場合の,`String#eff`と同様の値を返します.`self.poly(para, left_associative: left_associative).eff(smith, comp)`と等価です.
154
+
115
155
  ### `Mgmg::Equip`
116
156
  前述の`String#build`によって生成される装備品のクラスです.複数装備の合計値を表す「複数装備」という種別の装備品の場合もあります.以下のようなインスタンスメソッドが定義されています.
117
157
 
@@ -222,10 +262,10 @@ ver2.00β12以降では武器なら火,防具なら水エレメントと半々
222
262
  `Mgmg::TPolynomial#to_s`と同様ですが,鍛冶・防具製作Lvを`s`,道具製作Lvを`c`としたRubyの式として解釈可能な文字列を返します.つまり,係数をリテラル,掛け算を`*`で表現しています.`fmt`は`Mgmg::TPolynomial#to_s`と同様で,適当な値を指定することでRuby以外の言語でも解釈可能になります.例えば,精度が問題でないならば,`'%e'`とすると,大抵の言語で解釈可能な文字列を生成できます.
223
263
 
224
264
  ### `Mgmg::TPolynomial#leading(fmt=nil)`
225
- 最高次係数を返します.`fmt`が`nil`なら数値(`Rational`)をそのまま,それ以外なら`Mgmg::TPolynomial#to_s`と同様の方式で文字列に変換して返します.
265
+ 最高次係数を返します.`fmt`が`nil`なら数値(`Rational`)をそのまま,それ以外なら`Mgmg::TPolynomial#to_s`と同様の方式で文字列に変換して返します.ただし,レシピの段数に応じた最高次数を返すため,レシピ次第では本メソッドの返り値が`0`となり,それより低い次数の項が最高次となることもあり得ます.そのようなケースでの真の最高次の探索はしません.
226
266
 
227
267
  ### `Mgmg::TPolynomial#[](i, j)`
228
- 鍛冶・防具製作LvをS,道具製作LvをCとして,S<sup>i</sup>C<sup>j</sup> の係数を返します.負の値を指定すると,最高次から降順に数えた次数の項の係数を返します.例えば`i, j = -1, -1`なら,最高次の係数となります.引数が正で範囲外なら`0`を返し,負で範囲外なら`IndexError`を上げます.
268
+ 鍛冶・防具製作Lvをs,道具製作Lvをcとして,s<sup>i</sup>c<sup>j</sup> の係数を返します.負の値を指定すると,最高次から降順に数えた次数の項の係数を返します.例えば`i, j = -1, -1`なら,最高次の係数となります.引数が正で範囲外なら`0`を返し,負で範囲外なら`IndexError`を上げます.
229
269
 
230
270
  ### `Mgmg::TPolynomial#evaluate(smith, comp=smith)`
231
271
  鍛冶・防具製作Lvを`smith`,道具製作Lvを`comp`として値を計算します.丸めを無視しているため,実際の合成結果以上の値が返ります.
@@ -245,6 +285,10 @@ alias として`*`があるほか`scalar(1.quo(value))`として`quo`,`/`,`s
245
285
  多項式として偏微分し,その微分係数を返します.
246
286
  `variable`はどの変数で偏微分するかを指定するもので,`"s"`なら鍛冶・防具製作Lv,`"c"`なら道具製作Lvで偏微分します.
247
287
 
288
+ ### `Mgmg::TPolynomial#eff(smith, comp=smith)`
289
+ 製作Lv(`smith`, `comp`)における鍛冶・防具製作Lv効率と道具製作Lv効率からなる配列を返します.
290
+ 一方のみが欲しい場合,`Mgmg::TPolynomial#smith_eff(smith, comp=smith)`,`Mgmg::TPolynomial#smith_eff(smith, comp=smith)`が使えます.
291
+
248
292
  ## 謝辞
249
293
  面白いゲームを作ってくださった耕様および,高精度なシミュレータを作製し,本ライブラリの作製を可能とした,Excel版装備計算機の作者様に感謝いたします.
250
294
 
@@ -9,10 +9,19 @@ class String
9
9
  def min_level(w=1)
10
10
  Mgmg::Equip.min_level(self, w)
11
11
  end
12
- def build(smith, comp=smith, left_associative: true)
12
+ def min_levels(left_associative: true)
13
+ build(-1, -1, left_associative: left_associative).min_levels
14
+ end
15
+ def min_smith(left_associative: true)
16
+ Mgmg::Equip.min_smith(self, left_associative: left_associative)
17
+ end
18
+ def min_comp(left_associative: true)
19
+ Mgmg::Equip.min_comp(self, left_associative: left_associative)
20
+ end
21
+ def build(smith=-1, comp=smith, left_associative: true)
13
22
  Mgmg::Equip.build(self, smith, comp, left_associative: left_associative)
14
23
  end
15
- def poly(para, left_associative: true)
24
+ def poly(para=:cost, left_associative: true)
16
25
  case para
17
26
  when :atkstr
18
27
  self.poly(:attack) + self.poly(:str)
@@ -39,7 +48,58 @@ class String
39
48
  Mgmg::TPolynomial.build(self, para, left_associative: left_associative)
40
49
  end
41
50
  end
42
- def show(smith, comp=smith, left_associative: true)
51
+ def eff(para, smith, comp=smith, left_associative: true)
52
+ a = build(smith, comp, left_associative: left_associative).method(para).call
53
+ b = build(smith+1, comp, left_associative: left_associative).method(para).call
54
+ c = build(smith, comp+2, left_associative: left_associative).method(para).call
55
+ sden = smith==0 ? 1 : 2*smith-1
56
+ cden = comp==0 ? 4 : 8*comp
57
+ [(b-a).quo(sden), (c-a).quo(cden)]
58
+ end
59
+ def peff(para, smith, comp=smith, left_associative: true)
60
+ poly(para, left_associative: left_associative).eff(smith, comp)
61
+ end
62
+ def smith_search(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true)
63
+ smith_min = build(-1, -1, left_associative: left_associative).min_level if smith_min.nil?
64
+ if smith_max < smith_min
65
+ raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
66
+ end
67
+ if target <= build(smith_min, comp, left_associative: left_associative).method(para).call
68
+ return smith_min
69
+ elsif build(smith_max, comp, left_associative: left_associative).method(para).call < target
70
+ raise ArgumentError, "given smith_max=#{smith_max} does not satisfies the target"
71
+ end
72
+ while 1 < smith_max - smith_min do
73
+ smith = (smith_max - smith_min).div(2) + smith_min
74
+ if build(smith, comp, left_associative: left_associative).method(para).call < target
75
+ smith_min = smith
76
+ else
77
+ smith_max = smith
78
+ end
79
+ end
80
+ smith_max
81
+ end
82
+ def comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)
83
+ comp_min = min_comp(left_associative: left_associative)
84
+ if comp_max < comp_min
85
+ raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
86
+ end
87
+ if target <= build(smith, comp_min, left_associative: left_associative).method(para).call
88
+ return comp_min
89
+ elsif build(smith, comp_max, left_associative: left_associative).method(para).call < target
90
+ raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
91
+ end
92
+ while 1 < comp_max - comp_min do
93
+ comp = (comp_max - comp_min).div(2) + comp_min
94
+ if build(smith, comp, left_associative: left_associative).method(para).call < target
95
+ comp_min = comp
96
+ else
97
+ comp_max = comp
98
+ end
99
+ end
100
+ comp_max
101
+ end
102
+ def show(smith=-1, comp=smith, left_associative: true)
43
103
  built = self.build(smith, comp, left_associative: left_associative)
44
104
  pstr = '%.3f' % built.fpower
45
105
  pstr.sub!(/\.?0+\Z/, '')
@@ -50,7 +110,7 @@ class String
50
110
  end
51
111
  end
52
112
  module Enumerable
53
- def build(smith, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
113
+ def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
54
114
  self.map do |str|
55
115
  m = /\A\[*([^\+]+)/.match(str)
56
116
  if Mgmg::EquipPosition[m[1].build(0).kind] == 0
@@ -68,7 +68,7 @@ module Mgmg
68
68
  end
69
69
  ret
70
70
  else
71
- @min_levels.values.max
71
+ @min_levels.values.append(0).max
72
72
  end
73
73
  end
74
74
 
@@ -319,5 +319,74 @@ module Mgmg
319
319
  end
320
320
  [mat, m[1].to_i, mat<90 ? mat.div(10): 9]
321
321
  end
322
+
323
+ def min_comp(str, left_associative: true)
324
+ str = Mgmg.check_string(str)
325
+ stack, str = minc_sub0([], str)
326
+ (minc_sub(stack, str, left_associative)[1]-1)*3
327
+ end
328
+ private def minc_sub0(stack, str)
329
+ SystemEquip.each do |k, v|
330
+ if Regexp.compile(k).match(str)
331
+ stack << v.star
332
+ str = str.gsub(k, "<#{stack.length-1}>")
333
+ end
334
+ end
335
+ [stack, str]
336
+ end
337
+ private def minc_sub(stack, str, lassoc)
338
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
339
+ stack << minc_sub(stack, m[2], lassoc)[0]
340
+ minc_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
341
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
342
+ a, _ = minc_sub(stack, m[1], lassoc)
343
+ b, _ = minc_sub(stack, m[2], lassoc)
344
+ [a+b, [a, b].max]
345
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
346
+ [stack[m[1].to_i], 1]
347
+ else
348
+ [smith(str, 0, true).star, 1]
349
+ end
350
+ end
351
+
352
+ def min_smith(str, left_associative: true)
353
+ str = Mgmg.check_string(str)
354
+ stack, str = mins_sub0([], str)
355
+ (([mins_sub(stack, str, left_associative)]+stack).max-1)*3
356
+ end
357
+ private def mins_sub0(stack, str)
358
+ SystemEquip.each do |k, v|
359
+ if Regexp.compile(k).match(str)
360
+ stack << 0
361
+ str = str.gsub(k, "<#{stack.length-1}>")
362
+ end
363
+ end
364
+ [stack, str]
365
+ end
366
+ private def mins_sub(stack, str, lassoc)
367
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
368
+ stack << mins_sub(stack, m[2], lassoc)
369
+ mins_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
370
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
371
+ [mins_sub(stack, m[1], lassoc), mins_sub(stack, m[2], lassoc)].max
372
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
373
+ 1
374
+ else
375
+ mins_sub2(str)
376
+ end
377
+ end
378
+ private def mins_sub2(str)
379
+ str = Mgmg.check_string(str)
380
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
381
+ raise InvalidSmithError.new(str)
382
+ end
383
+ kind = EquipIndex[m[1].to_sym]
384
+ unless kind
385
+ raise InvalidEquipClassError.new(m[1])
386
+ end
387
+ main_m, main_s, main_mc = parse_material(m[2])
388
+ sub_m, sub_s, sub_mc = parse_material(m[3])
389
+ [main_s, sub_s].max
390
+ end
322
391
  end
323
392
  end
@@ -183,6 +183,15 @@ module Mgmg
183
183
  raise ArgumentError, "the argument must be `s' or `c', not `#{variable}'"
184
184
  end
185
185
  end
186
+ def smith_eff(smith, comp=smith)
187
+ partial_derivative('s').evaluate(smith, comp).quo(2*(smith-1))
188
+ end
189
+ def comp_eff(smith, comp=smith)
190
+ partial_derivative('c').evaluate(smith, comp).quo(4*(comp-1))
191
+ end
192
+ def eff(smith, comp=smith)
193
+ [smith_eff(smith, comp), comp_eff(smith, comp)]
194
+ end
186
195
 
187
196
  def [](i, j)
188
197
  if (i < 0 && @mat.body.size < -i) || (j < 0 && @mat.body[0].size < -j)
@@ -47,6 +47,10 @@ module Mgmg
47
47
  attr_accessor :equip
48
48
  end
49
49
 
50
+ module_function def exp(smith, comp)
51
+ ((smith-1)**2) + (2*((comp-1)**2)) + 3
52
+ end
53
+
50
54
  CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/
51
55
  module_function def check_string(str)
52
56
  str = str.gsub(/[\s \\]/, '')
@@ -1,3 +1,3 @@
1
1
  module Mgmg
2
- VERSION = "1.2.5"
2
+ VERSION = "1.3.0"
3
3
  end
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.2.5
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - KAZOON
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-21 00:00:00.000000000 Z
11
+ date: 2020-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler