mgmg 1.4.1 → 1.4.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.
data/lib/mgmg/ir.rb CHANGED
@@ -1,373 +1,407 @@
1
- module Mgmg
2
- using Refiner
3
- class IR
4
- class Const
5
- def initialize(value)
6
- @value = value
7
- end
8
- attr_accessor :value
9
- def initialize_copy(other)
10
- @value = other.value
11
- end
12
- def evaluate(s, c)
13
- @value
14
- end
15
- def evaluate3(s, a, c)
16
- @value
17
- end
18
- def to_s
19
- @value.to_s
20
- end
21
- end
22
- class Smith
23
- def initialize(sub9, coef, den, sa=nil)
24
- @sub9, @coef, @den, @sa = sub9, coef, den, sa
25
- end
26
- attr_accessor :sub9, :coef, :den, :sa
27
- def initialize_copy(other)
28
- @sub9, @coef, @den, @sa = other.sub9, other.coef, other.den, other.sa
29
- end
30
- def evaluate(s, c)
31
- ((s+@sub9)*@coef).div(@den)
32
- end
33
- def evaluate3(s, a, c)
34
- if sa==:a
35
- ((a+@sub9)*@coef).div(@den)
36
- else
37
- ((s+@sub9)*@coef).div(@den)
38
- end
39
- end
40
- def to_s
41
- if sa==:a
42
- "[#{@coef}(a+#{@sub9})/#{den}]"
43
- else
44
- "[#{@coef}(s+#{@sub9})/#{den}]"
45
- end
46
- end
47
- end
48
- class Compose
49
- def initialize(main, sub, equip9, coef, den)
50
- @main, @sub, @equip9, @coef, @den = main, sub, equip9, coef, den
51
- end
52
- attr_accessor :main, :sub, :equip9, :coef, :den
53
- def initialize_copy(other)
54
- @main, @sub = other.main.dup, other.sub.dup
55
- @equip9, @coef, @den = other.equip9, other.coef, other.den
56
- end
57
- def evaluate(s, c)
58
- @main.evaluate(s, c) + ( ( @sub.evaluate(s, c) * (c+@equip9).div(2) ).cdiv(100) * @coef ).cdiv(@den)
59
- end
60
- def evaluate3(s, a, c)
61
- @main.evaluate3(s, a, c) + ( ( @sub.evaluate3(s, a, c) * (c+@equip9).div(2) ).cdiv(100) * @coef ).cdiv(@den)
62
- end
63
- def to_s
64
- ms, ss = @main.to_s, @sub.to_s
65
- if ss == '0'
66
- ms
67
- else
68
- if ms == '0'
69
- "[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
70
- else
71
- "#{ms}+[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
72
- end
73
- end
74
- end
75
- end
76
- class Multi
77
- def initialize(body)
78
- @body = body
79
- end
80
- attr_accessor :body
81
- def initialize_copy(other)
82
- @body = other.body.dup
83
- end
84
- def evaluate(s, c)
85
- @body.sum do |e|
86
- e.evaluate(s, c)
87
- end
88
- end
89
- def evaluate3(s, a, c)
90
- @body.sum do |e|
91
- e.evaluate3(s, a, c)
92
- end
93
- end
94
- def to_s
95
- @body.map(&:to_s).join('+')
96
- end
97
- end
98
- class << Multi
99
- def sum(a, b)
100
- unconsts, const = [], Const.new(0)
101
- case a
102
- when Multi
103
- if a.body[0].kind_of?(Const)
104
- const.value += a.body[0].value
105
- unconsts = a.body[1..(-1)]
106
- else
107
- unconsts = a.body.dup
108
- end
109
- when Const
110
- const.value += a.value
111
- else
112
- unconsts << a
113
- end
114
- case b
115
- when Multi
116
- if b.body[0].kind_of?(Const)
117
- const.value += b.body[0].value
118
- unconsts.concat(b.body[1..(-1)])
119
- else
120
- unconsts.concat(b.body)
121
- end
122
- when Const
123
- const.value += b.value
124
- else
125
- unconsts << b
126
- end
127
- body = ( const.value == 0 ? unconsts : [const, *unconsts] )
128
- case body.size
129
- when 0
130
- const
131
- when 1
132
- body[0]
133
- else
134
- new(body)
135
- end
136
- end
137
- end
138
- def initialize(kind, star, main_m, sub_m, para)
139
- @kind, @star, @main, @sub, @para = kind, star, main_m, sub_m, para
140
- end
141
- attr_accessor :kind, :star, :main, :sub, :para
142
- def initialize_copy(other)
143
- @kind = other.kind
144
- @star = other.star
145
- @main = other.main
146
- @sub = other.sub
147
- @para = other.para.dup
148
- end
149
-
150
- def compose(other)
151
- self.class.compose(self, other)
152
- end
153
-
154
- def to_s
155
- par = @para.map.with_index{|e, i| e.to_s=='0' ? nil : "#{Mgmg::Equip::ParamList[i]}:#{e.to_s}"}.compact
156
- if @kind == 28
157
- ep = @star.map.with_index{|e, i| e==0 ? nil : "#{Mgmg::Equip::EqPosList[i]}:#{e}"}.compact
158
- "複数装備(#{ep.join(', ')})<#{par.join(', ')}>"
159
- else
160
- "#{EquipName[@kind]}☆#{@star}(#{MaterialClass[@main]}#{MaterialClass[@sub]})<#{par.join(', ')}>"
161
- end
162
- end
163
-
164
- def para_call(para, s, ac, x=nil)
165
- if x.nil?
166
- method(para).call(s, ac)
167
- else
168
- method(para).call(s, ac, x)
169
- end
170
- end
171
-
172
- %i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |sym, i|
173
- define_method(sym) do |s=nil, ac=s, x=nil|
174
- if s.nil?
175
- @para[i]
176
- elsif x.nil?
177
- @para[i].evaluate(s, ac)
178
- else
179
- @para[i].evaluate3(s, ac, x)
180
- end
181
- end
182
- end
183
- def atkstr(s, ac, x=nil)
184
- attack(s, ac, x)+str(s, ac, x)
185
- end
186
- def atk_sd(s, ac, x=nil)
187
- attack(s, ac, x)+str(s, ac, x).quo(2)+dex(s, ac, x).quo(2)
188
- end
189
- def dex_as(s, ac, x=nil)
190
- attack(s, ac, x).quo(2)+str(s, ac, x).quo(2)+dex(s, ac, x)
191
- end
192
- def mag_das(s, ac, x=nil)
193
- magic(s, ac, x)+dex_as(s, ac, x).quo(2)
194
- end
195
- def magic2(s, ac, x=nil)
196
- magic(s, ac, x)*2
197
- end
198
- def magmag(s, ac, x=nil)
199
- magdef(s, ac, x)+magic(s, ac, x).quo(2)
200
- end
201
- def pmdef(s, ac, x=nil)
202
- [phydef(s, ac, x), magmag(s, ac, x)].min
203
- end
204
-
205
- def power(s, a=s, c=a.tap{a=s})
206
- case @kind
207
- when 0, 1
208
- atk_sd(s, c)
209
- when 2, 3
210
- atkstr(s, c)
211
- when 4
212
- [dex_as(s, c), mag_das(s, c)].max
213
- when 5
214
- dex_as(s, c)
215
- when 6, 7
216
- [magic(s, c)*2, atkstr(s, c)].max
217
- when 28
218
- @para.sum{|e| e.evaluate3(s, a, c)}-((hp(s, a, c)+mp(s, a, c))*3.quo(4))
219
- else
220
- ret = @para.map{|e| e.evaluate3(s, a, c)}.max
221
- if ret == magdef(s, a, c)
222
- ret+magic(s, a, c).quo(2)
223
- else
224
- ret
225
- end
226
- end
227
- end
228
- def fpower(s, a=s, c=a.tap{a=s})
229
- power(s, a, c).to_f
230
- end
231
-
232
- def smith_cost(s, c=s, outsourcing=false)
233
- if outsourcing
234
- if @kind < 8
235
- (@star**2)*2+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)
236
- else
237
- (@star**2)+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)
238
- end
239
- else
240
- if @kind < 8
241
- ((@star**2)*2+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)).div(2)
242
- else
243
- ((@star**2)+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)).div(2)
244
- end
245
- end
246
- end
247
- def comp_cost(s, c=s, outsourcing=false)
248
- if outsourcing
249
- [(@star**2)*5+@para.sum{|e| e.evaluate(s, c)}+hp().cdiv(4)-hp()+mp().cdiv(4)-mp(), 0].max.div(2)
250
- else
251
- [((@star**2)*5+@para.sum{|e| e.evaluate(s, c)}+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2), 0].max.div(2)
252
- end
253
- end
254
- alias :cost :comp_cost
255
-
256
- def add!(other)
257
- if @kind == 28
258
- if other.kind == 28
259
- @star.add!(other.star)
260
- else
261
- @star[EquipPosition[other.kind]] += 1
262
- end
263
- else
264
- @star = Vec.new(6, 0)
265
- @star[EquipPosition[@kind]] = 1
266
- @kind = 28
267
- if other.kind == 28
268
- @star.add!(other.star)
269
- else
270
- @star[EquipPosition[other.kind]] += 1
271
- end
272
- end
273
- @main, @sub = 12, 12
274
- @para = Array.new(9) do |i|
275
- Multi.sum(self.para[i], other.para[i])
276
- end
277
- self
278
- end
279
- def +(other)
280
- self.dup.add!(other)
281
- end
282
- def coerce(other)
283
- if other == 0
284
- zero = self.class.new(28, Vec.new(6, 0), 12, 12, Array.new(9){Const.new(0)})
285
- [zero, self]
286
- else
287
- raise TypeError, "Mgmg::IR can't be coerced into other than 0"
288
- end
289
- end
290
- end
291
- class << IR
292
- def build(str, left_associative: true)
293
- str = Mgmg.check_string(str)
294
- stack, str = build_sub0([], str)
295
- build_sub(stack, str, left_associative)
296
- end
297
- private def build_sub0(stack, str)
298
- SystemEquip.each do |k, v|
299
- if Regexp.compile(k).match(str)
300
- stack << from_equip(v)
301
- str = str.gsub(k, "<#{stack.length-1}>")
302
- end
303
- end
304
- [stack, str]
305
- end
306
- private def build_sub(stack, str, lassoc)
307
- if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
308
- stack << build_sub(stack, m[2], lassoc)
309
- build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
310
- elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
311
- compose(build_sub(stack, m[1], lassoc), build_sub(stack, m[2], lassoc))
312
- elsif m = /\A\<(\d+)\>\Z/.match(str)
313
- stack[m[1].to_i]
314
- else
315
- smith(str)
316
- end
317
- end
318
-
319
- def compose(main, sub)
320
- main_k, sub_k = main.kind, sub.kind
321
- main_s, sub_s = main.star, sub.star
322
- main_main, sub_main = main.main, sub.main
323
- main_sub, sub_sub = main.sub, sub.sub
324
-
325
- coef = Equip9[main_k].dup
326
- coef.sub!(Equip9[sub_k])
327
- coef.add!( 100 + (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) )
328
- coef.add!(Material9[main_main]).sub!(Material9[sub_main])
329
- den = ( main_k==sub_k ? 200 : 100 )
330
- para = Array.new(9) do |i|
331
- if EquipFilter[main_k][i] == 0
332
- main.para[i]
333
- else
334
- Mgmg::IR::Compose.new(main.para[i], sub.para[i], Equip9[main_k][i], coef[i], den)
335
- end
336
- end
337
-
338
- new(main_k, main_s+sub_s, main_sub, sub_main, para)
339
- end
340
- def smith(str)
341
- str = Mgmg.check_string(str)
342
- unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
343
- raise InvalidSmithError.new(str)
344
- end
345
- kind = EquipIndex[m[1].to_sym]
346
- unless kind
347
- raise InvalidEquipClassError.new(m[1])
348
- end
349
- main_m, main_s, main_mc = Mgmg.parse_material(m[2])
350
- sub_m, sub_s, sub_mc = Mgmg.parse_material(m[3])
351
- sa = ( Mgmg::EquipPosition[kind] == 0 ? :s : :a )
352
-
353
- coef = Equip9[kind].dup
354
- coef.e_mul!(Main9[main_m]).e_div!(100)
355
- den = ( main_mc==sub_mc ? 200 : 100 )
356
- para = Array.new(9) do |i|
357
- if coef[i] == 0
358
- Mgmg::IR::Const.new(0)
359
- else
360
- Mgmg::IR::Smith.new(Sub9[sub_m][i], coef[i], den, sa)
361
- end
362
- end
363
-
364
- new(kind, (main_s+sub_s).div(2), main_mc, sub_mc, para)
365
- end
366
- def from_equip(equip)
367
- para = equip.para.map do |value|
368
- Mgmg::IR::Const.new(value)
369
- end
370
- new(equip.kind, equip.star, equip.main, equip.sub, para)
371
- end
372
- end
373
- end
1
+ module Mgmg
2
+ using Refiner
3
+ class IR
4
+ class Const
5
+ def initialize(value)
6
+ @value = value
7
+ end
8
+ attr_accessor :value
9
+ def initialize_copy(other)
10
+ @value = other.value
11
+ end
12
+ def evaluate(s, c)
13
+ @value
14
+ end
15
+ def evaluate3(s, a, c)
16
+ @value
17
+ end
18
+ def to_s
19
+ @value.to_s
20
+ end
21
+ end
22
+ class Smith
23
+ def initialize(sub9, coef, den, sa=nil)
24
+ @sub9, @coef, @den, @sa = sub9, coef, den, sa
25
+ end
26
+ attr_accessor :sub9, :coef, :den, :sa
27
+ def initialize_copy(other)
28
+ @sub9, @coef, @den, @sa = other.sub9, other.coef, other.den, other.sa
29
+ end
30
+ def evaluate(s, c)
31
+ ((s+@sub9)*@coef).div(@den)
32
+ end
33
+ def evaluate3(s, a, c)
34
+ if sa==:a
35
+ ((a+@sub9)*@coef).div(@den)
36
+ else
37
+ ((s+@sub9)*@coef).div(@den)
38
+ end
39
+ end
40
+ def to_s
41
+ if sa==:a
42
+ "[#{@coef}(a+#{@sub9})/#{den}]"
43
+ else
44
+ "[#{@coef}(s+#{@sub9})/#{den}]"
45
+ end
46
+ end
47
+ end
48
+ class Compose
49
+ def initialize(main, sub, equip9, coef, den)
50
+ @main, @sub, @equip9, @coef, @den = main, sub, equip9, coef, den
51
+ end
52
+ attr_accessor :main, :sub, :equip9, :coef, :den
53
+ def initialize_copy(other)
54
+ @main, @sub = other.main.dup, other.sub.dup
55
+ @equip9, @coef, @den = other.equip9, other.coef, other.den
56
+ end
57
+ def evaluate(s, c)
58
+ @main.evaluate(s, c) + ( ( @sub.evaluate(s, c) * (c+@equip9).div(2) ).cdiv(100) * @coef ).cdiv(@den)
59
+ end
60
+ def evaluate3(s, a, c)
61
+ @main.evaluate3(s, a, c) + ( ( @sub.evaluate3(s, a, c) * (c+@equip9).div(2) ).cdiv(100) * @coef ).cdiv(@den)
62
+ end
63
+ def to_s
64
+ ms, ss = @main.to_s, @sub.to_s
65
+ if ss == '0'
66
+ ms
67
+ else
68
+ if ms == '0'
69
+ "[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
70
+ else
71
+ "#{ms}+[[#{ss}[(c+#{@equip9})/2]/100]/#{@den}]"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ class Multi
77
+ def initialize(body)
78
+ @body = body
79
+ end
80
+ attr_accessor :body
81
+ def initialize_copy(other)
82
+ @body = other.body.dup
83
+ end
84
+ def evaluate(s, c)
85
+ @body.sum do |e|
86
+ e.evaluate(s, c)
87
+ end
88
+ end
89
+ def evaluate3(s, a, c)
90
+ @body.sum do |e|
91
+ e.evaluate3(s, a, c)
92
+ end
93
+ end
94
+ def to_s
95
+ @body.map(&:to_s).join('+')
96
+ end
97
+ end
98
+ class << Multi
99
+ def sum(a, b)
100
+ unconsts, const = [], Const.new(0)
101
+ case a
102
+ when Multi
103
+ if a.body[0].kind_of?(Const)
104
+ const.value += a.body[0].value
105
+ unconsts = a.body[1..(-1)]
106
+ else
107
+ unconsts = a.body.dup
108
+ end
109
+ when Const
110
+ const.value += a.value
111
+ else
112
+ unconsts << a
113
+ end
114
+ case b
115
+ when Multi
116
+ if b.body[0].kind_of?(Const)
117
+ const.value += b.body[0].value
118
+ unconsts.concat(b.body[1..(-1)])
119
+ else
120
+ unconsts.concat(b.body)
121
+ end
122
+ when Const
123
+ const.value += b.value
124
+ else
125
+ unconsts << b
126
+ end
127
+ body = ( const.value == 0 ? unconsts : [const, *unconsts] )
128
+ case body.size
129
+ when 0
130
+ const
131
+ when 1
132
+ body[0]
133
+ else
134
+ new(body)
135
+ end
136
+ end
137
+ end
138
+ def initialize(kind, star, main_m, sub_m, para, rein=[])
139
+ @kind, @star, @main, @sub, @para = kind, star, main_m, sub_m, para
140
+ add_reinforcement(rein)
141
+ end
142
+ def add_reinforcement(rein)
143
+ @rein = if rein.kind_of?(Array)
144
+ rein.map do |r|
145
+ Reinforcement.compile(r)
146
+ end
147
+ else
148
+ [Reinforcement.compile(rein)]
149
+ end
150
+ self
151
+ end
152
+ attr_accessor :kind, :star, :main, :sub, :para, :rein
153
+ def initialize_copy(other)
154
+ @kind = other.kind
155
+ @star = other.star
156
+ @main = other.main
157
+ @sub = other.sub
158
+ @para = other.para.dup
159
+ @rein = other.rein.dup
160
+ end
161
+
162
+ def compose(other)
163
+ self.class.compose(self, other)
164
+ end
165
+
166
+ def to_s
167
+ par = @para.map.with_index{|e, i| e.to_s=='0' ? nil : "#{Mgmg::Equip::ParamList[i]}:#{e.to_s}"}.compact
168
+ if @kind == 28
169
+ ep = @star.map.with_index{|e, i| e==0 ? nil : "#{Mgmg::Equip::EqPosList[i]}:#{e}"}.compact
170
+ "複数装備(#{ep.join(', ')})<#{par.join(', ')}>#{@rein.empty? ? '' : '{'+@rein.join(',')+'}'}"
171
+ else
172
+ "#{EquipName[@kind]}☆#{@star}(#{MaterialClass[@main]}#{MaterialClass[@sub]})<#{par.join(', ')}>#{@rein.empty? ? '' : '{'+@rein.join(',')+'}'}"
173
+ end
174
+ end
175
+
176
+ def para_call(para, s, ac, x=nil)
177
+ if x.nil?
178
+ method(para).call(s, ac)
179
+ else
180
+ method(para).call(s, ac, x)
181
+ end
182
+ end
183
+
184
+ %i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |sym, i|
185
+ define_method(sym) do |s=nil, ac=s, x=nil|
186
+ ret = if s.nil?
187
+ @para[i]
188
+ elsif x.nil?
189
+ @para[i].evaluate(s, ac)
190
+ else
191
+ @para[i].evaluate3(s, ac, x)
192
+ end
193
+ @rein.each do |r|
194
+ if r.vec[i] != 0
195
+ ret *= (100+r.vec[i]).quo(100)
196
+ end
197
+ end
198
+ ret
199
+ end
200
+ end
201
+ def atkstr(s, ac, x=nil)
202
+ attack(s, ac, x)+str(s, ac, x)
203
+ end
204
+ def atk_sd(s, ac, x=nil)
205
+ attack(s, ac, x)+str(s, ac, x).quo(2)+dex(s, ac, x).quo(2)
206
+ end
207
+ def dex_as(s, ac, x=nil)
208
+ attack(s, ac, x).quo(2)+str(s, ac, x).quo(2)+dex(s, ac, x)
209
+ end
210
+ def mag_das(s, ac, x=nil)
211
+ magic(s, ac, x)+dex_as(s, ac, x).quo(2)
212
+ end
213
+ def magic2(s, ac, x=nil)
214
+ magic(s, ac, x)*2
215
+ end
216
+ def magmag(s, ac, x=nil)
217
+ magdef(s, ac, x)+magic(s, ac, x).quo(2)
218
+ end
219
+ def pmdef(s, ac, x=nil)
220
+ [phydef(s, ac, x), magmag(s, ac, x)].min
221
+ end
222
+
223
+ def power(s, a=s, c=a.tap{a=s})
224
+ case @kind
225
+ when 0, 1
226
+ atk_sd(s, c)
227
+ when 2, 3
228
+ atkstr(s, c)
229
+ when 4
230
+ [dex_as(s, c), mag_das(s, c)].max
231
+ when 5
232
+ dex_as(s, c)
233
+ when 6, 7
234
+ [magic(s, c)*2, atkstr(s, c)].max
235
+ when 28
236
+ @para.enum_for(:sum).with_index do |e, i|
237
+ x = e.evaluate3(s, a, c)
238
+ @rein.each do |r|
239
+ if r.vec[i] != 0
240
+ x *= (100+r.vec[i]).quo(100)
241
+ end
242
+ end
243
+ x
244
+ end-((hp(s, a, c)+mp(s, a, c))*3.quo(4))
245
+ else
246
+ ret = @para.map.with_index do |e, i|
247
+ x = e.evaluate3(s, a, c)
248
+ @rein.each do |r|
249
+ if r.vec[i] != 0
250
+ x *= (100+r.vec[i]).quo(100)
251
+ end
252
+ end
253
+ x
254
+ end.max
255
+ if ret == magdef(s, a, c)
256
+ ret+magic(s, a, c).quo(2)
257
+ else
258
+ ret
259
+ end
260
+ end
261
+ end
262
+ def fpower(s, a=s, c=a.tap{a=s})
263
+ power(s, a, c).to_f
264
+ end
265
+
266
+ def smith_cost(s, c=s, outsourcing=false)
267
+ if outsourcing
268
+ if @kind < 8
269
+ (@star**2)*2+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)
270
+ else
271
+ (@star**2)+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)
272
+ end
273
+ else
274
+ if @kind < 8
275
+ ((@star**2)*2+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)).div(2)
276
+ else
277
+ ((@star**2)+@para.sum{|e| e.evaluate(s, c)}+hp(s, c).cdiv(4)-hp(s, c)+mp(s, c).cdiv(4)-mp(s, c)).div(2)
278
+ end
279
+ end
280
+ end
281
+ def comp_cost(s, c=s, outsourcing=false)
282
+ if outsourcing
283
+ [(@star**2)*5+@para.sum{|e| e.evaluate(s, c)}+hp().cdiv(4)-hp()+mp().cdiv(4)-mp(), 0].max.div(2)
284
+ else
285
+ [((@star**2)*5+@para.sum{|e| e.evaluate(s, c)}+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2), 0].max.div(2)
286
+ end
287
+ end
288
+ alias :cost :comp_cost
289
+
290
+ def add!(other)
291
+ if @kind == 28
292
+ if other.kind == 28
293
+ @star.add!(other.star)
294
+ else
295
+ @star[EquipPosition[other.kind]] += 1
296
+ end
297
+ else
298
+ @star = Vec.new(6, 0)
299
+ @star[EquipPosition[@kind]] = 1
300
+ @kind = 28
301
+ if other.kind == 28
302
+ @star.add!(other.star)
303
+ else
304
+ @star[EquipPosition[other.kind]] += 1
305
+ end
306
+ end
307
+ @main, @sub = 12, 12
308
+ @para = Array.new(9) do |i|
309
+ Multi.sum(self.para[i], other.para[i])
310
+ end
311
+ self
312
+ end
313
+ def +(other)
314
+ self.dup.add!(other)
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
324
+ end
325
+ class << IR
326
+ def build(str, left_associative: true, reinforcement: [])
327
+ str = Mgmg.check_string(str)
328
+ stack, str = build_sub0([], str)
329
+ build_sub(stack, str, left_associative).add_reinforcement(reinforcement)
330
+ end
331
+ private def build_sub0(stack, str)
332
+ SystemEquip.each do |k, v|
333
+ if Regexp.compile(k).match(str)
334
+ stack << from_equip(v)
335
+ str = str.gsub(k, "<#{stack.length-1}>")
336
+ end
337
+ end
338
+ [stack, str]
339
+ end
340
+ private def build_sub(stack, str, lassoc)
341
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
342
+ stack << build_sub(stack, m[2], lassoc)
343
+ build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
344
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
345
+ compose(build_sub(stack, m[1], lassoc), build_sub(stack, m[2], lassoc))
346
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
347
+ stack[m[1].to_i]
348
+ else
349
+ smith(str)
350
+ end
351
+ end
352
+
353
+ def compose(main, sub)
354
+ main_k, sub_k = main.kind, sub.kind
355
+ main_s, sub_s = main.star, sub.star
356
+ main_main, sub_main = main.main, sub.main
357
+ main_sub, sub_sub = main.sub, sub.sub
358
+
359
+ coef = Equip9[main_k].dup
360
+ coef.sub!(Equip9[sub_k])
361
+ coef.add!( 100 + (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) )
362
+ coef.add!(Material9[main_main]).sub!(Material9[sub_main])
363
+ den = ( main_k==sub_k ? 200 : 100 )
364
+ para = Array.new(9) do |i|
365
+ if EquipFilter[main_k][i] == 0
366
+ main.para[i]
367
+ else
368
+ Mgmg::IR::Compose.new(main.para[i], sub.para[i], Equip9[main_k][i], coef[i], den)
369
+ end
370
+ end
371
+
372
+ new(main_k, main_s+sub_s, main_sub, sub_main, para)
373
+ end
374
+ def smith(str)
375
+ str = Mgmg.check_string(str)
376
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
377
+ raise InvalidSmithError.new(str)
378
+ end
379
+ kind = EquipIndex[m[1].to_sym]
380
+ unless kind
381
+ raise InvalidEquipClassError.new(m[1])
382
+ end
383
+ main_m, main_s, main_mc = Mgmg.parse_material(m[2])
384
+ sub_m, sub_s, sub_mc = Mgmg.parse_material(m[3])
385
+ sa = ( Mgmg::EquipPosition[kind] == 0 ? :s : :a )
386
+
387
+ coef = Equip9[kind].dup
388
+ coef.e_mul!(Main9[main_m]).e_div!(100)
389
+ den = ( main_mc==sub_mc ? 200 : 100 )
390
+ para = Array.new(9) do |i|
391
+ if coef[i] == 0
392
+ Mgmg::IR::Const.new(0)
393
+ else
394
+ Mgmg::IR::Smith.new(Sub9[sub_m][i], coef[i], den, sa)
395
+ end
396
+ end
397
+
398
+ new(kind, (main_s+sub_s).div(2), main_mc, sub_mc, para)
399
+ end
400
+ def from_equip(equip)
401
+ para = equip.para.map do |value|
402
+ Mgmg::IR::Const.new(value)
403
+ end
404
+ new(equip.kind, equip.star, equip.main, equip.sub, para)
405
+ end
406
+ end
407
+ end