mgmg 1.2.3 → 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.
data/lib/mgmg/equip.rb ADDED
@@ -0,0 +1,396 @@
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.append(0).max
72
+ end
73
+ end
74
+
75
+ def para_call(para)
76
+ method(para).call
77
+ end
78
+
79
+ %i|attack phydef magdef hp mp str dex speed magic|.each.with_index do |s, i|
80
+ define_method(s){ @para[i] }
81
+ end
82
+ def atkstr
83
+ attack()+str()
84
+ end
85
+ def atk_sd
86
+ attack()*2+str()+dex()
87
+ end
88
+ def dex_as
89
+ attack()+str()+dex()*2
90
+ end
91
+ def mag_das
92
+ magic()*4+dex_as()
93
+ end
94
+ [:fire, :earth, :water].each.with_index do |s, i|
95
+ define_method(s){ @element[i] }
96
+ end
97
+
98
+ def power
99
+ case @kind
100
+ when 0, 1
101
+ atk_sd()*2
102
+ when 2, 3
103
+ atkstr()*4
104
+ when 4
105
+ [dex_as()*2, mag_das()].max
106
+ when 5
107
+ dex_as()*2
108
+ when 6, 7
109
+ [magic()*8, atkstr()*4].max
110
+ when 28
111
+ (@para.sum*4)-((hp()+mp())*3)
112
+ else
113
+ ret = @para.max
114
+ if ret == magdef()
115
+ ret*2+magic()
116
+ else
117
+ ret*2
118
+ end
119
+ end
120
+ end
121
+ def magmag
122
+ magdef()*2+magic()
123
+ end
124
+ def fpower
125
+ if @kind < 8 || @kind == 28
126
+ power().fdiv(4)
127
+ else
128
+ power().fdiv(2)
129
+ end
130
+ end
131
+
132
+ def smith_cost(outsourcing=false)
133
+ if outsourcing
134
+ if @kind < 8
135
+ (@star**2)*2+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()
136
+ else
137
+ (@star**2)+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()
138
+ end
139
+ else
140
+ if @kind < 8
141
+ ((@star**2)*2+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2)
142
+ else
143
+ ((@star**2)+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2)
144
+ end
145
+ end
146
+ end
147
+ def comp_cost(outsourcing=false)
148
+ if outsourcing
149
+ [(@star**2)*5+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp(), 0].max
150
+ else
151
+ [((@star**2)*5+@para.sum+hp().cdiv(4)-hp()+mp().cdiv(4)-mp()).div(2), 0].max
152
+ end
153
+ end
154
+ alias :cost :comp_cost
155
+
156
+ def add!(other)
157
+ if @kind == 28
158
+ if other.kind == 28
159
+ @star.add!(other.star)
160
+ else
161
+ @star[EquipPosition[other.kind]] += 1
162
+ end
163
+ else
164
+ @star = Vec.new(6, 0)
165
+ @star[EquipPosition[@kind]] = 1
166
+ @kind = 28
167
+ if other.kind == 28
168
+ @star.add!(other.star)
169
+ else
170
+ @star[EquipPosition[other.kind]] += 1
171
+ end
172
+ end
173
+ @weight += other.weight
174
+ @main = 12
175
+ @sub = 12
176
+ @para.add!(other.para)
177
+ @element.add!(other.element)
178
+ @total_cost.add!(other.total_cost)
179
+ @history.concat(other.history)
180
+ @min_levels.merge!(other.min_levels)
181
+ self
182
+ end
183
+ def +(other)
184
+ self.dup.add!(other)
185
+ end
186
+ def coerce(other)
187
+ if other == 0
188
+ zero = self.class.new(28, 0, Vec.new(6, 0), 12, 12, Vec.new(9, 0), Vec.new(3, 0))
189
+ zero.history.clear
190
+ [zero, self]
191
+ else
192
+ raise TypeError, "Mgmg::Equip can't be coerced into other than 0"
193
+ end
194
+ end
195
+ end
196
+
197
+ class << Equip
198
+ def build(str, s_level, c_level, left_associative: true)
199
+ str = Mgmg.check_string(str)
200
+ stack, str = build_sub0([], str)
201
+ build_sub(stack, str, s_level, c_level, left_associative)
202
+ end
203
+ private def build_sub0(stack, str)
204
+ SystemEquip.each do |k, v|
205
+ if Regexp.compile(k).match(str)
206
+ stack << v
207
+ str = str.gsub(k, "<#{stack.length-1}>")
208
+ end
209
+ end
210
+ [stack, str]
211
+ end
212
+ private def build_sub(stack, str, s_level, c_level, lassoc)
213
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
214
+ stack << build_sub(stack, m[2], s_level, c_level, lassoc)
215
+ build_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", s_level, c_level, lassoc)
216
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
217
+ if c_level < 0
218
+ compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), 0, true)
219
+ else
220
+ compose(build_sub(stack, m[1], s_level, c_level, lassoc), build_sub(stack, m[2], s_level, c_level, lassoc), c_level, false)
221
+ end
222
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
223
+ stack[m[1].to_i]
224
+ else
225
+ if s_level < 0
226
+ smith(str, 0, true)
227
+ else
228
+ smith(str, s_level, false)
229
+ end
230
+ end
231
+ end
232
+
233
+ def compose(main, sub, level, outsourcing)
234
+ main_k, sub_k = main.kind, sub.kind
235
+ main_s, sub_s = main.star, sub.star
236
+ main_main, sub_main = main.main, sub.main
237
+ main_sub, sub_sub = main.sub, sub.sub
238
+ para = Vec.new(9, 0)
239
+ ele = Vec.new(3, 0)
240
+
241
+ # 9パラメータ
242
+ coef = Equip9[main_k].dup
243
+ para[] = coef
244
+ para.add!(level).e_div!(2)
245
+ para.e_mul!(sub.para).e_div!(100)
246
+ coef.sub!(Equip9[sub_k])
247
+ coef.add!( 100 + (main_s-sub_s)*5 - ( ( main_main==sub_main && main_main != 9 ) ? 30 : 0 ) )
248
+ coef.add!(Material9[main_main]).sub!(Material9[sub_main])
249
+ coef.e_mul!(EquipFilter[main_k])
250
+ para.e_mul!(coef).e_div!( main_k==sub_k ? 200 : 100 )
251
+ para.add!(main.para)
252
+
253
+ # エレメント
254
+ ele[] = sub.element
255
+ ele.e_mul!([75, level].min).e_div!( main_k==sub_k ? 200 : 100 )
256
+ ele.add!(main.element)
257
+
258
+ ret = new(main_k, main.weight+sub.weight, main_s+sub_s, main_sub, sub_main, para, ele)
259
+ ret.total_cost.add!(main.total_cost).add!(sub.total_cost)
260
+ ret.total_cost[1] += ret.comp_cost(outsourcing)
261
+ ret.min_levels.merge!(main.min_levels, sub.min_levels)
262
+ ret.history = [*main.history, *sub.history, ret]
263
+ ret
264
+ end
265
+
266
+ def smith(str, level, outsourcing)
267
+ str = Mgmg.check_string(str)
268
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
269
+ raise InvalidSmithError.new(str)
270
+ end
271
+ kind = EquipIndex[m[1].to_sym]
272
+ unless kind
273
+ raise InvalidEquipClassError.new(m[1])
274
+ end
275
+ main_m, main_s, main_mc = parse_material(m[2])
276
+ sub_m, sub_s, sub_mc = parse_material(m[3])
277
+ para = Vec.new(9, 0)
278
+ ele = Vec.new(3, 0)
279
+
280
+ # 9パラメータ
281
+ para[] = Equip9[kind]
282
+ para.e_mul!(Main9[main_m]).e_div!(100)
283
+ coef = Sub9[sub_m].dup
284
+ coef.add!(level)
285
+ para.e_mul!(coef).e_div!( main_mc==sub_mc ? 200 : 100 )
286
+
287
+ # エレメント
288
+ ele[] = MainEL[main_m]
289
+ ele.e_mul!(SubEL[sub_m]).e_div!(6)
290
+
291
+ # 重量
292
+ weight = ( ( EquipWeight[kind] + SubWeight[sub_m] - level.div(2) ) * ( MainWeight[main_m] ) ).div(10000)
293
+
294
+ ret = new(kind, ( weight<1 ? 1 : weight ), (main_s+sub_s).div(2), main_mc, sub_mc, para, ele)
295
+ if kind < 8
296
+ ret.total_cost[0] = ret.smith_cost(outsourcing)
297
+ else
298
+ ret.total_cost[2] = ret.smith_cost(outsourcing)
299
+ end
300
+ ret.min_levels.store(str, str.min_level)
301
+ ret
302
+ end
303
+
304
+ def min_level(str, weight=1)
305
+ str = Mgmg.check_string(str)
306
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
307
+ raise InvalidSmithError.new(str)
308
+ end
309
+ kind = EquipIndex[m[1].to_sym]
310
+ main_m, main_s, = parse_material(m[2])
311
+ sub_m, sub_s, = parse_material(m[3])
312
+
313
+ q, r = ((weight+1)*10000).divmod(MainWeight[main_m])
314
+ l = ( EquipWeight[kind] + SubWeight[sub_m] - q + ( r==0 ? 1 : 0 ) )*2
315
+ [(main_s-1)*3, (sub_s-1)*3, l].max
316
+ end
317
+
318
+ private def parse_material(str)
319
+ m = /\A.+?(\d+)\Z/.match(str)
320
+ mat = MaterialIndex[str.to_sym]
321
+ if m.nil? || mat.nil?
322
+ raise InvalidMaterialError.new(str)
323
+ end
324
+ [mat, m[1].to_i, mat<90 ? mat.div(10): 9]
325
+ end
326
+
327
+ def min_comp(str, left_associative: true)
328
+ str = Mgmg.check_string(str)
329
+ stack, str = minc_sub0([], str)
330
+ (minc_sub(stack, str, left_associative)[1]-1)*3
331
+ end
332
+ private def minc_sub0(stack, str)
333
+ SystemEquip.each do |k, v|
334
+ if Regexp.compile(k).match(str)
335
+ stack << v.star
336
+ str = str.gsub(k, "<#{stack.length-1}>")
337
+ end
338
+ end
339
+ [stack, str]
340
+ end
341
+ private def minc_sub(stack, str, lassoc)
342
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
343
+ stack << minc_sub(stack, m[2], lassoc)[0]
344
+ minc_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
345
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
346
+ a, _ = minc_sub(stack, m[1], lassoc)
347
+ b, _ = minc_sub(stack, m[2], lassoc)
348
+ [a+b, [a, b].max]
349
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
350
+ [stack[m[1].to_i], 1]
351
+ else
352
+ [smith(str, 0, true).star, 1]
353
+ end
354
+ end
355
+
356
+ def min_smith(str, left_associative: true)
357
+ str = Mgmg.check_string(str)
358
+ stack, str = mins_sub0([], str)
359
+ (([mins_sub(stack, str, left_associative)]+stack).max-1)*3
360
+ end
361
+ private def mins_sub0(stack, str)
362
+ SystemEquip.each do |k, v|
363
+ if Regexp.compile(k).match(str)
364
+ stack << 0
365
+ str = str.gsub(k, "<#{stack.length-1}>")
366
+ end
367
+ end
368
+ [stack, str]
369
+ end
370
+ private def mins_sub(stack, str, lassoc)
371
+ if m = /\A(.*\+?)\[([^\[\]]+)\](\+?[^\[]*)\Z/.match(str)
372
+ stack << mins_sub(stack, m[2], lassoc)
373
+ mins_sub(stack, "#{m[1]}<#{stack.length-1}>#{m[3]}", lassoc)
374
+ elsif m = ( lassoc ? /\A(.+)\+(.+?)\Z/ : /\A(.+?)\+(.+)\Z/ ).match(str)
375
+ [mins_sub(stack, m[1], lassoc), mins_sub(stack, m[2], lassoc)].max
376
+ elsif m = /\A\<(\d+)\>\Z/.match(str)
377
+ 1
378
+ else
379
+ mins_sub2(str)
380
+ end
381
+ end
382
+ private def mins_sub2(str)
383
+ str = Mgmg.check_string(str)
384
+ unless m = /\A(.+)\((.+\d+),?(.+\d+)\)\Z/.match(str)
385
+ raise InvalidSmithError.new(str)
386
+ end
387
+ kind = EquipIndex[m[1].to_sym]
388
+ unless kind
389
+ raise InvalidEquipClassError.new(m[1])
390
+ end
391
+ main_m, main_s, main_mc = parse_material(m[2])
392
+ sub_m, sub_s, sub_mc = parse_material(m[3])
393
+ [main_s, sub_s].max
394
+ end
395
+ end
396
+ end
@@ -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