mgmg 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32ba0853f1b7578105ed06d7ebe4286544ae2a3188a2ab58c9d577b0e61bdd09
4
- data.tar.gz: de86373a23cd69a9cbed9a9f28ce2fe0e10ef3dee1b7803a2eaeac154fda0cec
3
+ metadata.gz: '0939daf2680e3d9a8a80a9616355ed10232ce6794b288ea86d295d283cfde413'
4
+ data.tar.gz: 7c6f9fdf112335d9844f1ec9e06c694b9cffd0a897787b4c9e74b306296b179c
5
5
  SHA512:
6
- metadata.gz: 123076c3d2728af73cf53b1dbc9834d0eea262fcab89a454618b2e63798156c98d127a54dbb40e696af122064ad435a7794af165dc96a4ca883cf1a2c8256814
7
- data.tar.gz: 79fe5ebb67a840611930042b9f75c21839d79d1b3164f59b88a88db66a4fdba719dda819414ecaa1fcf379507426f6776b99058f2329662b2838d001a94f0320
6
+ metadata.gz: 31c5e140183a5417c833b7af756b454701333d71293bad1e5cd3f15073d71657c0503038daf0f7c7c02290aee22cef38c795ff98fc92df85462da96759c816f9
7
+ data.tar.gz: d02cfe4e1f571b76083c644cd0c44d41caced733e22d4c24853ac91b2a3410f53500c7867bda2b2109d46a873d4110a801d1cf2ecb7f2a3a54ba48f1d31d8b51
data/CHANGELOG.md CHANGED
@@ -120,3 +120,14 @@
120
120
  - `Mgmg::Equip#reinforce`および`Mgmg::IR`を使うメソッド群に`reinforcement`キーワード引数を追加.
121
121
  - スキルおよび料理による強化効果をシミュレートできるようになった.
122
122
  - 料理については,プリセット料理名または`Mgmg.#cuisine`で生成される`Mgmg::Cuisine`オブジェクトを使う.
123
+
124
+ ## 1.5.0 2022/06/22
125
+ - `Mgmg::Option`を実装し,search系メソッドを中心としたキーワード引数を,このクラスに集約してから受け渡すようにした.
126
+ - オプションオブジェクトは`Mgmg.#option`によって生成し,キーワード引数`opt`に渡す.従来のキーワード引数は廃止された.
127
+ - この変更で,一部の受け渡し忘れのバグが修正され,パフォーマンスが改善した.
128
+ - `Enumerable#search`で無駄な処理が発生していて,処理時間がかかっていたバグを修正.
129
+ - `String#min_level`,`Enumerable#min_level`の仕様を変更し,合成後の重量を目標値にするのに必要な鍛冶・道具製作Lvを計算するようにした.
130
+ - この変更に伴い,`Mgmg::Equip#min_level`を,`Mgmg::Equip#min_levels_max`に名称変更し,`String#min_levels_max`,`Enumerable#min_levels_max`を追加した.
131
+ - 関連して,`String#max_weight`,`String#min_weight`,`Enumerable#max_weight`,`Enumerable#min_weight`,`Enumerable#max_weights`,`Enumerable#min_weights`を追加した.
132
+ - `Mgmg::Option#smith_min`,`Mgmg::Option#armor_min`のデフォルト値を,`String#min_level`,`Enumerable#min_level`を用いて設定する仕様とし,その目標重量を`Mgmg::Option#target_weight`で指定するようにした.
133
+ - `String#min_comp`,`String#min_smith`,`Enumerable#min_comp`,`Enumerable#min_smith`において,既製品のみである,合成を行わないなど,該当スキルが必要ないレシピである場合の返り値を`-1`に変更した.
data/README.md CHANGED
@@ -53,19 +53,21 @@ puts r.build(122, 139, 232)
53
53
  #=> 複数装備9(武:1, 頭:1, 飾:2)[攻撃:15, 物防:34, 魔防:28, HP:241, MP:71, 器用:223, 素早:222, 魔力:6,604]
54
54
  ```
55
55
 
56
- 重量1または2で作るのに必要な防具製作Lvを確認する.
57
-
56
+ 製作品の重量及び特定の重量にするために必要な鍛冶・防具製作Lvを確認する.
58
57
  ```ruby
59
- p ['重鎧(皮1010)'.min_level, '重鎧(皮10金10)'.min_level(2)]
60
- #=> [162, 42]
61
- ```
62
-
63
- 合成レシピから必要製作Lvを確認する.
64
- ```ruby
65
- p '[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.min_levels
66
- #=> {"杖(水玉10火玉5)"=>92, "本(骨10鉄1)"=>48, "本(水玉5綿2)"=>12, "杖(骨10鉄1)"=>28}
67
- p '[杖(水玉10火玉5)+本(骨10鉄1)]+[本(水玉5綿2)+杖(骨10鉄1)]'.build.min_level
68
- #=> 92
58
+ r = 'サンダル(骨2皮1)+[重鎧(金3金3)+[フード(骨2宝1)+[重鎧(皮10金10)+軽鎧(鉄10皮1)]]]'
59
+ p r.min_levels # 各材料装備を重量1で作るのに必要な防具製作Lv
60
+ #=> {"サンダル(骨2皮1)"=>3, "重鎧(金3金3)"=>202, "フード(骨2宝1)"=>3, "重鎧(皮10金10)"=>162, "軽鎧(鉄10皮1)"=>68}
61
+ p r.min_levels(2) # 同重量2以下
62
+ #=> {"サンダル(骨2皮1)"=>3, "重鎧(金3金3)"=>102, "フード(骨2宝1)"=>3, "重鎧(皮10金10)"=>42, "軽鎧(鉄10皮1)"=>27}
63
+ p [r.min_weight, r.max_weight] # 最小重量と最大重量
64
+ #=> [5, 11]
65
+ p r.min_level # 最小重量で作るのに必要な防具製作Lv
66
+ #=> 202
67
+ p r.min_level(7) # 重量7以下で作るのに必要な防具製作Lv
68
+ #=> 102
69
+ p r.min_level(-1) # 最小重量+1=重量6以下で作るのに必要な防具製作Lv
70
+ #=> 162
69
71
  ```
70
72
 
71
73
  近似多項式を得る.
@@ -91,11 +93,21 @@ p [sc, Mgmg.exp(*sc)]
91
93
  #=> [[155, 376], 304969]
92
94
  ```
93
95
 
96
+ 最小重量で製作できない鍛冶レベルを探索範囲に含める.
97
+
98
+ ```ruby
99
+ r = '双短剣(金3皮1)+[杖(水1綿1)+[斧(玉5水1)+[杖(鉄1綿1)+[[斧(木2金3)+剣(鉄10皮1)]+[剣(木2綿1)+双短剣(鉄10皮1)]]]]]'
100
+ sc = r.search(:atk_sd, 2000, opt: Mgmg.option(target_weight: 9))
101
+ p [sc, Mgmg.exp(*sc)]
102
+ #=> [[70, 130], 38046]
103
+ # オプションなしの場合は鍛冶Lv100以上を探索するため,[[100, 126], 41054] になる
104
+ ```
105
+
94
106
  探索の際,スキル及び料理を考慮する.
95
107
 
96
108
  ```ruby
97
109
  r = '重鎧(皮2綿1)+[帽子(宝1宝1)+[重鎧(玉5金3)+[帽子(宝1宝1)+[重鎧(玉5金6)+[軽鎧(金3骨1)+[重鎧(皮2骨1)+軽鎧(鉄10綿1)]]]]]]'
98
- sc = r.search(:phydef, 100_000, reinforcement: %w|物防御UP アースドランと氷河酒の蒸し焼き ガードアップ|)
110
+ sc = r.search(:phydef, 100_000, opt: Mgmg.option(buff: %w|物防御UP アースドランと氷河酒の蒸し焼き ガードアップ|))
99
111
  p [sc, Mgmg.exp(*sc)]
100
112
  #=> [[120, 264], 152502]
101
113
  ```
data/lib/mgmg/equip.rb CHANGED
@@ -57,15 +57,15 @@ module Mgmg
57
57
  @min_levels
58
58
  else
59
59
  @min_levels.map do |key, value|
60
- [key, key.min_level(w)]
60
+ [key, Equip.min_level(key, w)]
61
61
  end.to_h
62
62
  end
63
63
  end
64
- def min_level(w=1)
64
+ def min_levels_max(w=1)
65
65
  if @kind == 28
66
- ret = [0, 0]
66
+ ret = [-1, -1]
67
67
  min_levels(w).each do |str, ml|
68
- if str.build(-1).kind < 8
68
+ if str.build.kind < 8
69
69
  if ret[0] < ml
70
70
  ret[0] = ml
71
71
  end
@@ -77,7 +77,7 @@ module Mgmg
77
77
  end
78
78
  ret
79
79
  else
80
- min_levels(w).values.append(0).max
80
+ min_levels(w).values.append(-1).max
81
81
  end
82
82
  end
83
83
 
@@ -193,15 +193,9 @@ module Mgmg
193
193
  def +(other)
194
194
  self.dup.add!(other)
195
195
  end
196
- def coerce(other)
197
- if other == 0
198
- zero = self.class.new(28, 0, Vec.new(6, 0), 12, 12, Vec.new(9, 0), Vec.new(3, 0))
199
- zero.history.clear
200
- [zero, self]
201
- else
202
- raise TypeError, "Mgmg::Equip can't be coerced into other than 0"
203
- end
204
- 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
198
+ Zero.freeze
205
199
  end
206
200
 
207
201
  class << Equip
@@ -212,7 +206,7 @@ module Mgmg
212
206
  end
213
207
  private def build_sub0(stack, str)
214
208
  SystemEquip.each do |k, v|
215
- if Regexp.compile(k).match(str)
209
+ if SystemEquipRegexp[k].match(str)
216
210
  stack << v
217
211
  str = str.gsub(k, "<#{stack.length-1}>")
218
212
  end
@@ -305,7 +299,7 @@ module Mgmg
305
299
 
306
300
  ret = new(kind, ( weight<1 ? 1 : weight ), (main_s+sub_s).div(2), main_mc, sub_mc, para, ele)
307
301
  ret.total_cost[kind < 8 ? 0 : 2] += ret.smith_cost(outsourcing)
308
- ret.min_levels.store(str, str.min_level)
302
+ ret.min_levels.store(str, Equip.min_level(str))
309
303
  ret
310
304
  end
311
305
 
@@ -323,14 +317,14 @@ module Mgmg
323
317
  [(main_s-1)*3, (sub_s-1)*3, l].max
324
318
  end
325
319
 
326
- def min_comp(str, left_associative: true)
320
+ def min_comp(str, opt: Option.new)
327
321
  str = Mgmg.check_string(str)
328
322
  stack, str = minc_sub0([], str)
329
- (minc_sub(stack, str, left_associative)[1]-1)*3
323
+ (minc_sub(stack, str, opt.left_associative)[1]-1)*3
330
324
  end
331
325
  private def minc_sub0(stack, str)
332
326
  SystemEquip.each do |k, v|
333
- if Regexp.compile(k).match(str)
327
+ if SystemEquipRegexp[k].match(str)
334
328
  stack << v.star
335
329
  str = str.gsub(k, "<#{stack.length-1}>")
336
330
  end
@@ -352,14 +346,15 @@ module Mgmg
352
346
  end
353
347
  end
354
348
 
355
- def min_smith(str, left_associative: true)
349
+ def min_smith(str, opt: Option.new)
356
350
  str = Mgmg.check_string(str)
357
351
  stack, str = mins_sub0([], str)
358
- (([mins_sub(stack, str, left_associative)]+stack).max-1)*3
352
+ ret = (([mins_sub(stack, str, opt.left_associative)]+stack).max-1)*3
353
+ ret < 0 ? -1 : ret
359
354
  end
360
355
  private def mins_sub0(stack, str)
361
356
  SystemEquip.each do |k, v|
362
- if Regexp.compile(k).match(str)
357
+ if SystemEquipRegexp[k].match(str)
363
358
  stack << 0
364
359
  str = str.gsub(k, "<#{stack.length-1}>")
365
360
  end
@@ -373,7 +368,7 @@ module Mgmg
373
368
  elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
374
369
  [mins_sub(stack, m[1], lassoc), mins_sub(stack, m[2], lassoc)].max
375
370
  elsif m = /\A\<(\d+)\>\Z/.match(str)
376
- 1
371
+ 0
377
372
  else
378
373
  mins_sub2(str)
379
374
  end
data/lib/mgmg/ir.rb CHANGED
@@ -31,7 +31,7 @@ module Mgmg
31
31
  ((s+@sub9)*@coef).div(@den)
32
32
  end
33
33
  def evaluate3(s, a, c)
34
- if sa==:a
34
+ if @sa==:a
35
35
  ((a+@sub9)*@coef).div(@den)
36
36
  else
37
37
  ((s+@sub9)*@coef).div(@den)
@@ -313,14 +313,7 @@ module Mgmg
313
313
  def +(other)
314
314
  self.dup.add!(other)
315
315
  end
316
- def coerce(other)
317
- if other == 0
318
- zero = self.class.new(28, Vec.new(6, 0), 12, 12, Array.new(9){Const.new(0)})
319
- [zero, self]
320
- else
321
- raise TypeError, "Mgmg::IR can't be coerced into other than 0"
322
- end
323
- end
316
+ Zero = self.new(28, Vec.new(6, 0), 12, 12, Array.new(9){Const.new(0)})
324
317
  end
325
318
  class << IR
326
319
  def build(str, left_associative: true, reinforcement: [])
@@ -330,7 +323,7 @@ module Mgmg
330
323
  end
331
324
  private def build_sub0(stack, str)
332
325
  SystemEquip.each do |k, v|
333
- if Regexp.compile(k).match(str)
326
+ if SystemEquipRegexp[k].match(str)
334
327
  stack << from_equip(v)
335
328
  str = str.gsub(k, "<#{stack.length-1}>")
336
329
  end
data/lib/mgmg/optimize.rb CHANGED
@@ -2,8 +2,12 @@ module Mgmg
2
2
  module Optimize; end
3
3
  class << Optimize
4
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)] )
5
+ def phydef_optimize(str, smith, comp=smith, opt: Option.new)
6
+ best = if smith.nil? then
7
+ [str, str.poly(:phydef, opt: opt), str.poly(:magdef, opt: opt), str.poly(:cost, opt: opt)]
8
+ else
9
+ [str, str.build(smith, comp, opt: opt)]
10
+ end
7
11
  str = Mgmg.check_string(str)
8
12
  ai = 0
9
13
  while str.sub!(/(帽子|フード|サンダル)\([宝木骨][12][宝木骨]1\)/){
@@ -19,7 +23,7 @@ module Mgmg
19
23
  m = /([^\+]*\([^\(]+[綿皮]1\))\]*\Z/.match(str)
20
24
  if m
21
25
  if smith
22
- if m[1].sub(/綿1\)/, '皮1)').build(smith).weight == m[1].sub(/皮1\)/, '綿1)').build(smith).weight
26
+ if m[1].sub(/綿1\)/, '皮1)').build(smith, opt: opt).weight == m[1].sub(/皮1\)/, '綿1)').build(smith, opt: opt).weight
23
27
  skin = true
24
28
  end
25
29
  else
@@ -35,7 +39,11 @@ module Mgmg
35
39
  b = b0
36
40
  while b
37
41
  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)
42
+ best = if smith.nil? then
43
+ pd_better(best, [r, r.poly(:phydef, opt: opt), r.poly(:magdef, opt: opt), r.poly(:cost, opt: opt)], opt.magdef_maximize)
44
+ else
45
+ pd_better(best, [r, r.build(smith, comp, opt: opt)], opt.magdef_maximize)
46
+ end
39
47
  b = pd_next_b(b)
40
48
  end
41
49
  a = pd_next_a(a)
@@ -49,7 +57,11 @@ module Mgmg
49
57
  b = b0
50
58
  while b
51
59
  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)
60
+ best = if smith.nil? then
61
+ pd_better(best, [r, r.poly(:phydef, opt: opt), r.poly(:magdef, opt: opt), r.poly(:cost, opt: opt)], opt.magdef_maximize)
62
+ else
63
+ pd_better(best, [r, r.build(smith, comp, opt: opt)], opt.magdef_maximize)
64
+ end
53
65
  b = pd_next_b(b)
54
66
  end
55
67
  a = pd_next_a(a)
@@ -102,7 +114,7 @@ module Mgmg
102
114
  end
103
115
  return pre
104
116
  else
105
- raise "Unexpected Error"
117
+ raise UnexpectedError
106
118
  end
107
119
  end
108
120
  private def pd_apply_idx(str, a, b)
@@ -146,8 +158,8 @@ module Mgmg
146
158
  end
147
159
 
148
160
  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)] )
161
+ def buster_optimize(str, smith, comp=smith, opt: Option.new)
162
+ best = ( smith.nil? ? [str, str.poly(:mag_das, opt: opt)] : [str, str.build(smith, comp, opt: opt)] )
151
163
  str = Mgmg.check_string(str)
152
164
  ai = -1
153
165
  org = nil
@@ -162,7 +174,7 @@ module Mgmg
162
174
  a = Array.new(ai){ [0, 0, 0] }
163
175
  while a
164
176
  r = bus_apply_idx(str, a)
165
- best = bus_better(best, ( smith.nil? ? [r, r.poly(:mag_das)] : [r, r.build(smith, comp)] ))
177
+ best = bus_better(best, ( smith.nil? ? [r, r.poly(:mag_das, opt: opt)] : [r, r.build(smith, comp, opt: opt)] ))
166
178
  a = bus_next_a(a)
167
179
  end
168
180
  best[0]
@@ -0,0 +1,85 @@
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
+ class Option
8
+ def initialize(
9
+ left_associative: true,
10
+ smith_min: nil, armor_min:nil, comp_min: nil, smith_max: 10000, armor_max: 10000, comp_max: 10000,
11
+ step: 1, magdef_maximize: true,
12
+ target_weight: 0, reinforcement: [], buff: nil,
13
+ irep: nil, cut_exp: Float::INFINITY
14
+ )
15
+ @left_associative = left_associative
16
+ @smith_min = smith_min
17
+ @armor_min = armor_min
18
+ @comp_min = comp_min
19
+ @smith_max = smith_max
20
+ @armor_max = armor_max
21
+ @comp_max = comp_max
22
+ @step = step
23
+ @magdef_maximize = magdef_maximize
24
+ @target_weight = target_weight
25
+ @reinforcement = reinforcement
26
+ unless buff.nil?
27
+ if @reinforcement.empty?
28
+ @reinforcement = buff
29
+ else
30
+ raise ArgumentError, "reinforcement and buff are exclusive"
31
+ end
32
+ end
33
+ @irep = irep
34
+ @cut_exp = cut_exp
35
+ end
36
+ attr_accessor :left_associative, :smith_min, :armor_min, :comp_min, :smith_max, :armor_max, :comp_max
37
+ attr_accessor :step, :magdef_maximize, :target_weight, :reinforcement, :irep, :cut_exp
38
+ def initialize_copy(other)
39
+ @left_associative = other.left_associative
40
+ @smith_min = other.smith_min
41
+ @armor_min = other.armor_min
42
+ @comp_min = other.comp_min
43
+ @smith_max = other.smith_max
44
+ @armor_max = other.armor_max
45
+ @comp_max = other.comp_max
46
+ @step = other.step
47
+ @magdef_maximize = other.magdef_maximize
48
+ @target_weight = other.target_weight
49
+ @reinforcement = other.reinforcement.dup
50
+ @irep = other.irep
51
+ @cut_exp = other.cut_exp
52
+ end
53
+ def set_default(recipe, force: false)
54
+ case recipe
55
+ when String
56
+ if @smith_min.nil? && @armor_min
57
+ @smith_min = @armor_min
58
+ end
59
+ if force || @smith_min.nil?
60
+ s = recipe.min_level(@target_weight, opt: self)
61
+ @smith_min = s if force || @smith_min.nil?
62
+ @armor_min = s if force || @armor_min.nil?
63
+ end
64
+ when Enumerable
65
+ if force || @smith_min.nil? || @armor_min.nil?
66
+ @target_weight = [@target_weight, @target_weight] if @target_weight.kind_of? Numeric
67
+ s, a = recipe.min_level(*@target_weight, opt: self)
68
+ @smith_min = s if force || @smith_min.nil?
69
+ @armor_min = a if force || @armor_min.nil?
70
+ end
71
+ else
72
+ raise ArgumentError, 'recipe should be String or Enumerable'
73
+ end
74
+ @comp_min = recipe.min_comp(opt: self) if force || @comp_min.nil?
75
+ @irep = recipe.ir(opt: self) if force || @irep.nil?
76
+ self
77
+ end
78
+ def buff
79
+ @reinforcement
80
+ end
81
+ def buff=(v)
82
+ @reinforcement = v
83
+ end
84
+ end
85
+ end
@@ -14,7 +14,7 @@ module Mgmg
14
14
  alias :inspect :to_s
15
15
  end
16
16
 
17
- # 攻 物 防 HP MP 腕 器 速 魔
17
+ # スキル名 攻 物 防 HP MP 腕 器 速 魔
18
18
  Skill = {
19
19
  '物防御UP' => Reinforcement.new( Vec[ 0, 10, 0, 0, 0, 0, 0, 0, 0] ),
20
20
  '魔防御UP' => Reinforcement.new( Vec[ 0, 0, 10, 0, 0, 0, 0, 0, 0] ),
@@ -42,9 +42,9 @@ module Mgmg
42
42
  if Skill.has_key?(arg)
43
43
  Skill[arg]
44
44
  elsif SystemCuisine.has_key?(arg)
45
- SystemCuisine[arg]
45
+ cuisine(SystemCuisine[arg])
46
46
  else
47
- raise ArgumentError, "Unknown skill or preset cuisine name `#{arg}' is given."
47
+ raise InvalidReinforcementNameError, arg
48
48
  end
49
49
  else
50
50
  raise ArgumentError, "The argument should be Mgmg::Cuisine or skill name String. (`#{arg}' is given)"