mgmg 1.3.0 → 1.3.1
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 +6 -0
- data/README.md +27 -5
- data/lib/mgmg.rb +47 -52
- data/lib/mgmg/equip.rb +4 -0
- data/lib/mgmg/search.rb +230 -0
- data/lib/mgmg/utils.rb +37 -2
- data/lib/mgmg/version.rb +1 -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: 5ae250ef7035838c1f0598c419e66259c1cde7ab692e5b5ffefcd78ab845207d
|
4
|
+
data.tar.gz: 0fd5f62e8c3ac85ba990010bca631e08111b50d69fad11d782fcadfe075781fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40bdd74efb69a024d87d265340caefd48ee90f4d3fd9d74d2a7a46fd78c6a553bc931798636b1ebc8bed8e95cfa8c6501a554c073897ac0ae9be3fdd37298466
|
7
|
+
data.tar.gz: 9c32dfaf9a0d1027afd33e70562e813f7cce5a0378e0e81f806e77e3d4415ee4d779a09b7d3b122d523d9a0f8cc10af1a97da0ee3e3464440777b82efee35c48
|
data/CHANGELOG.md
CHANGED
@@ -87,3 +87,9 @@
|
|
87
87
|
- `String#poly`のデフォルト引数を`:cost`に設定.
|
88
88
|
- `Mgmg.#exp`,`String#eff`,`String#peff`,`String#min_levels`を追加.
|
89
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`を追加.
|
data/README.md
CHANGED
@@ -110,12 +110,23 @@ puts '小竜咆哮'.build
|
|
110
110
|
合成レシピの各鍛冶・防具製作品に対して,レシピ文字列をキー,重量1で作製するために必要な製作Lvを値とした`Hash`を返します.重量1以外は指定できません.
|
111
111
|
最大値は,`self.build.min_level`によって得られます.
|
112
112
|
|
113
|
-
### `
|
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)`
|
114
121
|
レシピ通りに合成するのに必要な道具製作Lvを返します.ただし,全体が「[]」で囲われているか,非合成レシピの場合,代わりに`0`を返します.
|
115
122
|
|
116
|
-
|
123
|
+
`Enumerable`の場合,すべての要素に対する最大値を返します.
|
124
|
+
|
125
|
+
### `String#min_smith(left_associative: true)`,`Enumerable#min_smith(left_associative: true)`
|
117
126
|
レシピ通りに製作するのに必要な鍛冶・防具製作Lvを返します.製作物の重量については考慮せず,鍛冶・防具製作に必要な☆条件を満たすために必要な製作Lvを返します.
|
118
127
|
|
128
|
+
`Enumerable`の場合,すべての要素に対し,武器,防具それぞれの最大値を求め,`[必要最小鍛冶Lv, 必要最小防具製作Lv]`を返します.
|
129
|
+
|
119
130
|
### `String#poly(para=:cost, left_associative: true)`
|
120
131
|
レシピ文字列である`self`を解釈し,`para`で指定した9パラ値について,丸めを無視した鍛冶・防具製作Lvと道具製作Lvの2変数からなる多項式関数を示す`Mgmg::TPolynomial`クラスのインスタンスを生成し,返します.`para`は次のシンボルのいずれかを指定します.
|
121
132
|
```ruby
|
@@ -131,20 +142,31 @@ puts '小竜咆哮'.build
|
|
131
142
|
|
132
143
|
また,`:cost`を渡すことで,消費エレメント量に関する近似多項式を得られます.`self`に`"+"`が含まれていれば合成品とみなし,最後の合成に必要な地エレメント量を,それ以外では,武器なら消費火エレメント量を,防具なら消費水エレメント量を返します.ただし,`self`が既成品そのものの場合,零多項式を返します.
|
133
144
|
|
134
|
-
### `String#smith_seach(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true)`
|
145
|
+
### `String#smith_seach(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)`
|
135
146
|
`para`の値が`target`以上となるのに必要な最小の鍛冶・防具製作Lvを二分探索で探索して返します.
|
136
147
|
道具製作Lvは`comp`で固定,鍛冶・防具製作Lvを`smith_min`と`smith_max`で挟み込んで探索します.
|
137
|
-
`smith_min`が`nil
|
138
|
-
重量を無視して,製作に必要な最小Lvである`self.min_smith`まで探索したい場合,明示的に指定します.
|
148
|
+
`smith_min`が`nil`のとき,`min_smith`が真なら重量を問わず☆的に必要な最小の鍛冶・防具製作Lv (`self.min_smith`),偽なら最小重量で製作するのに必要な鍛冶・防具製作Lv (`self.build.min_level`)を使用します.
|
139
149
|
`smith_min<smith_max`でないとき,`smith_max`で`para`が`target`以上でないときは`ArgumentError`となります.
|
140
150
|
`para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
|
141
151
|
反転などの影響で,探索範囲において`para`の値が(広義)単調増加になっていない場合,正しい結果を返しません.
|
152
|
+
`cut_exp`以下の経験値で`target`以上を達成できない場合,`Mgmg::SearchCutException`を発生します.
|
142
153
|
|
143
154
|
### `String#comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)`
|
144
155
|
`String#smith_seach`とは逆に,鍛冶・防具製作Lvを固定して最小の道具製作Lvを探索します.
|
145
156
|
`comp_min`が`nil`のときは,製作に必要な最小の道具製作Lv (`self.min_comp`)を使用します.
|
146
157
|
その他は`String#smith_seach`と同様です.
|
147
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
|
+
|
148
170
|
### `String#eff(para, smith, comp=smith, left_associative: true)`
|
149
171
|
[`smith`を1上げたときの`para`値/(`smith`を1上げるのに必要な経験値), `comp`を1上げたときの`para`値/(`comp`を2上げるのに必要な経験値)]を返します.
|
150
172
|
`para`は,`Mgmg::Equip`のメソッド名をシンボルで指定(`:power, :fpower`も可)します.
|
data/lib/mgmg.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative './mgmg/const'
|
|
4
4
|
require_relative './mgmg/equip'
|
5
5
|
require_relative './mgmg/poly'
|
6
6
|
require_relative './mgmg/system_equip'
|
7
|
+
require_relative './mgmg/search'
|
7
8
|
|
8
9
|
class String
|
9
10
|
def min_level(w=1)
|
@@ -22,36 +23,37 @@ class String
|
|
22
23
|
Mgmg::Equip.build(self, smith, comp, left_associative: left_associative)
|
23
24
|
end
|
24
25
|
def poly(para=:cost, left_associative: true)
|
26
|
+
la = left_associative
|
25
27
|
case para
|
26
28
|
when :atkstr
|
27
|
-
self.poly(:attack) + self.poly(:str)
|
29
|
+
self.poly(:attack, left_associative: la) + self.poly(:str, left_associative: la)
|
28
30
|
when :atk_sd
|
29
|
-
self.poly(:attack) + self.poly(:str).quo(2) + self.poly(:dex).quo(2)
|
31
|
+
self.poly(:attack) + self.poly(:str, left_associative: la).quo(2) + self.poly(:dex, left_associative: la).quo(2)
|
30
32
|
when :dex_as
|
31
|
-
self.poly(:dex) + self.poly(:attack).quo(2) + self.poly(:str).quo(2)
|
33
|
+
self.poly(:dex) + self.poly(:attack, left_associative: la).quo(2) + self.poly(:str, left_associative: la).quo(2)
|
32
34
|
when :mag_das
|
33
|
-
self.poly(:magic) + self.poly(:dex_as).quo(2)
|
35
|
+
self.poly(:magic) + self.poly(:dex_as, left_associative: la).quo(2)
|
34
36
|
when :magmag
|
35
|
-
self.poly(:magdef) + self.poly(:magic).quo(2)
|
37
|
+
self.poly(:magdef) + self.poly(:magic, left_associative: la).quo(2)
|
36
38
|
when :cost
|
37
39
|
if Mgmg::SystemEquip.keys.include?(self)
|
38
40
|
return Mgmg::TPolynomial.new(Mgmg::Mat.new(1, 1, 0.quo(1)), 28, 0, 12, 12)
|
39
41
|
end
|
40
42
|
built = self.build(-1)
|
41
43
|
const = (built.star**2) * ( /\+/.match(self) ? 5 : ( built.kind < 8 ? 2 : 1 ) )
|
42
|
-
ret = poly(:attack) + poly(:phydef) + poly(:magdef)
|
43
|
-
ret += poly(:hp).quo(4) + poly(:mp).quo(4)
|
44
|
-
ret += poly(:str) + poly(:dex) + poly(:speed) + poly(:magic)
|
44
|
+
ret = poly(:attack, left_associative: la) + poly(:phydef, left_associative: la) + poly(:magdef, left_associative: la)
|
45
|
+
ret += poly(:hp, left_associative: la).quo(4) + poly(:mp, left_associative: la).quo(4)
|
46
|
+
ret += poly(:str, left_associative: la) + poly(:dex, left_associative: la) + poly(:speed, left_associative: la) + poly(:magic, left_associative: la)
|
45
47
|
ret.mat.body[0][0] += const
|
46
48
|
ret
|
47
49
|
else
|
48
|
-
Mgmg::TPolynomial.build(self, para, left_associative:
|
50
|
+
Mgmg::TPolynomial.build(self, para, left_associative: la)
|
49
51
|
end
|
50
52
|
end
|
51
53
|
def eff(para, smith, comp=smith, left_associative: true)
|
52
|
-
a = build(smith, comp, left_associative: left_associative).
|
53
|
-
b = build(smith+1, comp, left_associative: left_associative).
|
54
|
-
c = build(smith, comp+2, left_associative: left_associative).
|
54
|
+
a = build(smith, comp, left_associative: left_associative).para_call(para)
|
55
|
+
b = build(smith+1, comp, left_associative: left_associative).para_call(para)
|
56
|
+
c = build(smith, comp+2, left_associative: left_associative).para_call(para)
|
55
57
|
sden = smith==0 ? 1 : 2*smith-1
|
56
58
|
cden = comp==0 ? 4 : 8*comp
|
57
59
|
[(b-a).quo(sden), (c-a).quo(cden)]
|
@@ -59,46 +61,6 @@ class String
|
|
59
61
|
def peff(para, smith, comp=smith, left_associative: true)
|
60
62
|
poly(para, left_associative: left_associative).eff(smith, comp)
|
61
63
|
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
64
|
def show(smith=-1, comp=smith, left_associative: true)
|
103
65
|
built = self.build(smith, comp, left_associative: left_associative)
|
104
66
|
pstr = '%.3f' % built.fpower
|
@@ -120,4 +82,37 @@ module Enumerable
|
|
120
82
|
end
|
121
83
|
end.sum
|
122
84
|
end
|
85
|
+
def min_levels(left_associative: true)
|
86
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels
|
87
|
+
end
|
88
|
+
def min_level(left_associative: true)
|
89
|
+
ret = [0, 0]
|
90
|
+
build(-1, -1, -1, left_associative: left_associative).min_levels.each do |str, level|
|
91
|
+
m = /\A\[*([^\+]+)/.match(str)
|
92
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
93
|
+
ret[0] = [ret[0], level].max
|
94
|
+
else
|
95
|
+
ret[1] = [ret[1], level].max
|
96
|
+
end
|
97
|
+
end
|
98
|
+
ret
|
99
|
+
end
|
100
|
+
def min_smith(left_associative: true)
|
101
|
+
ret = [0, 0]
|
102
|
+
self.each do |str|
|
103
|
+
s = Mgmg::Equip.min_smith(str, left_associative: left_associative)
|
104
|
+
m = /\A\[*([^\+]+)/.match(str)
|
105
|
+
if Mgmg::EquipPosition[m[1].build(0).kind] == 0
|
106
|
+
ret[0] = [ret[0], s].max
|
107
|
+
else
|
108
|
+
ret[1] = [ret[1], s].max
|
109
|
+
end
|
110
|
+
end
|
111
|
+
ret
|
112
|
+
end
|
113
|
+
def min_comp(left_associative: true)
|
114
|
+
self.map do |str|
|
115
|
+
Mgmg::Equip.min_comp(str, left_associative: left_associative)
|
116
|
+
end.max
|
117
|
+
end
|
123
118
|
end
|
data/lib/mgmg/equip.rb
CHANGED
data/lib/mgmg/search.rb
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
class String
|
2
|
+
def smith_search(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
|
3
|
+
if smith_min.nil?
|
4
|
+
if min_smith
|
5
|
+
smith_min = self.min_smith.min_smith
|
6
|
+
else
|
7
|
+
smith_min = build(-1, -1, left_associative: left_associative).min_level
|
8
|
+
end
|
9
|
+
end
|
10
|
+
if smith_max < smith_min
|
11
|
+
raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
|
12
|
+
elsif cut_exp < Float::INFINITY
|
13
|
+
begin
|
14
|
+
smith_max = [smith_max, Mgmg.invexp2(cut_exp, comp)].min
|
15
|
+
rescue
|
16
|
+
raise Mgmg::SearchCutException
|
17
|
+
end
|
18
|
+
end
|
19
|
+
if target <= build(smith_min, comp, left_associative: left_associative).para_call(para)
|
20
|
+
return smith_min
|
21
|
+
elsif build(smith_max, comp, left_associative: left_associative).para_call(para) < target
|
22
|
+
raise Mgmg::SearchCutException
|
23
|
+
end
|
24
|
+
while 1 < smith_max - smith_min do
|
25
|
+
smith = (smith_max - smith_min).div(2) + smith_min
|
26
|
+
if build(smith, comp, left_associative: left_associative).para_call(para) < target
|
27
|
+
smith_min = smith
|
28
|
+
else
|
29
|
+
smith_max = smith
|
30
|
+
end
|
31
|
+
end
|
32
|
+
smith_max
|
33
|
+
end
|
34
|
+
def comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)
|
35
|
+
comp_min = min_comp(left_associative: left_associative)
|
36
|
+
if comp_max < comp_min
|
37
|
+
raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
|
38
|
+
end
|
39
|
+
if target <= build(smith, comp_min, left_associative: left_associative).para_call(para)
|
40
|
+
return comp_min
|
41
|
+
elsif build(smith, comp_max, left_associative: left_associative).para_call(para) < target
|
42
|
+
raise Mgmg::SearchCutException
|
43
|
+
end
|
44
|
+
while 1 < comp_max - comp_min do
|
45
|
+
comp = (comp_max - comp_min).div(2) + comp_min
|
46
|
+
if build(smith, comp, left_associative: left_associative).para_call(para) < target
|
47
|
+
comp_min = comp
|
48
|
+
else
|
49
|
+
comp_max = comp
|
50
|
+
end
|
51
|
+
end
|
52
|
+
comp_max
|
53
|
+
end
|
54
|
+
def 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)
|
55
|
+
if smith_min.nil?
|
56
|
+
if min_smith
|
57
|
+
smith_min = self.min_smith
|
58
|
+
else
|
59
|
+
smith_min = build(-1, -1, left_associative: left_associative).min_level
|
60
|
+
end
|
61
|
+
end
|
62
|
+
comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
|
63
|
+
comp_min = comp_search(para, target, smith_max, comp_min, comp_max, left_associative: left_associative)
|
64
|
+
smith_max = smith_search(para, target, comp_min, smith_min, smith_max, left_associative: left_associative)
|
65
|
+
smith_min = smith_search(para, target, comp_max, smith_min, smith_max, left_associative: left_associative)
|
66
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, comp_min)
|
67
|
+
comp_max = comp_search(para, target, smith_min, comp_min, comp_max, left_associative: left_associative)
|
68
|
+
minex, ret = Mgmg.exp(smith_min, comp_max), [smith_min, comp_max]
|
69
|
+
exp = Mgmg.exp(smith_max, comp_min)
|
70
|
+
minex, ret = exp, [smith_max, comp_min] if exp < minex
|
71
|
+
(comp_min+step).step(comp_max-1, step) do |comp|
|
72
|
+
break if minex < Mgmg.exp(smith_min, comp)
|
73
|
+
smith = smith_search(para, target, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
|
74
|
+
exp = Mgmg.exp(smith, comp)
|
75
|
+
minex, ret = exp, [smith, comp] if exp < minex
|
76
|
+
rescue Mgmg::SearchCutException
|
77
|
+
end
|
78
|
+
raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
|
79
|
+
ret
|
80
|
+
end
|
81
|
+
end
|
82
|
+
module Enumerable
|
83
|
+
def smith_search(para, target, armor, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
|
84
|
+
if smith_min.nil?
|
85
|
+
if min_smith
|
86
|
+
smith_min = self.min_smith[0]
|
87
|
+
else
|
88
|
+
smith_min = build(-1, -1, -1, left_associative: left_associative).min_level[0]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
if smith_max < smith_min
|
92
|
+
raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
|
93
|
+
elsif cut_exp < Float::INFINITY
|
94
|
+
begin
|
95
|
+
smith_max = [smith_max, Mgmg.invexp3(cut_exp, armor, comp)].min
|
96
|
+
rescue
|
97
|
+
raise Mgmg::SearchCutException
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if build(smith_max, armor, comp, left_associative: left_associative).para_call(para) < target
|
101
|
+
raise Mgmg::SearchCutException
|
102
|
+
elsif target <= build(smith_min, armor, comp, left_associative: left_associative).para_call(para)
|
103
|
+
return smith_min
|
104
|
+
end
|
105
|
+
while 1 < smith_max - smith_min do
|
106
|
+
smith = (smith_max - smith_min).div(2) + smith_min
|
107
|
+
if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
|
108
|
+
smith_min = smith
|
109
|
+
else
|
110
|
+
smith_max = smith
|
111
|
+
end
|
112
|
+
end
|
113
|
+
smith_max
|
114
|
+
end
|
115
|
+
def armor_search(para, target, smith, comp, armor_min=nil, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
|
116
|
+
if armor_min.nil?
|
117
|
+
if min_smith
|
118
|
+
armor_min = self.min_smith[1]
|
119
|
+
else
|
120
|
+
armor_min = build(-1, -1, -1, left_associative: left_associative).min_level[1]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
if armor_max < armor_min
|
124
|
+
raise ArgumentError, "armor_min <= armor_max is needed, (armor_min, armor_max) = (#{armor_min}, #{armor_max}) are given"
|
125
|
+
elsif cut_exp < Float::INFINITY
|
126
|
+
begin
|
127
|
+
armor_max = [armor_max, Mgmg.invexp3(cut_exp, smith, comp)].min
|
128
|
+
rescue
|
129
|
+
raise Mgmg::SearchCutException
|
130
|
+
end
|
131
|
+
end
|
132
|
+
if build(smith, armor_max, comp, left_associative: left_associative).para_call(para) < target
|
133
|
+
raise Mgmg::SearchCutException
|
134
|
+
elsif target <= build(smith, armor_min, comp, left_associative: left_associative).para_call(para)
|
135
|
+
return armor_min
|
136
|
+
end
|
137
|
+
while 1 < armor_max - armor_min do
|
138
|
+
armor = (armor_max - armor_min).div(2) + armor_min
|
139
|
+
if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
|
140
|
+
armor_min = armor
|
141
|
+
else
|
142
|
+
armor_max = armor
|
143
|
+
end
|
144
|
+
end
|
145
|
+
armor_max
|
146
|
+
end
|
147
|
+
def sa_search(para, target, comp, smith_min=nil, armor_min=nil, smith_max=10000, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
|
148
|
+
if min_smith
|
149
|
+
s, a = self.min_smith
|
150
|
+
else
|
151
|
+
s, a = build(-1, -1, -1, left_associative: left_associative).min_level
|
152
|
+
end
|
153
|
+
smith_min = s if smith_min.nil?
|
154
|
+
armor_min = a if armor_min.nil?
|
155
|
+
smith_min = smith_search(para, target, armor_max, comp, smith_min, smith_max, left_associative: true)
|
156
|
+
armor_min = armor_search(para, target, smith_max, comp, armor_min, armor_max, left_associative: true)
|
157
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp)
|
158
|
+
smith_max = smith_search(para, target, armor_min, comp, smith_min, smith_max, left_associative: true)
|
159
|
+
armor_max = armor_search(para, target, smith_min, comp, armor_min, armor_max, left_associative: true)
|
160
|
+
minex, ret = Mgmg.exp(smith_min, armor_max, comp), [smith_min, armor_max]
|
161
|
+
exp = Mgmg.exp(smith_max, armor_min, comp)
|
162
|
+
if exp < minex
|
163
|
+
minex, ret = exp, [smith_max, armor_min]
|
164
|
+
(armor_min+1).upto(armor_max-1) do |armor|
|
165
|
+
break if minex < Mgmg.exp(smith_min, armor, comp)
|
166
|
+
smith = smith_search(para, target, armor, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
|
167
|
+
exp = Mgmg.exp(smith, armor, comp)
|
168
|
+
minex, ret = exp, [smith, armor] if exp < minex
|
169
|
+
rescue Mgmg::SearchCutException
|
170
|
+
end
|
171
|
+
else
|
172
|
+
(smith_min+1).upto(smith_max-1) do |smith|
|
173
|
+
break if minex < Mgmg.exp(smith, armor_min, comp)
|
174
|
+
armor = armor_search(para, target, smith, comp, armor_min, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
|
175
|
+
exp = Mgmg.exp(smith, armor, comp)
|
176
|
+
minex, ret = exp, [smith, armor] if exp < minex
|
177
|
+
rescue Mgmg::SearchCutException
|
178
|
+
end
|
179
|
+
end
|
180
|
+
raise Mgmg::SearchCutException if cut_exp < minex
|
181
|
+
ret
|
182
|
+
end
|
183
|
+
def comp_search(para, target, smith, armor, comp_min=nil, comp_max=10000, left_associative: true)
|
184
|
+
comp_min = min_comp(left_associative: left_associative)
|
185
|
+
if comp_max < comp_min
|
186
|
+
raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
|
187
|
+
end
|
188
|
+
if target <= build(smith, armor, comp_min, left_associative: left_associative).para_call(para)
|
189
|
+
return comp_min
|
190
|
+
elsif build(smith, comp_max, left_associative: left_associative).para_call(para) < target
|
191
|
+
raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
|
192
|
+
end
|
193
|
+
while 1 < comp_max - comp_min do
|
194
|
+
comp = (comp_max - comp_min).div(2) + comp_min
|
195
|
+
if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
|
196
|
+
comp_min = comp
|
197
|
+
else
|
198
|
+
comp_max = comp
|
199
|
+
end
|
200
|
+
end
|
201
|
+
comp_max
|
202
|
+
end
|
203
|
+
def 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)
|
204
|
+
if min_smith
|
205
|
+
s, a = self.min_smith
|
206
|
+
else
|
207
|
+
s, a = build(-1, -1, -1, left_associative: left_associative).min_level
|
208
|
+
end
|
209
|
+
smith_min = s if smith_min.nil?
|
210
|
+
armor_min = a if armor_min.nil?
|
211
|
+
comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
|
212
|
+
comp_min = comp_search(para, target, smith_max, armor_max, comp_min, comp_max, left_associative: left_associative)
|
213
|
+
smith_max, armor_max = sa_search(para, target, comp_min, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative)
|
214
|
+
smith_min, armor_min = sa_search(para, target, comp_max, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative)
|
215
|
+
raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp_min)
|
216
|
+
comp_max = comp_search(para, target, smith_min, armor_min, comp_min, comp_max, left_associative: left_associative)
|
217
|
+
minex, ret = Mgmg.exp(smith_min, armor_min, comp_max), [smith_min, armor_min, comp_max]
|
218
|
+
exp = Mgmg.exp(smith_max, armor_max, comp_min)
|
219
|
+
minex, ret = exp, [smith_max, armor_max, comp_min] if exp < minex
|
220
|
+
(comp_min+1).upto(comp_max-1) do |comp|
|
221
|
+
break if minex < Mgmg.exp(smith_min, armor_min, comp)
|
222
|
+
smith, armor = sa_search(para, target, comp, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
|
223
|
+
exp = Mgmg.exp(smith, armor, comp)
|
224
|
+
minex, ret = exp, [smith, armor, comp] if exp < minex
|
225
|
+
rescue Mgmg::SearchCutException
|
226
|
+
end
|
227
|
+
raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
|
228
|
+
ret
|
229
|
+
end
|
230
|
+
end
|
data/lib/mgmg/utils.rb
CHANGED
@@ -46,9 +46,44 @@ module Mgmg
|
|
46
46
|
end
|
47
47
|
attr_accessor :equip
|
48
48
|
end
|
49
|
+
class SearchCutException < StandardError; end
|
49
50
|
|
50
|
-
module_function def exp(smith, comp)
|
51
|
-
|
51
|
+
module_function def exp(smith, armor, comp=armor.tap{armor=0})
|
52
|
+
if armor <= 0
|
53
|
+
if smith <= 0
|
54
|
+
if comp <= 0
|
55
|
+
0
|
56
|
+
else
|
57
|
+
(2*((comp-1)**2)) + 2
|
58
|
+
end
|
59
|
+
else
|
60
|
+
if comp <= 0
|
61
|
+
((smith-1)**2) + 1
|
62
|
+
else
|
63
|
+
((smith-1)**2) + (2*((comp-1)**2)) + 3
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
if smith <= 0
|
68
|
+
if comp <= 0
|
69
|
+
((armor-1)**2) + 1
|
70
|
+
else
|
71
|
+
((armor-1)**2) + (2*((comp-1)**2)) + 3
|
72
|
+
end
|
73
|
+
else
|
74
|
+
if comp <= 0
|
75
|
+
((smith-1)**2) + ((armor-1)**2) + 2
|
76
|
+
else
|
77
|
+
((smith-1)**2) + ((armor-1)**2) + (2*((comp-1)**2)) + 4
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
module_function def invexp2(exp, comp)
|
83
|
+
Math.sqrt(exp - (2*((comp-1)**2)) - 3).round + 1
|
84
|
+
end
|
85
|
+
module_function def invexp3(exp, sa, comp)
|
86
|
+
Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).round + 1
|
52
87
|
end
|
53
88
|
|
54
89
|
CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/
|
data/lib/mgmg/version.rb
CHANGED
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.3.
|
4
|
+
version: 1.3.1
|
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-
|
11
|
+
date: 2020-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,7 @@ files:
|
|
71
71
|
- lib/mgmg/const.rb
|
72
72
|
- lib/mgmg/equip.rb
|
73
73
|
- lib/mgmg/poly.rb
|
74
|
+
- lib/mgmg/search.rb
|
74
75
|
- lib/mgmg/system_equip.rb
|
75
76
|
- lib/mgmg/utils.rb
|
76
77
|
- lib/mgmg/version.rb
|