mgmg 1.3.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ae250ef7035838c1f0598c419e66259c1cde7ab692e5b5ffefcd78ab845207d
4
- data.tar.gz: 0fd5f62e8c3ac85ba990010bca631e08111b50d69fad11d782fcadfe075781fd
3
+ metadata.gz: d35a19c90c58e70a8410540581af727523ea22584580bbf5ccf3b50fd19cbe4c
4
+ data.tar.gz: ca9c6122b4d7d84389787a10ac7073e5f3f633d1c1fffab58be1ad693e3613d4
5
5
  SHA512:
6
- metadata.gz: 40bdd74efb69a024d87d265340caefd48ee90f4d3fd9d74d2a7a46fd78c6a553bc931798636b1ebc8bed8e95cfa8c6501a554c073897ac0ae9be3fdd37298466
7
- data.tar.gz: 9c32dfaf9a0d1027afd33e70562e813f7cce5a0378e0e81f806e77e3d4415ee4d779a09b7d3b122d523d9a0f8cc10af1a97da0ee3e3464440777b82efee35c48
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
- - 丸めを無視した多項式近似(変数は製作レベル)を表す `Mgmg::TPolynomial`およびこれを生成するメソッド String#poly を追加.
33
+ - 丸めを無視した多項式近似(変数は製作レベル)を表す`Mgmg::TPolynomial`およびこれを生成するメソッド`String#poly`を追加.
34
34
 
35
35
  ## 1.0.10 2019/06/29
36
36
  - 消費エレメント量を返す`Mgmg::Equip#total_cost`を追加.
@@ -93,3 +93,9 @@
93
93
  - `Mgmg.#exp`に3引数を与えられるように修正.
94
94
  - `String#search`,`Enumerable#search`を追加.
95
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
@@ -174,6 +174,15 @@ puts '小竜咆哮'.build
174
174
  ### `String#peff(para, smith, comp=smith, left_associative: true)`
175
175
  近似多項式における偏微分値を使用した場合の,`String#eff`と同様の値を返します.`self.poly(para, left_associative: left_associative).eff(smith, comp)`と等価です.
176
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
+
177
186
  ### `Mgmg::Equip`
178
187
  前述の`String#build`によって生成される装備品のクラスです.複数装備の合計値を表す「複数装備」という種別の装備品の場合もあります.以下のようなインスタンスメソッドが定義されています.
179
188
 
data/lib/mgmg.rb CHANGED
@@ -5,6 +5,7 @@ require_relative './mgmg/equip'
5
5
  require_relative './mgmg/poly'
6
6
  require_relative './mgmg/system_equip'
7
7
  require_relative './mgmg/search'
8
+ require_relative './mgmg/optimize'
8
9
 
9
10
  class String
10
11
  def min_level(w=1)
@@ -70,6 +71,12 @@ class String
70
71
  puts "with levels (#{smith}, #{comp}) yields (#{pstr}, #{built.total_cost})"
71
72
  puts " #{built}"
72
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
73
80
  end
74
81
  module Enumerable
75
82
  def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, left_associative: true)
@@ -0,0 +1,213 @@
1
+ module Mgmg
2
+ module Optimize; end
3
+ class << Optimize
4
+ InvList = [%w|帽子 フード サンダル|.freeze, %w|宝1 骨1 木1 木2 骨2|.freeze, %w|宝1 骨1 木1|.freeze].freeze
5
+ def phydef_optimize(str, smith, comp=smith, left_associative: true, magdef_maximize: true)
6
+ best = ( smith.nil? ? [str, str.poly(:phydef), str.poly(:magdef), str.poly(:cost)] : [str, str.build(smith, comp)] )
7
+ str = Mgmg.check_string(str)
8
+ ai = 0
9
+ while str.sub!(/(帽子|フード|サンダル)\([宝木骨][12][宝木骨]1\)/){
10
+ ai += 1
11
+ "<A#{ai}>"
12
+ }; end
13
+ bi = 0
14
+ while str.sub!(/[宝木骨]1\)/){
15
+ bi += 1
16
+ "<B#{bi}>)"
17
+ }; end
18
+ skin = false
19
+ m = /([^\+]*\([^\(]+[綿皮]1\))\]*\Z/.match(str)
20
+ if m
21
+ if smith
22
+ if m[1].sub(/綿1\)/, '皮1)').build(smith).weight == m[1].sub(/皮1\)/, '綿1)').build(smith).weight
23
+ skin = true
24
+ end
25
+ else
26
+ skin = true
27
+ end
28
+ str = str.sub(/皮(1\)\]*)\Z/) do
29
+ "綿#{$1}"
30
+ end
31
+ end
32
+ a = Array.new(ai){ [0, 0, 0] }
33
+ b0 = Array.new(bi){ 0 }
34
+ while a
35
+ b = b0
36
+ while b
37
+ r = pd_apply_idx(str, a, b)
38
+ best = pd_better(best, ( smith.nil? ? [r, r.poly(:phydef), r.poly(:magdef), r.poly(:cost)] : [r, r.build(smith, comp)] ), magdef_maximize)
39
+ b = pd_next_b(b)
40
+ end
41
+ a = pd_next_a(a)
42
+ end
43
+ if skin
44
+ str = str.sub(/綿(1\)\]*)\Z/) do
45
+ "皮#{$1}"
46
+ end
47
+ a = Array.new(ai){ [0, 0, 0] }
48
+ while a
49
+ b = b0
50
+ while b
51
+ r = pd_apply_idx(str, a, b)
52
+ best = pd_better(best, ( smith.nil? ? [r, r.poly(:phydef), r.poly(:magdef), r.poly(:cost)] : [r, r.build(smith, comp)] ), magdef_maximize)
53
+ b = pd_next_b(b)
54
+ end
55
+ a = pd_next_a(a)
56
+ end
57
+ end
58
+ best[0]
59
+ end
60
+ private def pd_better(pre, cur, mag)
61
+ case pre.size
62
+ when 2
63
+ if pre[1].phydef < cur[1].phydef
64
+ return cur
65
+ elsif pre[1].phydef == cur[1].phydef
66
+ if mag
67
+ if pre[1].magdef < cur[1].magdef
68
+ return cur
69
+ elsif pre[1].magdef == cur[1].magdef
70
+ if cur[1].total_cost.sum < pre[1].total_cost.sum
71
+ return cur
72
+ end
73
+ end
74
+ else
75
+ if cur[1].comp_cost < pre[1].comp_cost
76
+ return cur
77
+ elsif cur[1].comp_cost == pre[1].comp_cost
78
+ if cur[1].total_cost.sum < pre[1].total_cost.sum
79
+ return cur
80
+ end
81
+ end
82
+ end
83
+ end
84
+ return pre
85
+ when 4
86
+ if pre[1] < cur[1]
87
+ return cur
88
+ elsif pre[1] == cur[1]
89
+ if mag
90
+ if pre[2] < cur[2]
91
+ return cur
92
+ elsif pre[2] == cur[2]
93
+ if cur[3] < pre[3]
94
+ return cur
95
+ end
96
+ end
97
+ else
98
+ if cur[3] < pre[3]
99
+ return cur
100
+ end
101
+ end
102
+ end
103
+ return pre
104
+ else
105
+ raise "Unexpected Error"
106
+ end
107
+ end
108
+ private def pd_apply_idx(str, a, b)
109
+ a.each.with_index do |aa, i|
110
+ str = str.sub("<A#{i+1}>", "#{InvList[0][aa[0]]}(#{InvList[1][aa[1]]}#{InvList[2][aa[2]]})")
111
+ end
112
+ b.each.with_index do |bb, i|
113
+ str = str.sub("<B#{i+1}>", InvList[2][bb])
114
+ end
115
+ str
116
+ end
117
+ private def pd_next_b_full(b)
118
+ 0.upto(b.length-1) do |i|
119
+ b[i] += 1
120
+ if b[i] == InvList[2].size
121
+ b[i] = 0
122
+ else
123
+ return b
124
+ end
125
+ end
126
+ nil
127
+ end
128
+ private def pd_next_b(b)
129
+ if b[0] == 0
130
+ return Array.new(b.length, 1)
131
+ end
132
+ nil
133
+ end
134
+ private def pd_next_a(a)
135
+ 0.upto(a.length-1) do |i|
136
+ 0.upto(2) do |j|
137
+ a[i][j] += 1
138
+ if a[i][j] == InvList[j].size
139
+ a[i][j] = 0
140
+ else
141
+ return a
142
+ end
143
+ end
144
+ end
145
+ nil
146
+ end
147
+
148
+ MwList = %w|綿 皮 骨 木 水|.freeze
149
+ def buster_optimize(str, smith, comp=smith, left_associative: true)
150
+ best = ( smith.nil? ? [str, str.poly(:mag_das)] : [str, str.build(smith, comp)] )
151
+ str = Mgmg.check_string(str)
152
+ ai = -1
153
+ org = nil
154
+ while str.sub!(/弓\(([骨水綿皮木][12][骨水綿皮木]1)\)/){
155
+ ai += 1
156
+ if ai == 0
157
+ org = $1.dup
158
+ end
159
+ "弓(<A#{ai}>)"
160
+ }; end
161
+ str = str.sub(/<A0>/, org)
162
+ a = Array.new(ai){ [0, 0, 0] }
163
+ while a
164
+ r = bus_apply_idx(str, a)
165
+ best = bus_better(best, ( smith.nil? ? [r, r.poly(:mag_das)] : [r, r.build(smith, comp)] ))
166
+ a = bus_next_a(a)
167
+ end
168
+ best[0]
169
+ end
170
+ private def bus_apply_idx(str, a)
171
+ a.each.with_index do |aa, i|
172
+ str = str.sub("<A#{i+1}>", "#{MwList[aa[0]]}#{aa[1]+1}#{MwList[aa[2]]}1")
173
+ end
174
+ str
175
+ end
176
+ private def bus_better(pre, cur)
177
+ if pre[1].kind_of?(Mgmg::Equip)
178
+ if pre[1].mag_das < cur[1].mag_das
179
+ return cur
180
+ elsif pre[1].mag_das == cur[1].mag_das
181
+ if cur[1].total_cost.sum < pre[1].total_cost.sum
182
+ return cur
183
+ end
184
+ end
185
+ return pre
186
+ else
187
+ if pre[1] < cur[1]
188
+ return cur
189
+ end
190
+ return pre
191
+ end
192
+ end
193
+ private def bus_next_a(a)
194
+ 0.upto(a.length-1) do |i|
195
+ [0, 2].each do |j|
196
+ a[i][j] += 1
197
+ if a[i][j] == 5
198
+ a[i][j] = 0
199
+ else
200
+ return a
201
+ end
202
+ end
203
+ a[i][1] += 1
204
+ if a[i][1] == 2
205
+ a[i][1] = 0
206
+ else
207
+ return a
208
+ end
209
+ end
210
+ nil
211
+ end
212
+ end
213
+ end
data/lib/mgmg/poly.rb CHANGED
@@ -139,10 +139,12 @@ module Mgmg
139
139
  ret
140
140
  end
141
141
  def +(other)
142
+ other = self.coerce(other)[0] unless other.kind_of?(self.class)
142
143
  mat = @mat.padd(other.mat)
143
144
  self.class.new(mat, 28, 0, 12, 12)
144
145
  end
145
146
  def -(other)
147
+ other = self.coerce(other)[0] unless other.kind_of?(self.class)
146
148
  mat = @mat.padd(other.mat.scalar(-1))
147
149
  self.class.new(mat, 28, 0, 12, 12)
148
150
  end
@@ -204,6 +206,76 @@ module Mgmg
204
206
  end
205
207
  ret.nil? ? 0 : ret
206
208
  end
209
+
210
+ def coerce(other)
211
+ [self.class.new(Mat.new(1, 1, other), 28, 0, 12, 12), self]
212
+ end
213
+ def <(other)
214
+ foo = self-other
215
+ (foo.mat.row_size-1).downto(0) do |s|
216
+ (foo.mat.col_size-1).downto(0) do |c|
217
+ bar = foo.mat.body[s][c]
218
+ if bar < 0
219
+ return true
220
+ elsif 0 < bar
221
+ return false
222
+ end
223
+ end
224
+ end
225
+ false
226
+ end
227
+ def <=(other)
228
+ foo = self-other
229
+ (foo.mat.row_size-1).downto(0) do |s|
230
+ (foo.mat.col_size-1).downto(0) do |c|
231
+ bar = foo.mat.body[s][c]
232
+ if bar < 0
233
+ return true
234
+ elsif 0 < bar
235
+ return false
236
+ end
237
+ end
238
+ end
239
+ true
240
+ end
241
+ def >(other)
242
+ foo = other-self
243
+ (foo.mat.row_size-1).downto(0) do |s|
244
+ (foo.mat.col_size-1).downto(0) do |c|
245
+ bar = foo.mat.body[s][c]
246
+ if bar < 0
247
+ return true
248
+ elsif 0 < bar
249
+ return false
250
+ end
251
+ end
252
+ end
253
+ false
254
+ end
255
+ def >=(other)
256
+ foo = other-self
257
+ (foo.mat.row_size-1).downto(0) do |s|
258
+ (foo.mat.col_size-1).downto(0) do |c|
259
+ bar = foo.mat.body[s][c]
260
+ if bar < 0
261
+ return true
262
+ elsif 0 < bar
263
+ return false
264
+ end
265
+ end
266
+ end
267
+ true
268
+ end
269
+ def ==(other)
270
+ foo = self-other
271
+ (foo.mat.row_size-1).downto(0) do |s|
272
+ (foo.mat.col_size-1).downto(0) do |c|
273
+ bar = foo.mat.body[s][c]
274
+ return false if bar != 0
275
+ end
276
+ end
277
+ true
278
+ end
207
279
  end
208
280
  class << TPolynomial
209
281
  ParamIndex = Hash.new
data/lib/mgmg/search.rb CHANGED
@@ -72,7 +72,13 @@ class String
72
72
  break if minex < Mgmg.exp(smith_min, comp)
73
73
  smith = smith_search(para, target, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
74
74
  exp = Mgmg.exp(smith, comp)
75
- minex, ret = exp, [smith, comp] if exp < minex
75
+ if exp < minex
76
+ minex, ret = exp, [smith, comp]
77
+ elsif exp == minex
78
+ if build(*ret).para_call(para) < build(smith, comp).para_call(para)
79
+ ret = [smith, comp]
80
+ end
81
+ end
76
82
  rescue Mgmg::SearchCutException
77
83
  end
78
84
  raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
@@ -165,7 +171,13 @@ module Enumerable
165
171
  break if minex < Mgmg.exp(smith_min, armor, comp)
166
172
  smith = smith_search(para, target, armor, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
167
173
  exp = Mgmg.exp(smith, armor, comp)
168
- minex, ret = exp, [smith, armor] if exp < minex
174
+ if exp < minex
175
+ minex, ret = exp, [smith, armor]
176
+ elsif exp == minex
177
+ if build(*ret, comp).para_call(para) < build(smith, armor, comp).para_call(para)
178
+ ret = [smith, armor]
179
+ end
180
+ end
169
181
  rescue Mgmg::SearchCutException
170
182
  end
171
183
  else
@@ -173,7 +185,13 @@ module Enumerable
173
185
  break if minex < Mgmg.exp(smith, armor_min, comp)
174
186
  armor = armor_search(para, target, smith, comp, armor_min, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
175
187
  exp = Mgmg.exp(smith, armor, comp)
176
- minex, ret = exp, [smith, armor] if exp < minex
188
+ if exp < minex
189
+ minex, ret = exp, [smith, armor]
190
+ elsif exp == minex
191
+ if build(*ret, comp).para_call(para) < build(smith, armor, comp).para_call(para)
192
+ ret = [smith, armor]
193
+ end
194
+ end
177
195
  rescue Mgmg::SearchCutException
178
196
  end
179
197
  end
@@ -187,7 +205,7 @@ module Enumerable
187
205
  end
188
206
  if target <= build(smith, armor, comp_min, left_associative: left_associative).para_call(para)
189
207
  return comp_min
190
- elsif build(smith, comp_max, left_associative: left_associative).para_call(para) < target
208
+ elsif build(smith, armor, comp_max, left_associative: left_associative).para_call(para) < target
191
209
  raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
192
210
  end
193
211
  while 1 < comp_max - comp_min do
@@ -221,7 +239,13 @@ module Enumerable
221
239
  break if minex < Mgmg.exp(smith_min, armor_min, comp)
222
240
  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
241
  exp = Mgmg.exp(smith, armor, comp)
224
- minex, ret = exp, [smith, armor, comp] if exp < minex
242
+ if exp < minex
243
+ minex, ret = exp, [smith, armor, comp]
244
+ elsif exp == minex
245
+ if build(*ret).para_call(para) < build(smith, armor, comp).para_call(para)
246
+ ret = [smith, armor, comp]
247
+ end
248
+ end
225
249
  rescue Mgmg::SearchCutException
226
250
  end
227
251
  raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
data/lib/mgmg/utils.rb CHANGED
@@ -221,6 +221,9 @@ module Mgmg
221
221
  def col_size
222
222
  @body[0].length
223
223
  end
224
+ def shape
225
+ [row_size(), col_size()]
226
+ end
224
227
  def each_with_index
225
228
  @body.each.with_index do |row, i|
226
229
  row.each.with_index do |e, j|
data/lib/mgmg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mgmg
2
- VERSION = "1.3.1"
2
+ VERSION = "1.3.2"
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.3.1
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - KAZOON
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-31 00:00:00.000000000 Z
11
+ date: 2021-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.2.3
55
- description:
55
+ description:
56
56
  email:
57
57
  - cycloawaodorin+gem@gmail.com
58
58
  executables: []
@@ -70,6 +70,7 @@ files:
70
70
  - lib/mgmg.rb
71
71
  - lib/mgmg/const.rb
72
72
  - lib/mgmg/equip.rb
73
+ - lib/mgmg/optimize.rb
73
74
  - lib/mgmg/poly.rb
74
75
  - lib/mgmg/search.rb
75
76
  - lib/mgmg/system_equip.rb
@@ -82,7 +83,7 @@ metadata:
82
83
  homepage_uri: https://github.com/cycloawaodorin/
83
84
  source_code_uri: https://github.com/cycloawaodorin/mgmg
84
85
  changelog_uri: https://github.com/cycloawaodorin/mgmg/blob/master/CHANGELOG.md
85
- post_install_message:
86
+ post_install_message:
86
87
  rdoc_options: []
87
88
  require_paths:
88
89
  - lib
@@ -97,8 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
98
  - !ruby/object:Gem::Version
98
99
  version: '0'
99
100
  requirements: []
100
- rubygems_version: 3.1.4
101
- signing_key:
101
+ rubygems_version: 3.2.17
102
+ signing_key:
102
103
  specification_version: 4
103
104
  summary: Calculate specs of equipments of Megurimeguru, a game produced by Kou.
104
105
  test_files: []