mgmg 1.4.1 → 1.5.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.
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,84 @@
1
+ module Mgmg
2
+ class Option
3
+ def initialize(
4
+ left_associative: true,
5
+ smith_min: nil, armor_min:nil, comp_min: nil, smith_max: 10000, armor_max: 10000, comp_max: 10000,
6
+ step: 1, magdef_maximize: true,
7
+ target_weight: 0, reinforcement: [], buff: nil,
8
+ irep: nil, cut_exp: Float::INFINITY
9
+ )
10
+ @left_associative = left_associative
11
+ @smith_min = smith_min
12
+ @armor_min = armor_min
13
+ @comp_min = comp_min
14
+ @smith_max = smith_max
15
+ @armor_max = armor_max
16
+ @comp_max = comp_max
17
+ @step = step
18
+ @magdef_maximize = magdef_maximize
19
+ @target_weight = target_weight
20
+ @reinforcement = reinforcement
21
+ unless buff.nil?
22
+ if @reinforcement.empty?
23
+ @reinforcement = buff
24
+ else
25
+ raise ArgumentError, "reinforcement and buff are exclusive"
26
+ end
27
+ end
28
+ @irep = irep
29
+ @cut_exp = cut_exp
30
+ end
31
+ attr_accessor :left_associative, :smith_min, :armor_min, :comp_min, :smith_max, :armor_max, :comp_max
32
+ attr_accessor :step, :magdef_maximize, :target_weight, :reinforcement, :irep, :cut_exp
33
+ def initialize_copy(other)
34
+ @left_associative = other.left_associative
35
+ @smith_min = other.smith_min
36
+ @armor_min = other.armor_min
37
+ @comp_min = other.comp_min
38
+ @smith_max = other.smith_max
39
+ @armor_max = other.armor_max
40
+ @comp_max = other.comp_max
41
+ @step = other.step
42
+ @magdef_maximize = other.magdef_maximize
43
+ @target_weight = other.target_weight
44
+ @reinforcement = other.reinforcement.dup
45
+ @irep = other.irep
46
+ @cut_exp = other.cut_exp
47
+ end
48
+ def update_sa_min(recipe, force=true)
49
+ case recipe
50
+ when String
51
+ if @smith_min.nil? && @armor_min
52
+ @smith_min = @armor_min
53
+ end
54
+ if force || @smith_min.nil?
55
+ s = recipe.min_level(@target_weight, opt: self)
56
+ @smith_min = s if force || @smith_min.nil?
57
+ @armor_min = s if force || @armor_min.nil?
58
+ end
59
+ when Enumerable
60
+ if force || @smith_min.nil? || @armor_min.nil?
61
+ @target_weight = [@target_weight, @target_weight] if @target_weight.kind_of? Numeric
62
+ s, a = recipe.min_level(*@target_weight, opt: self)
63
+ @smith_min = s if force || @smith_min.nil?
64
+ @armor_min = a if force || @armor_min.nil?
65
+ end
66
+ else
67
+ raise ArgumentError, 'recipe should be String or Enumerable'
68
+ end
69
+ self
70
+ end
71
+ def set_default(recipe, force: false)
72
+ update_sa_min(recipe, force)
73
+ @comp_min = recipe.min_comp(opt: self) if force || @comp_min.nil?
74
+ @irep = recipe.ir(opt: self) if force || @irep.nil?
75
+ self
76
+ end
77
+ def buff
78
+ @reinforcement
79
+ end
80
+ def buff=(v)
81
+ @reinforcement = v
82
+ end
83
+ end
84
+ end
data/lib/mgmg/poly.rb CHANGED
@@ -301,8 +301,8 @@ module Mgmg
301
301
  raise ArgumentError.new("given string `#{str}' is unparsable as a smithing recipe")
302
302
  end
303
303
  kind = EquipIndex[m[1].to_sym]
304
- main_m, main_s, main_mc = Equip.__send__(:parse_material, m[2])
305
- sub_m, sub_s, sub_mc = Equip.__send__(:parse_material, m[3])
304
+ main_m, main_s, main_mc = Mgmg.parse_material(m[2])
305
+ sub_m, sub_s, sub_mc = Mgmg.parse_material(m[3])
306
306
  para = ParamIndex[para]
307
307
 
308
308
  c = ( Equip9[kind][para] * Main9[main_m][para] ).cdiv(100).quo( main_mc==sub_mc ? 200 : 100 )
@@ -0,0 +1,172 @@
1
+ module Mgmg
2
+ class Recipe
3
+ def initialize(recipe, para=:power, **kw)
4
+ @recipe = recipe
5
+ @recipe.each(&:freeze) if @recipe.kind_of?(Enumerable)
6
+ @recipe.freeze
7
+ @para = para
8
+ @option = Option.new(**kw).set_default(@recipe)
9
+ end
10
+ attr_reader :recipe
11
+ attr_accessor :para
12
+ def initialize_copy(other)
13
+ @recipe = other.recipe.dup
14
+ @option = other.option.dup
15
+ end
16
+ private def temp_opt(**kw)
17
+ if kw.empty?
18
+ @option
19
+ else
20
+ ret = @option.dup
21
+ kw.each do |key, value|
22
+ ret.method((key.to_s+'=').to_sym).call(value)
23
+ ret.update_sa_min(@recipe) if key == :target_weight
24
+ ret.irep.add_reinforcement(value) if key == :reinforcement || key == :buff
25
+ if key == :left_associative
26
+ ret.irep = @recipe.ir(opt: ret).add_reinforcement(ret.reinforcement)
27
+ end
28
+ end
29
+ ret
30
+ end
31
+ end
32
+ def option(**kw)
33
+ @option = temp_opt(*kw)
34
+ @option
35
+ end
36
+ def option=(new_option)
37
+ @option = new_option.set_default(@recipe)
38
+ end
39
+ def replace(new_recipe, para: @para, **kw)
40
+ @recipe = new_recipe
41
+ @recipe.each(&:freeze) if @recipe.kind_of?(Enumerable)
42
+ @recipe.freeze
43
+ @para = para
44
+ @option = Option.new(**kw).set_default(@recipe)
45
+ self
46
+ end
47
+ def min_weight
48
+ @recipe.min_weight(opt: @option)
49
+ end
50
+ def max_weight(include_outsourcing=false)
51
+ @recipe.max_weight(opt: @option)
52
+ end
53
+ def min_level(w=@option.target_weight, include_outsourcing=false)
54
+ @recipe.min_level(w, include_outsourcing, opt: @option)
55
+ end
56
+ def min_levels(w=1)
57
+ @recipe.min_levels(w, opt: @option)
58
+ end
59
+ def min_levels_max(w=1)
60
+ @recipe.min_levels_max(w, opt: @option)
61
+ end
62
+ def min_smith
63
+ @recipe.min_smith
64
+ end
65
+ def min_comp
66
+ @recipe.min_comp
67
+ end
68
+ def build(smith=-1, armor=smith, comp=armor.tap{armor=smith}, **kw)
69
+ opt = temp_opt(**kw)
70
+ smith, armor, comp = opt.smith_min, opt.armor_min, opt.comp_min if smith.nil?
71
+ case @recipe
72
+ when String
73
+ recipe.build(smith, comp, opt: opt)
74
+ when Enumerable
75
+ recipe.build(smith, armor, comp, opt: opt)
76
+ else
77
+ raise BrokenRecipeError
78
+ end
79
+ end
80
+ def show(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: @para, **kw)
81
+ opt = temp_opt(**kw)
82
+ smith, armor, comp = opt.smith_min, opt.armor_min, opt.comp_min if smith.nil?
83
+ case @recipe
84
+ when String
85
+ recipe.show(smith, comp, para: para, opt: opt)
86
+ when Enumerable
87
+ recipe.show(smith, armor, comp, para: para, opt: opt)
88
+ else
89
+ raise BrokenRecipeError
90
+ end
91
+ end
92
+ def search(target, para: @para, **kw)
93
+ opt = temp_opt(**kw)
94
+ @recipe.search(para, target, opt: opt)
95
+ end
96
+ private def correct_level(s, ac, x, opt)
97
+ if s.nil?
98
+ if x.equal?(false)
99
+ s, ac, x = opt.smith_min, opt.comp_min, nil
100
+ else
101
+ s, ac, x = opt.smith_min, opt.armor_min, opt.comp_min
102
+ end
103
+ else
104
+ s = 0 if s < 0
105
+ ac = 0 if ac < 0
106
+ if x.equal?(false)
107
+ x = nil
108
+ else
109
+ x = 0 if x < 0
110
+ end
111
+ end
112
+ [s, ac, x]
113
+ end
114
+ def para_call(smith=-1, armor=smith, comp=armor.tap{armor=smith}, para: @para, **kw)
115
+ opt = temp_opt(**kw)
116
+ smith, armor, comp = correct_level(smith, armor, comp, opt)
117
+ case @recipe
118
+ when String
119
+ opt.irep.para_call(para, smith, comp)
120
+ when Enumerable
121
+ opt.irep.para_call(para, smith, armor, comp)
122
+ else
123
+ raise InvalidRecipeError
124
+ end
125
+ end
126
+ def ir(**kw)
127
+ temp_opt(**kw).irep
128
+ end
129
+ %i|attack phydef magdef hp mp str dex speed magic atkstr atk_sd dex_as mag_das magic2 magmag pmdef|.each do |sym|
130
+ define_method(sym) do |s, ac=s, x=false, **kw|
131
+ s, ac, x = correct_level(s, ac, x, temp_opt(**kw))
132
+ ir(**kw).method(sym).call(s, ac, x)
133
+ end
134
+ end
135
+ %i|power fpower|.each do |sym|
136
+ define_method(sym) do |s, a=s, c=a.tap{a=s}, **kw|
137
+ s, a, c = correct_level(s, a, c, temp_opt(**kw))
138
+ ir(**kw).method(sym).call(s, a, c)
139
+ end
140
+ end
141
+ %i|smith_cost comp_cost cost|.each do |sym|
142
+ define_method(sym) do |s, c=s, outsourcing=false, **kw|
143
+ s, c, x = correct_level(s, c, false, temp_opt(**kw))
144
+ ir(**kw).method(sym).call(s, c, out_sourcing)
145
+ end
146
+ end
147
+ def poly(para=@para, **kw)
148
+ opt = temp_opt(**kw)
149
+ if @recipe.kind_of?(String)
150
+ @recipe.poly(para, opt: opt)
151
+ else
152
+ raise InvalidRecipeError, "Mgmg::Recipe#poly is available only for String recipes."
153
+ end
154
+ end
155
+ def phydef_optimize(smith=nil, comp=smith, **kw)
156
+ opt = temp_opt(**kw)
157
+ if @recipe.kind_of?(String)
158
+ @recipe.phydef_optimize(smith, comp, opt: opt)
159
+ else
160
+ raise InvalidRecipeError, "Mgmg::Recipe#phydef_optimize is available only for String recipes."
161
+ end
162
+ end
163
+ def buster_optimize(smith=nil, comp=smith, **kw)
164
+ opt = temp_opt(**kw)
165
+ if @recipe.kind_of?(String)
166
+ @recipe.buster_optimize(smith, comp, opt: opt)
167
+ else
168
+ raise InvalidRecipeError, "Mgmg::Recipe#buster_optimize is available only for String recipes."
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,70 @@
1
+ module Mgmg
2
+ class Reinforcement
3
+ def initialize(vec)
4
+ @vec = vec
5
+ end
6
+ attr_accessor :vec
7
+ def initialize_copy(other)
8
+ @vec = other.vec.dup
9
+ end
10
+
11
+ def to_s
12
+ '(' + @vec.map.with_index{|e, i| e==0 ? nil : "#{Equip::ParamList[i]}:#{e}"}.compact.join(', ') + ')'
13
+ end
14
+ alias :inspect :to_s
15
+ end
16
+
17
+ # スキル名 攻 物 防 HP MP 腕 器 速 魔
18
+ Skill = {
19
+ '物防御UP' => Reinforcement.new( Vec[ 0, 10, 0, 0, 0, 0, 0, 0, 0] ),
20
+ '魔防御UP' => Reinforcement.new( Vec[ 0, 0, 10, 0, 0, 0, 0, 0, 0] ),
21
+ '腕力UP' => Reinforcement.new( Vec[ 0, 0, 0, 0, 0, 10, 0, 0, 0] ),
22
+ 'メンテナンス' => Reinforcement.new( Vec[ 50, 0, 0, 0, 0, 0, 0, 0, 0] ),
23
+ 'ガードアップ' => Reinforcement.new( Vec[ 0, 50, 0, 0, 0, 0, 0, 0, 0] ),
24
+ 'パワーアップ' => Reinforcement.new( Vec[ 0, 0, 0, 0, 0, 50, 0, 0, 0] ),
25
+ 'デックスアップ' => Reinforcement.new( Vec[ 0, 0, 0, 0, 0, 0, 50, 0, 0] ),
26
+ 'スピードアップ' => Reinforcement.new( Vec[ 0, 0, 0, 0, 0, 0, 0, 50, 0] ),
27
+ 'マジックアップ' => Reinforcement.new( Vec[ 0, 0, 0, 0, 0, 0, 0, 0, 50] ),
28
+ 'オールアップ' => Reinforcement.new( Vec[ 0, 50, 0, 0, 0, 50, 50, 50, 50] ),
29
+ }
30
+
31
+ class << Reinforcement
32
+ def cuisine(c)
33
+ Reinforcement.new( Vec[*(c.vec), *Array.new(6, 0)] )
34
+ end
35
+ def compile(arg)
36
+ case arg
37
+ when Reinforcement
38
+ arg
39
+ when Cuisine
40
+ cuisine(arg)
41
+ when String
42
+ if Skill.has_key?(arg)
43
+ Skill[arg]
44
+ elsif SystemCuisine.has_key?(arg)
45
+ cuisine(SystemCuisine[arg])
46
+ else
47
+ raise InvalidReinforcementNameError, arg
48
+ end
49
+ else
50
+ raise ArgumentError, "The argument should be Mgmg::Cuisine or skill name String. (`#{arg}' is given)"
51
+ end
52
+ end
53
+ end
54
+
55
+ class Equip
56
+ def reinforce(*arg)
57
+ arg.each do |r|
58
+ r = Reinforcement.compile(r)
59
+ @para.map!.with_index do |pr, i|
60
+ if r.vec[i] == 0
61
+ pr
62
+ else
63
+ pr * (100+r.vec[i]).quo(100)
64
+ end
65
+ end
66
+ end
67
+ self
68
+ end
69
+ end
70
+ end