mgmg 1.2.4 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,323 @@
1
+ module Mgmg
2
+ using Refiner
3
+ class Equip
4
+ ParamList = %w|攻撃 物防 魔防 HP MP 腕力 器用 素早 魔力|
5
+ ElementList = %w|火 地 水|
6
+ EqPosList = %w|武 頭 胴 腕 足 飾|
7
+ def initialize(kind, weight, star, main_m, sub_m, para, element)
8
+ @kind, @weight, @star, @main, @sub, @para, @element = kind, weight, star, main_m, sub_m, para, element
9
+ @total_cost = Vec[0, 0, 0]
10
+ @history, @min_levels = [self], Hash.new
11
+ end
12
+ attr_accessor :kind, :weight, :star, :main, :sub, :para, :element, :total_cost, :history, :min_levels
13
+ def initialize_copy(other)
14
+ @kind = other.kind
15
+ @weight = other.weight
16
+ @star = other.star
17
+ @main = other.main
18
+ @sub = other.sub
19
+ @para = other.para.dup
20
+ @element = other.element.dup
21
+ @total_cost = other.total_cost.dup
22
+ @history = other.history.dup
23
+ @min_levels = other.min_levels.dup
24
+ end
25
+
26
+ def compose(other, level, outsourcing=false)
27
+ self.class.compose(self, other, level, outsourcing)
28
+ end
29
+
30
+ def to_s
31
+ par = @para.map.with_index{|e, i| e==0 ? nil : "#{ParamList[i]}:#{e.comma3}"}.compact
32
+ elm = @element.map.with_index{|e, i| e==0 ? nil : "#{ElementList[i]}#{e}"}.compact
33
+ unless elm.empty?
34
+ par << "EL:#{elm.join('')}"
35
+ end
36
+ if @kind == 28
37
+ ep = @star.map.with_index{|e, i| e==0 ? nil : "#{EqPosList[i]}:#{e}"}.compact
38
+ "複数装備#{@weight}(#{ep.join(', ')})[#{par.join(', ')}]"
39
+ else
40
+ "#{EquipName[@kind]}#{@weight}☆#{@star}(#{MaterialClass[@main]}#{MaterialClass[@sub]})[#{par.join(', ')}]"
41
+ end
42
+ end
43
+ def inspect
44
+ par = @para.map.with_index{|e, i| "#{ParamList[i]}:#{e}"}
45
+ par << ( "EL:" + @element.map.with_index{|e, i| "#{ElementList[i]}#{e}"}.join('') )
46
+ tc = "<コスト:" + @total_cost.map.with_index{|e, i| "#{ElementList[i]}#{e}"}.join('') + '>'
47
+ if @kind == 28
48
+ ep = @star.map.with_index{|e, i| "#{EqPosList[i]}:#{e}"}
49
+ "複数装備#{@weight}(#{ep.join(', ')})[#{par.join(', ')}]#{tc}"
50
+ else
51
+ "#{EquipName[@kind]}#{@weight}☆#{@star}(#{MaterialClass[@main]}#{MaterialClass[@sub]})[#{par.join(', ')}]#{tc}"
52
+ end
53
+ end
54
+
55
+ def min_level
56
+ if @kind == 28
57
+ ret = [0, 0]
58
+ @min_levels.each do |str, ml|
59
+ if str.build(-1).kind < 8
60
+ if ret[0] < ml
61
+ ret[0] = ml
62
+ end
63
+ else
64
+ if ret[1] < ml
65
+ ret[1] = ml
66
+ end
67
+ end
68
+ end
69
+ ret
70
+ else
71
+ @min_levels.values.max
72
+ end
73
+ end
74
+
75
+ %i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |s, i|
76
+ define_method(s){ @para[i] }
77
+ end
78
+ def atkstr
79
+ attack()+str()
80
+ end
81
+ def atk_sd
82
+ attack()*2+str()+dex()
83
+ end
84
+ def dex_as
85
+ attack()+str()+dex()*2
86
+ end
87
+ def mag_das
88
+ magic()*4+dex_as()
89
+ end
90
+ [:fire, :earth, :water].each.with_index do |s, i|
91
+ define_method(s){ @element[i] }
92
+ end
93
+
94
+ def power
95
+ case @kind
96
+ when 0, 1
97
+ atk_sd()*2
98
+ when 2, 3
99
+ atkstr()*4
100
+ when 4
101
+ [dex_as()*2, mag_das()].max
102
+ when 5
103
+ dex_as()*2
104
+ when 6, 7
105
+ [magic()*8, atkstr()*4].max
106
+ when 28
107
+ (@para.sum*4)-((hp()+mp())*3)
108
+ else
109
+ ret = @para.max
110
+ if ret == magdef()
111
+ ret*2+magic()
112
+ else
113
+ ret*2
114
+ end
115
+ end
116
+ end
117
+ def magmag
118
+ magdef()*2+magic()
119
+ end
120
+ def fpower
121
+ if @kind < 8 || @kind == 28
122
+ power().fdiv(4)
123
+ else
124
+ power().fdiv(2)
125
+ end
126
+ end
127
+
128
+ def smith_cost(outsourcing=false)
129
+ if outsourcing
130
+ if @kind < 8
131
+ (@star**2)*2+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()
132
+ else
133
+ (@star**2)+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()
134
+ end
135
+ else
136
+ if @kind < 8
137
+ ((@star**2)*2+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2)
138
+ else
139
+ ((@star**2)+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2)
140
+ end
141
+ end
142
+ end
143
+ def comp_cost(outsourcing=false)
144
+ if outsourcing
145
+ [(@star**2)*5+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp(), 0].max
146
+ else
147
+ [((@star**2)*5+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2), 0].max
148
+ end
149
+ end
150
+ alias :cost :comp_cost
151
+
152
+ def add!(other)
153
+ if @kind == 28
154
+ if other.kind == 28
155
+ @star.add!(other.star)
156
+ else
157
+ @star[EquipPosition[other.kind]] += 1
158
+ end
159
+ else
160
+ @star = Vec.new(6, 0)
161
+ @star[EquipPosition[@kind]] = 1
162
+ @kind = 28
163
+ if other.kind == 28
164
+ @star.add!(other.star)
165
+ else
166
+ @star[EquipPosition[other.kind]] += 1
167
+ end
168
+ end
169
+ @weight += other.weight
170
+ @main = 12
171
+ @sub = 12
172
+ @para.add!(other.para)
173
+ @element.add!(other.element)
174
+ @total_cost.add!(other.total_cost)
175
+ @history.concat(other.history)
176
+ @min_levels.merge!(other.min_levels)
177
+ self
178
+ end
179
+ def +(other)
180
+ self.dup.add!(other)
181
+ end
182
+ def coerce(other)
183
+ if other == 0
184
+ zero = self.class.new(28, 0, Vec.new(6, 0), 12, 12, Vec.new(9, 0), Vec.new(3, 0))
185
+ zero.history.clear
186
+ [zero, self]
187
+ else
188
+ raise TypeError, "Mgmg::Equip can't be coerced into other than 0"
189
+ end
190
+ end
191
+ end
192
+
193
+ class << Equip
194
+ def build(str, s_level, c_level, left_associative: true)
195
+ str = Mgmg.check_string(str)
196
+ stack, str = build_sub0([], str)
197
+ build_sub(stack, str, s_level, c_level, left_associative)
198
+ end
199
+ private def build_sub0(stack, str)
200
+ SystemEquip.each do |k, v|
201
+ if Regexp.compile(k).match(str)
202
+ stack << v
203
+ str = str.gsub(k, "<#{stack.length-1}>")
204
+ end
205
+ end
206
+ [stack, str]
207
+ end
208
+ private def build_sub(stack, str, s_level, c_level, lassoc)
209
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
210
+ stack << build_sub(stack, m[2], s_level, c_level, lassoc)
211
+ build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", s_level, c_level, lassoc)
212
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
213
+ if c_level < 0
214
+ compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), 0, true)
215
+ else
216
+ compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), c_level, false)
217
+ end
218
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
219
+ stack[m[1].to_i]
220
+ else
221
+ if s_level < 0
222
+ smith(str, 0, true)
223
+ else
224
+ smith(str, s_level, false)
225
+ end
226
+ end
227
+ end
228
+
229
+ def compose(main, sub, level, outsourcing)
230
+ main_k, sub_k = main.kind, sub.kind
231
+ main_s, sub_s = main.star, sub.star
232
+ main_main, sub_main = main.main, sub.main
233
+ main_sub, sub_sub = main.sub, sub.sub
234
+ para = Vec.new(9, 0)
235
+ ele = Vec.new(3, 0)
236
+
237
+ # 9パラメータ
238
+ coef = Equip9[main_k].dup
239
+ para[] = coef
240
+ para.add!(level).e_div!(2)
241
+ para.e_mul!(sub.para).e_div!(100)
242
+ coef.sub!(Equip9[sub_k])
243
+ coef.add!( 100 + (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) )
244
+ coef.add!(Material9[main_main]).sub!(Material9[sub_main])
245
+ coef.e_mul!(EquipFilter[main_k])
246
+ para.e_mul!(coef).e_div!( main_k==sub_k ? 200 : 100 )
247
+ para.add!(main.para)
248
+
249
+ # エレメント
250
+ ele[] = sub.element
251
+ ele.e_mul!([75, level].min).e_div!( main_k==sub_k ? 200 : 100 )
252
+ ele.add!(main.element)
253
+
254
+ ret = new(main_k, main.weight+sub.weight, main_s+sub_s, main_sub, sub_main, para, ele)
255
+ ret.total_cost.add!(main.total_cost).add!(sub.total_cost)
256
+ ret.total_cost[1] += ret.comp_cost(outsourcing)
257
+ ret.min_levels.merge!(main.min_levels, sub.min_levels)
258
+ ret.history = [*main.history, *sub.history, ret]
259
+ ret
260
+ end
261
+
262
+ def smith(str, level, outsourcing)
263
+ str = Mgmg.check_string(str)
264
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
265
+ raise InvalidSmithError.new(str)
266
+ end
267
+ kind = EquipIndex[m[1].to_sym]
268
+ unless kind
269
+ raise InvalidEquipClassError.new(m[1])
270
+ end
271
+ main_m, main_s, main_mc = parse_material(m[2])
272
+ sub_m, sub_s, sub_mc = parse_material(m[3])
273
+ para = Vec.new(9, 0)
274
+ ele = Vec.new(3, 0)
275
+
276
+ # 9パラメータ
277
+ para[] = Equip9[kind]
278
+ para.e_mul!(Main9[main_m]).e_div!(100)
279
+ coef = Sub9[sub_m].dup
280
+ coef.add!(level)
281
+ para.e_mul!(coef).e_div!( main_mc==sub_mc ? 200 : 100 )
282
+
283
+ # エレメント
284
+ ele[] = MainEL[main_m]
285
+ ele.e_mul!(SubEL[sub_m]).e_div!(6)
286
+
287
+ # 重量
288
+ weight = ( ( EquipWeight[kind] + SubWeight[sub_m] - level.div(2) ) * ( MainWeight[main_m] ) ).div(10000)
289
+
290
+ ret = new(kind, ( weight<1 ? 1 : weight ), (main_s+sub_s).div(2), main_mc, sub_mc, para, ele)
291
+ if kind < 8
292
+ ret.total_cost[0] = ret.smith_cost(outsourcing)
293
+ else
294
+ ret.total_cost[2] = ret.smith_cost(outsourcing)
295
+ end
296
+ ret.min_levels.store(str, str.min_level)
297
+ ret
298
+ end
299
+
300
+ def min_level(str, weight=1)
301
+ str = Mgmg.check_string(str)
302
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
303
+ raise InvalidSmithError.new(str)
304
+ end
305
+ kind = EquipIndex[m[1].to_sym]
306
+ main_m, main_s, = parse_material(m[2])
307
+ sub_m, sub_s, = parse_material(m[3])
308
+
309
+ q, r = ((weight+1)*10000).divmod(MainWeight[main_m])
310
+ l = ( EquipWeight[kind] + SubWeight[sub_m] - q + ( r==0 ? 1 : 0 ) )*2
311
+ [(main_s-1)*3, (sub_s-1)*3, l].max
312
+ end
313
+
314
+ private def parse_material(str)
315
+ m = /\A.+?(\d+)\Z/.match(str)
316
+ mat = MaterialIndex[str.to_sym]
317
+ if m.nil? || mat.nil?
318
+ raise InvalidMaterialError.new(str)
319
+ end
320
+ [mat, m[1].to_i, mat<90 ? mat.div(10): 9]
321
+ end
322
+ end
323
+ end
@@ -0,0 +1,266 @@
1
+ module Mgmg
2
+ using Refiner
3
+ class TPolynomial
4
+ def initialize(mat, kind, star, main_m, sub_m)
5
+ @mat, @kind, @star, @main, @sub = mat, kind, star, main_m, sub_m
6
+ end
7
+ attr_accessor :mat, :kind, :star, :main, :sub
8
+ def initialize_copy(obj)
9
+ @mat, @kind, @star, @main, @sub = obj.mat.dup, obj.kind, obj.star, obj.main, obj.sub
10
+ end
11
+ def evaluate(smith, comp=smith)
12
+ @mat.map_with_index do |e, i, j|
13
+ e * (smith**i) * (comp**j)
14
+ end.sum
15
+ end
16
+ def to_s(fmt=nil)
17
+ foo = []
18
+ (@mat.col_size-1).downto(0) do |c|
19
+ bar = []
20
+ (@mat.row_size-1).downto(0) do |s|
21
+ value = @mat.body[s][c]
22
+ baz = str(value, fmt)
23
+ case s
24
+ when 0
25
+ # nothing to do
26
+ when 1
27
+ baz << 'S'
28
+ else
29
+ baz << "S^#{s}"
30
+ end
31
+ bar << baz if value != 0
32
+ end
33
+ case bar.length
34
+ when 0
35
+ next
36
+ when 1
37
+ bar = bar[0]
38
+ else
39
+ bar = "(#{bar.join('+')})"
40
+ end
41
+ case c
42
+ when 0
43
+ # nothing to do
44
+ when 1
45
+ bar << 'C'
46
+ else
47
+ bar << "C^#{c}"
48
+ end
49
+ foo << bar
50
+ end
51
+ foo.join('+').tap{|r| break str(0.quo(1), fmt) if r==''}
52
+ end
53
+ private def str(value, fmt)
54
+ ret = case fmt
55
+ when NilClass
56
+ value.to_s
57
+ when String
58
+ fmt % value
59
+ when Symbol
60
+ value.__send__(fmt)
61
+ when Proc
62
+ fmt.call(value)
63
+ else
64
+ raise
65
+ end
66
+ if ret[0] == '-' || ( /\//.match(ret) && ret[0] != '(' )
67
+ "(#{ret})"
68
+ else
69
+ ret
70
+ end
71
+ end
72
+ def inspect(fmt=->(r){"Rational(#{r.numerator}, #{r.denominator})"})
73
+ foo = []
74
+ (@mat.col_size-1).downto(0) do |c|
75
+ bar = []
76
+ (@mat.row_size-1).downto(0) do |s|
77
+ value = @mat.body[s][c]
78
+ bar << str(value, fmt)
79
+ end
80
+ buff = bar[0]
81
+ buff = "#{buff}*s+#{bar[1]}" if 1 < bar.length
82
+ 2.upto(bar.length-1) do |i|
83
+ buff = "(#{buff})*s+#{bar[i]}"
84
+ end
85
+ foo << buff
86
+ end
87
+ ret = foo[0]
88
+ 1.upto(foo.length-1) do |i|
89
+ ret = "(#{ret})*c+#{foo[i]}"
90
+ end
91
+ ret
92
+ end
93
+ def leading(fmt=nil)
94
+ value = self[-1, -1]
95
+ if fmt.nil?
96
+ value
97
+ else
98
+ str(value, fmt)
99
+ end
100
+ end
101
+ def smith_balance(other, order=-1)
102
+ o_org = order
103
+ order += @mat.col_size if order < 0
104
+ if order < 0 || @mat.col_size <= order || other.mat.col_size <= order then
105
+ raise ArgumentError, "given order #{o_org} is out of range [-max(#{@mat.col_size}, #{other.mat.col_size}), max(#{@mat.col_size}, #{other.mat.col_size})-1]"
106
+ end
107
+ a, b, c, d = @mat.body[1][order], @mat.body[0][order], other.mat.body[1][order], other.mat.body[0][order]
108
+ if a == c
109
+ return( b == d )
110
+ else
111
+ return( (d-b).quo(a-c) )
112
+ end
113
+ end
114
+ def smith_fix(smith, fmt=nil)
115
+ foo = []
116
+ (@mat.col_size-1).downto(0) do |c|
117
+ bar = 0
118
+ (@mat.row_size-1).downto(0) do |s|
119
+ bar += ( @mat.body[s][c] * (smith**s) )
120
+ end
121
+ bar = str(bar, fmt)
122
+ case c
123
+ when 0
124
+ # nothing to do
125
+ when 1
126
+ bar << 'C'
127
+ else
128
+ bar << "C^#{c}"
129
+ end
130
+ foo << bar
131
+ end
132
+ foo.join('+')
133
+ end
134
+
135
+ alias :+@ :dup
136
+ def -@
137
+ ret = self.dup
138
+ ret.mat.scalar!(-1)
139
+ ret
140
+ end
141
+ def +(other)
142
+ mat = @mat.padd(other.mat)
143
+ self.class.new(mat, 28, 0, 12, 12)
144
+ end
145
+ def -(other)
146
+ mat = @mat.padd(other.mat.scalar(-1))
147
+ self.class.new(mat, 28, 0, 12, 12)
148
+ end
149
+ def scalar(val)
150
+ ret = self.dup
151
+ ret.mat.scalar!(val)
152
+ ret
153
+ end
154
+ alias :* :scalar
155
+ def quo(val)
156
+ ret = self.dup
157
+ ret.mat.scalar!(1.quo(val))
158
+ ret
159
+ end
160
+ alias :/ :quo
161
+
162
+ def partial_derivative(variable)
163
+ case variable.to_s
164
+ when /\Ac/i
165
+ if @mat.col_size <= 1
166
+ self.class.new(Mat.new(1, 1, 0), 28, 0, 12, 12)
167
+ else
168
+ mat = Mat.new(@mat.row_size, @mat.col_size-1) do |i, j|
169
+ @mat.body[i][j+1] * (j+1)
170
+ end
171
+ self.class.new(mat, 28, 0, 12, 12)
172
+ end
173
+ when /\As/i
174
+ if @mat.row_size <= 1
175
+ self.class.new(Mat.new(1, 1, 0), 28, 0, 12, 12)
176
+ else
177
+ mat = Mat.new(@mat.row_size-1, @mat.col_size) do |i, j|
178
+ @mat.body[i+1][j] * (i+1)
179
+ end
180
+ self.class.new(mat, 28, 0, 12, 12)
181
+ end
182
+ else
183
+ raise ArgumentError, "the argument must be `s' or `c', not `#{variable}'"
184
+ end
185
+ end
186
+
187
+ def [](i, j)
188
+ if (i < 0 && @mat.body.size < -i) || (j < 0 && @mat.body[0].size < -j)
189
+ raise IndexError, "(#{i}, #{j}) is out of (#{@mat.body.size}, #{@mat.body[0].size})"
190
+ end
191
+ begin
192
+ ret = @mat.body[i][j]
193
+ rescue NoMethodError
194
+ return 0
195
+ end
196
+ ret.nil? ? 0 : ret
197
+ end
198
+ end
199
+ class << TPolynomial
200
+ ParamIndex = Hash.new
201
+ %i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |s, i|
202
+ ParamIndex.store(s, i)
203
+ ParamIndex.store(i, i)
204
+ ParamIndex.store(Equip::ParamList[i], i)
205
+ end
206
+ def from_equip(equip, para)
207
+ new(Mat.new(1, 1, equip.para[ParamIndex[para]]), equip.kind, equip.star, equip.main, equip.sub)
208
+ end
209
+ def smith(str, para)
210
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
211
+ raise ArgumentError.new("given string `#{str}' is unparsable as a smithing recipe")
212
+ end
213
+ kind = EquipIndex[m[1].to_sym]
214
+ main_m, main_s, main_mc = Equip.__send__(:parse_material, m[2])
215
+ sub_m, sub_s, sub_mc = Equip.__send__(:parse_material, m[3])
216
+ para = ParamIndex[para]
217
+
218
+ c = ( Equip9[kind][para] * Main9[main_m][para] ).cdiv(100).quo( main_mc==sub_mc ? 200 : 100 )
219
+ new(Mat.v_array(c*Sub9[sub_m][para], c), kind, (main_s+sub_s).div(2), main_mc, sub_mc)
220
+ end
221
+ def compose(main, sub, para)
222
+ main_k, sub_k = main.kind, sub.kind
223
+ main_s, sub_s = main.star, sub.star
224
+ main_main, sub_main = main.main, sub.main
225
+ main_sub, sub_sub = main.sub, sub.sub
226
+ para = ParamIndex[para]
227
+
228
+ if Equip9[main_k][para] == 0
229
+ c = 0.quo(1)
230
+ else
231
+ c = ( 100 + Equip9[main_k][para] - Equip9[sub_k][para] + Material9[main_main][para] - Material9[sub_main][para] +
232
+ (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) ).quo( main_k==sub_k ? 40000 : 20000 )
233
+ end
234
+ mat = main.mat.padd(sub.mat.pprod(Mat.h_array(c*Equip9[main_k][para], c)))
235
+ new(mat, main_k, main_s+sub_s, main_sub, sub_main)
236
+ end
237
+ def build(str, para, left_associative: true)
238
+ str = Mgmg.check_string(str)
239
+ _para = ParamIndex[para]
240
+ if _para.nil?
241
+ raise ArgumentError, "unknown parameter symbol `#{para.inspect}' given"
242
+ end
243
+ stack, str = build_sub0([], str, _para)
244
+ build_sub(stack, str, _para, left_associative)
245
+ end
246
+ private def build_sub0(stack, str, para)
247
+ SystemEquip.each do |k, v|
248
+ stack << from_equip(v, para)
249
+ str = str.gsub(k, "<#{stack.length-1}>")
250
+ end
251
+ [stack, str]
252
+ end
253
+ private def build_sub(stack, str, para, lassoc)
254
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
255
+ stack << build_sub(stack, m[2], para, lassoc)
256
+ build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", para, lassoc)
257
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
258
+ compose(build_sub(stack, m[1], para, lassoc), build_sub(stack, m[2], para, lassoc), para)
259
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
260
+ stack[m[1].to_i]
261
+ else
262
+ smith(str, para)
263
+ end
264
+ end
265
+ end
266
+ end