mgmg 1.4.0 → 1.5.0

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/search.rb CHANGED
@@ -1,254 +1,325 @@
1
1
  class String
2
- def smith_search(para, target, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
3
- if smith_min.nil?
4
- if min_smith
5
- smith_min = self.min_smith.min_smith
6
- else
7
- smith_min = build(-1, -1, left_associative: left_associative).min_level
8
- end
9
- end
10
- if smith_max < smith_min
11
- raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
12
- elsif cut_exp < Float::INFINITY
2
+ def smith_search(para, target, comp, opt: Mgmg::Option.new)
3
+ opt = opt.dup.set_default(self)
4
+ if opt.smith_max < opt.smith_min
5
+ raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{opt.smith_min}, #{opt.smith_max}) are given"
6
+ elsif opt.cut_exp < Float::INFINITY
13
7
  begin
14
- smith_max = [smith_max, Mgmg.invexp2(cut_exp, comp)].min
8
+ opt.smith_max = [opt.smith_max, Mgmg.invexp2(opt.cut_exp, comp)].min
15
9
  rescue
16
10
  raise Mgmg::SearchCutException
17
11
  end
18
12
  end
19
- if target <= build(smith_min, comp, left_associative: left_associative).para_call(para)
20
- return smith_min
21
- elsif build(smith_max, comp, left_associative: left_associative).para_call(para) < target
13
+ if target <= opt.irep.para_call(para, opt.smith_min, comp)
14
+ return opt.smith_min
15
+ elsif opt.irep.para_call(para, opt.smith_max, comp) < target
22
16
  raise Mgmg::SearchCutException
23
17
  end
24
- while 1 < smith_max - smith_min do
25
- smith = (smith_max - smith_min).div(2) + smith_min
26
- if build(smith, comp, left_associative: left_associative).para_call(para) < target
27
- smith_min = smith
18
+ while 1 < opt.smith_max - opt.smith_min do
19
+ smith = (opt.smith_max - opt.smith_min).div(2) + opt.smith_min
20
+ if opt.irep.para_call(para, smith, comp) < target
21
+ opt.smith_min = smith
28
22
  else
29
- smith_max = smith
23
+ opt.smith_max = smith
30
24
  end
31
25
  end
32
- smith_max
26
+ opt.smith_max
33
27
  end
34
- def comp_search(para, target, smith, comp_min=nil, comp_max=10000, left_associative: true)
35
- comp_min = min_comp(left_associative: left_associative)
36
- if comp_max < comp_min
37
- raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
38
- end
39
- if target <= build(smith, comp_min, left_associative: left_associative).para_call(para)
40
- return comp_min
41
- elsif build(smith, comp_max, left_associative: left_associative).para_call(para) < target
28
+ def comp_search(para, target, smith, opt: Mgmg::Option.new)
29
+ opt = opt.dup.set_default(self)
30
+ if opt.comp_max < opt.comp_min
31
+ raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{opt.comp_min}, #{opt.comp_max}) are given"
32
+ end
33
+ if target <= opt.irep.para_call(para, smith, opt.comp_min)
34
+ return opt.comp_min
35
+ elsif opt.irep.para_call(para, smith, opt.comp_max) < target
42
36
  raise Mgmg::SearchCutException
43
37
  end
44
- while 1 < comp_max - comp_min do
45
- comp = (comp_max - comp_min).div(2) + comp_min
46
- if build(smith, comp, left_associative: left_associative).para_call(para) < target
47
- comp_min = comp
38
+ while 1 < opt.comp_max - opt.comp_min do
39
+ comp = (opt.comp_max - opt.comp_min).div(2) + opt.comp_min
40
+ if opt.irep.para_call(para, smith, comp) < target
41
+ opt.comp_min = comp
48
42
  else
49
- comp_max = comp
43
+ opt.comp_max = comp
50
44
  end
51
45
  end
52
- comp_max
46
+ opt.comp_max
53
47
  end
54
- def search(para, target, smith_min=nil, comp_min=nil, smith_max=10000, comp_max=10000, left_associative: true, step: 1, cut_exp: Float::INFINITY, min_smith: false)
55
- if smith_min.nil?
56
- if min_smith
57
- smith_min = self.min_smith
58
- else
59
- smith_min = build(-1, -1, left_associative: left_associative).min_level
60
- end
61
- end
62
- comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
63
- comp_min = comp_search(para, target, smith_max, comp_min, comp_max, left_associative: left_associative)
64
- smith_max = smith_search(para, target, comp_min, smith_min, smith_max, left_associative: left_associative)
65
- smith_min = smith_search(para, target, comp_max, smith_min, smith_max, left_associative: left_associative)
66
- raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, comp_min)
67
- comp_max = comp_search(para, target, smith_min, comp_min, comp_max, left_associative: left_associative)
68
- minex, ret = Mgmg.exp(smith_min, comp_max), [smith_min, comp_max]
69
- exp = Mgmg.exp(smith_max, comp_min)
70
- minex, ret = exp, [smith_max, comp_min] if exp < minex
71
- (comp_min+step).step(comp_max-1, step) do |comp|
72
- break if minex < Mgmg.exp(smith_min, comp)
73
- smith = smith_search(para, target, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
48
+ def search(para, target, opt: Mgmg::Option.new)
49
+ opt = opt.dup.set_default(self)
50
+ opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
51
+ opt.comp_min = comp_search(para, target, opt.smith_max, opt: opt)
52
+ opt.smith_max = smith_search(para, target, opt.comp_min, opt: opt_nocut)
53
+ opt.smith_min = smith_search(para, target, opt.comp_max, opt: opt_nocut)
54
+ raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.comp_min)
55
+ opt.comp_max = comp_search(para, target, opt.smith_min, opt: opt)
56
+ ret = nil
57
+ exp = Mgmg.exp(opt.smith_min, opt.comp_max)
58
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.comp_max] if exp < opt.cut_exp
59
+ exp = Mgmg.exp(opt.smith_max, opt.comp_min)
60
+ opt.cut_exp, ret = exp, [opt.smith_max, opt.comp_min] if exp < opt.cut_exp
61
+ (opt.comp_min+opt.step).step(opt.comp_max-1, opt.step) do |comp|
62
+ break if opt.cut_exp < Mgmg.exp(opt.smith_min, comp)
63
+ smith = smith_search(para, target, comp, opt: opt)
74
64
  exp = Mgmg.exp(smith, comp)
75
- if exp < minex
76
- minex, ret = exp, [smith, comp]
77
- elsif exp == minex
78
- if build(*ret).para_call(para) < build(smith, comp).para_call(para)
65
+ if exp < opt.cut_exp
66
+ opt.cut_exp, ret = exp, [smith, comp]
67
+ elsif exp == opt.cut_exp
68
+ if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, smith, comp) then
79
69
  ret = [smith, comp]
80
70
  end
81
71
  end
82
72
  rescue Mgmg::SearchCutException
83
73
  end
84
- raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
74
+ raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{opt.cut_exp}" if ret.nil?
85
75
  ret
86
76
  end
87
77
  end
88
78
  module Enumerable
89
- def smith_search(para, target, armor, comp, smith_min=nil, smith_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
90
- if smith_min.nil?
91
- if min_smith
92
- smith_min = self.min_smith[0]
93
- else
94
- smith_min = build(-1, -1, -1, left_associative: left_associative).min_level[0]
95
- end
96
- end
97
- if smith_max < smith_min
98
- raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{smith_min}, #{smith_max}) are given"
99
- elsif cut_exp < Float::INFINITY
79
+ def smith_search(para, target, armor, comp, opt: Mgmg::Option.new)
80
+ opt = opt.dup.set_default(self)
81
+ if opt.smith_max < opt.smith_min
82
+ raise ArgumentError, "smith_min <= smith_max is needed, (smith_min, smith_max) = (#{opt.smith_min}, #{opt.smith_max}) are given"
83
+ elsif opt.cut_exp < Float::INFINITY
100
84
  begin
101
- smith_max = [smith_max, Mgmg.invexp3(cut_exp, armor, comp)].min
85
+ opt.smith_max = [opt.smith_max, Mgmg.invexp3(opt.cut_exp, armor, comp)].min
102
86
  rescue
103
87
  raise Mgmg::SearchCutException
104
88
  end
105
89
  end
106
- if build(smith_max, armor, comp, left_associative: left_associative).para_call(para) < target
90
+ if opt.irep.para_call(para, opt.smith_max, armor, comp) < target
107
91
  raise Mgmg::SearchCutException
108
- elsif target <= build(smith_min, armor, comp, left_associative: left_associative).para_call(para)
109
- return smith_min
92
+ elsif target <= opt.irep.para_call(para, opt.smith_min, armor, comp)
93
+ return opt.smith_min
110
94
  end
111
- while 1 < smith_max - smith_min do
112
- smith = (smith_max - smith_min).div(2) + smith_min
113
- if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
114
- smith_min = smith
95
+ while 1 < opt.smith_max - opt.smith_min do
96
+ smith = (opt.smith_max - opt.smith_min).div(2) + opt.smith_min
97
+ if opt.irep.para_call(para, smith, armor, comp) < target
98
+ opt.smith_min = smith
115
99
  else
116
- smith_max = smith
100
+ opt.smith_max = smith
117
101
  end
118
102
  end
119
- smith_max
103
+ opt.smith_max
120
104
  end
121
- def armor_search(para, target, smith, comp, armor_min=nil, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
122
- if armor_min.nil?
123
- if min_smith
124
- armor_min = self.min_smith[1]
125
- else
126
- armor_min = build(-1, -1, -1, left_associative: left_associative).min_level[1]
127
- end
128
- end
129
- if armor_max < armor_min
130
- raise ArgumentError, "armor_min <= armor_max is needed, (armor_min, armor_max) = (#{armor_min}, #{armor_max}) are given"
131
- elsif cut_exp < Float::INFINITY
105
+ def armor_search(para, target, smith, comp, opt: Mgmg::Option.new)
106
+ opt = opt.dup.set_default(self)
107
+ if opt.armor_max < opt.armor_min
108
+ raise ArgumentError, "armor_min <= armor_max is needed, (armor_min, armor_max) = (#{opt.armor_min}, #{opt.armor_max}) are given"
109
+ elsif opt.cut_exp < Float::INFINITY
132
110
  begin
133
- armor_max = [armor_max, Mgmg.invexp3(cut_exp, smith, comp)].min
111
+ opt.armor_max = [opt.armor_max, Mgmg.invexp3(opt.cut_exp, smith, comp)].min
134
112
  rescue
135
113
  raise Mgmg::SearchCutException
136
114
  end
137
115
  end
138
- if build(smith, armor_max, comp, left_associative: left_associative).para_call(para) < target
116
+ if opt.irep.para_call(para, smith, opt.armor_max, comp) < target
139
117
  raise Mgmg::SearchCutException
140
- elsif target <= build(smith, armor_min, comp, left_associative: left_associative).para_call(para)
141
- return armor_min
118
+ elsif target <= opt.irep.para_call(para, smith, opt.armor_min, comp)
119
+ return opt.armor_min
142
120
  end
143
- while 1 < armor_max - armor_min do
144
- armor = (armor_max - armor_min).div(2) + armor_min
145
- if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
146
- armor_min = armor
121
+ while 1 < opt.armor_max - opt.armor_min do
122
+ armor = (opt.armor_max - opt.armor_min).div(2) + opt.armor_min
123
+ if opt.irep.para_call(para, smith, armor, comp) < target
124
+ opt.armor_min = armor
147
125
  else
148
- armor_max = armor
126
+ opt.armor_max = armor
149
127
  end
150
128
  end
151
- armor_max
129
+ opt.armor_max
152
130
  end
153
- def sa_search(para, target, comp, smith_min=nil, armor_min=nil, smith_max=10000, armor_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
154
- if min_smith
155
- s, a = self.min_smith
156
- else
157
- s, a = build(-1, -1, -1, left_associative: left_associative).min_level
158
- end
159
- smith_min = s if smith_min.nil?
160
- armor_min = a if armor_min.nil?
161
- smith_min = smith_search(para, target, armor_max, comp, smith_min, smith_max, left_associative: true)
162
- armor_min = armor_search(para, target, smith_max, comp, armor_min, armor_max, left_associative: true)
163
- raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp)
164
- smith_max = smith_search(para, target, armor_min, comp, smith_min, smith_max, left_associative: true)
165
- armor_max = armor_search(para, target, smith_min, comp, armor_min, armor_max, left_associative: true)
166
- minex, ret = Mgmg.exp(smith_min, armor_max, comp), [smith_min, armor_max]
167
- exp = Mgmg.exp(smith_max, armor_min, comp)
168
- if exp < minex
169
- minex, ret = exp, [smith_max, armor_min]
170
- (armor_min+1).upto(armor_max-1) do |armor|
171
- break if minex < Mgmg.exp(smith_min, armor, comp)
172
- smith = smith_search(para, target, armor, comp, smith_min, smith_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
131
+ def sa_search(para, target, comp, opt: Mgmg::Option.new)
132
+ opt = opt.dup.set_default(self)
133
+ opt_nocut = opt.dup; opt_nocut.cut_exp = Float::INFINITY
134
+ opt.smith_min = smith_search(para, target, opt.armor_max, comp, opt: opt_nocut)
135
+ opt.armor_min = armor_search(para, target, opt.smith_max, comp, opt: opt_nocut)
136
+ raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, comp)
137
+ opt.smith_max = smith_search(para, target, opt.armor_min, comp, opt: opt_nocut)
138
+ opt.armor_max = armor_search(para, target, opt.smith_min, comp, opt: opt_nocut)
139
+ ret = nil
140
+ exp = Mgmg.exp(opt.smith_min, opt.armor_max, comp)
141
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_max] if exp < opt.cut_exp
142
+ exp2 = Mgmg.exp(opt.smith_max, opt.armor_min, comp)
143
+ if exp2 < exp
144
+ opt.cut_exp, ret = exp2, [opt.smith_max, opt.armor_min] if exp2 < opt.cut_exp
145
+ (opt.armor_min+1).upto(opt.armor_max-1) do |armor|
146
+ break if opt.cut_exp < Mgmg.exp(opt.smith_min, armor, comp)
147
+ smith = smith_search(para, target, armor, comp, opt: opt)
173
148
  exp = Mgmg.exp(smith, armor, comp)
174
- if exp < minex
175
- minex, ret = exp, [smith, armor]
176
- elsif exp == minex
177
- if build(*ret, comp).para_call(para) < build(smith, armor, comp).para_call(para)
149
+ if exp < opt.cut_exp
150
+ opt.cut_exp, ret = exp, [smith, armor]
151
+ elsif exp == opt.cut_exp
152
+ if ret.nil? or opt.irep.para_call(para, *ret, comp) < opt.irep.para_call(para, smith, armor, comp) then
178
153
  ret = [smith, armor]
179
154
  end
180
155
  end
181
156
  rescue Mgmg::SearchCutException
182
157
  end
183
158
  else
184
- (smith_min+1).upto(smith_max-1) do |smith|
185
- break if minex < Mgmg.exp(smith, armor_min, comp)
186
- armor = armor_search(para, target, smith, comp, armor_min, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
159
+ (opt.smith_min+1).upto(opt.smith_max-1) do |smith|
160
+ break if opt.cut_exp < Mgmg.exp(smith, opt.armor_min, comp)
161
+ armor = armor_search(para, target, smith, comp, opt: opt)
187
162
  exp = Mgmg.exp(smith, armor, comp)
188
- if exp < minex
189
- minex, ret = exp, [smith, armor]
190
- elsif exp == minex
191
- if build(*ret, comp).para_call(para) < build(smith, armor, comp).para_call(para)
163
+ if exp < opt.cut_exp
164
+ opt.cut_exp, ret = exp, [smith, armor]
165
+ elsif exp == opt.cut_exp
166
+ if ret.nil? or opt.irep.para_call(para, *ret, comp) < opt.irep.para_call(para, smith, armor, comp) then
192
167
  ret = [smith, armor]
193
168
  end
194
169
  end
195
170
  rescue Mgmg::SearchCutException
196
171
  end
197
172
  end
198
- raise Mgmg::SearchCutException if cut_exp < minex
173
+ raise Mgmg::SearchCutException if ret.nil?
199
174
  ret
200
175
  end
201
- def comp_search(para, target, smith, armor, comp_min=nil, comp_max=10000, left_associative: true)
202
- comp_min = min_comp(left_associative: left_associative)
203
- if comp_max < comp_min
204
- raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{comp_min}, #{comp_max}) are given"
205
- end
206
- if target <= build(smith, armor, comp_min, left_associative: left_associative).para_call(para)
207
- return comp_min
208
- elsif build(smith, armor, comp_max, left_associative: left_associative).para_call(para) < target
209
- raise ArgumentError, "given comp_max=#{comp_max} does not satisfies the target"
210
- end
211
- while 1 < comp_max - comp_min do
212
- comp = (comp_max - comp_min).div(2) + comp_min
213
- if build(smith, armor, comp, left_associative: left_associative).para_call(para) < target
214
- comp_min = comp
176
+ def comp_search(para, target, smith, armor, opt: Mgmg::Option.new)
177
+ opt = opt.dup.set_default(self)
178
+ if opt.comp_max < opt.comp_min
179
+ raise ArgumentError, "comp_min <= comp_max is needed, (comp_min, comp_max) = (#{opt.comp_min}, #{opt.comp_max}) are given"
180
+ end
181
+ if target <= opt.irep.para_call(para, smith, armor, opt.comp_min)
182
+ return opt.comp_min
183
+ elsif opt.irep.para_call(para, smith, armor, opt.comp_max) < target
184
+ raise ArgumentError, "given comp_max=#{opt.comp_max} does not satisfies the target"
185
+ end
186
+ while 1 < opt.comp_max - opt.comp_min do
187
+ comp = (opt.comp_max - opt.comp_min).div(2) + opt.comp_min
188
+ if opt.irep.para_call(para, smith, armor, comp) < target
189
+ opt.comp_min = comp
215
190
  else
216
- comp_max = comp
191
+ opt.comp_max = comp
217
192
  end
218
193
  end
219
- comp_max
194
+ opt.comp_max
220
195
  end
221
- def search(para, target, smith_min=nil, armor_min=nil, comp_min=nil, smith_max=10000, armor_max=10000, comp_max=10000, left_associative: true, cut_exp: Float::INFINITY, min_smith: false)
222
- if min_smith
223
- s, a = self.min_smith
224
- else
225
- s, a = build(-1, -1, -1, left_associative: left_associative).min_level
226
- end
227
- smith_min = s if smith_min.nil?
228
- armor_min = a if armor_min.nil?
229
- comp_min = min_comp(left_associative: left_associative) if comp_min.nil?
230
- comp_min = comp_search(para, target, smith_max, armor_max, comp_min, comp_max, left_associative: left_associative)
231
- smith_max, armor_max = sa_search(para, target, comp_min, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative)
232
- smith_min, armor_min = sa_search(para, target, comp_max, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative)
233
- raise Mgmg::SearchCutException if cut_exp < Mgmg.exp(smith_min, armor_min, comp_min)
234
- comp_max = comp_search(para, target, smith_min, armor_min, comp_min, comp_max, left_associative: left_associative)
235
- minex, ret = Mgmg.exp(smith_min, armor_min, comp_max), [smith_min, armor_min, comp_max]
236
- exp = Mgmg.exp(smith_max, armor_max, comp_min)
237
- minex, ret = exp, [smith_max, armor_max, comp_min] if exp < minex
238
- (comp_min+1).upto(comp_max-1) do |comp|
239
- break if minex < Mgmg.exp(smith_min, armor_min, comp)
240
- smith, armor = sa_search(para, target, comp, smith_min, armor_min, smith_max, armor_max, left_associative: left_associative, cut_exp: [minex, cut_exp].min)
196
+ def search(para, target, opt: Mgmg::Option.new)
197
+ opt = opt.dup.set_default(self)
198
+ opt.comp_min = comp_search(para, target, opt.smith_max, opt.armor_max, opt: opt)
199
+ opt.smith_max, opt.armor_max = sa_search(para, target, opt.comp_min, opt: opt)
200
+ opt.smith_min, opt.armor_min = sa_search(para, target, opt.comp_max, opt: opt)
201
+ raise Mgmg::SearchCutException if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_min)
202
+ opt.comp_max = comp_search(para, target, opt.smith_min, opt.armor_min, opt: opt)
203
+ ret = nil
204
+ exp = Mgmg.exp(opt.smith_min, opt.armor_min, opt.comp_max)
205
+ opt.cut_exp, ret = exp, [opt.smith_min, opt.armor_min,opt. comp_max] if exp < opt.cut_exp
206
+ exp = Mgmg.exp(opt.smith_max, opt.armor_max, opt.comp_min)
207
+ opt.cut_exp, ret = exp, [opt.smith_max, opt.armor_max, opt.comp_min] if exp < opt.cut_exp
208
+ (opt.comp_min+1).upto(opt.comp_max-1) do |comp|
209
+ break if opt.cut_exp < Mgmg.exp(opt.smith_min, opt.armor_min, comp)
210
+ smith, armor = sa_search(para, target, comp, opt: opt)
241
211
  exp = Mgmg.exp(smith, armor, comp)
242
- if exp < minex
243
- minex, ret = exp, [smith, armor, comp]
244
- elsif exp == minex
245
- if build(*ret).para_call(para) < build(smith, armor, comp).para_call(para)
212
+ if exp < opt.cut_exp
213
+ opt.cut_exp, ret = exp, [smith, armor, comp]
214
+ elsif exp == opt.cut_exp
215
+ if ret.nil? or opt.irep.para_call(para, *ret) < opt.irep.para_call(para, smith, armor, comp) then
246
216
  ret = [smith, armor, comp]
247
217
  end
248
218
  end
249
219
  rescue Mgmg::SearchCutException
250
220
  end
251
- raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{cut_exp}" if cut_exp < minex
221
+ raise Mgmg::SearchCutException, "the result exceeds given cut_exp=#{opt.cut_exp}" if ret.nil?
252
222
  ret
253
223
  end
254
224
  end
225
+
226
+ module Mgmg
227
+ module_function def find_lowerbound(a, b, para, start, term, opt_a: Option.new, opt_b: Option.new)
228
+ if term <= start
229
+ raise ArgumentError, "start < term is needed, (start, term) = (#{start}, #{term}) are given"
230
+ end
231
+ opt_a, opt_b = opt_a.dup.set_default(a), opt_b.dup.set_default(b)
232
+ sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
233
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
234
+ if eb < ea || ( ea == eb && opt_a.irep.para_call(para, *sca) < opt_b.irep.para_call(para, *scb) )
235
+ a, b, opt_a, opt_b, sca, scb, ea, eb = b, a, opt_b, opt_a, scb, sca, eb, ea
236
+ end
237
+ tag = opt_a.irep.para_call(para, *sca) + 1
238
+ sca, scb = a.search(para, term, opt: opt_a), b.search(para, term, opt: opt_b)
239
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
240
+ if ea < eb || ( ea == eb && opt_b.irep.para_call(para, *scb) < opt_a.irep.para_call(para, *sca) )
241
+ raise Mgmg::SearchCutException
242
+ end
243
+ while tag < term
244
+ sca, scb = a.search(para, tag, opt: opt_a), b.search(para, tag, opt: opt_b)
245
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
246
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
247
+ if eb < ea
248
+ return [tag-1, pb]
249
+ elsif ea == eb
250
+ if pa < pb
251
+ return [tag-1, pa]
252
+ else
253
+ tag = pb + 1
254
+ end
255
+ else
256
+ tag = pa + 1
257
+ end
258
+ end
259
+ raise UnexpectedError
260
+ end
261
+
262
+ module_function def find_upperbound(a, b, para, start, term, opt_a: Option.new, opt_b: Option.new)
263
+ if start <= term
264
+ raise ArgumentError, "term < start is needed, (start, term) = (#{start}, #{term}) are given"
265
+ end
266
+ opt_a, opt_b = opt_a.dup.set_default(a), opt_b.dup.set_default(b)
267
+ sca, scb = a.search(para, start, opt: opt_a), b.search(para, start, opt: opt_b)
268
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
269
+ if ea < eb || ( ea == eb && opt_b.irep.para_call(para, *scb) < opt_a.irep.para_call(para, *sca) )
270
+ a, b, opt_a, opt_b, sca, scb, ea, eb = b, a, opt_b, opt_a, scb, sca, eb, ea
271
+ end
272
+ tagu = opt_a.irep.para_call(para, *sca)
273
+ sca[-1] -= 2
274
+ tagl = opt_a.irep.para_call(para, *sca)
275
+ sca, scb = a.search(para, term, opt: opt_a), b.search(para, term, opt: opt_b)
276
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
277
+ if eb < ea || ( ea == eb && opt_a.irep.para_call(para, *sca) < opt_b.irep.para_call(para, *scb) )
278
+ raise Mgmg::SearchCutException
279
+ end
280
+ while term < tagu
281
+ ret = nil
282
+ sca = a.search(para, tagl, opt: opt_a)
283
+ next_tagu, next_sca = tagl, sca
284
+ scb = b.search(para, tagl, opt: opt_b)
285
+ while tagl < tagu
286
+ ea, eb = Mgmg.exp(*sca), Mgmg.exp(*scb)
287
+ pa, pb = opt_a.irep.para_call(para, *sca), opt_b.irep.para_call(para, *scb)
288
+ if ea < eb
289
+ ret = tagl
290
+ sca = a.search(para, pa + 1, opt: opt_a)
291
+ tagl = opt_a.irep.para_call(para, *sca)
292
+ scb = b.search(para, tagl, opt: opt_b)
293
+ elsif ea == eb
294
+ if pb < pa
295
+ ret = tagl
296
+ sca = a.search(para, pa + 1, opt: opt_a)
297
+ tagl = opt_a.irep.para_call(para, *sca)
298
+ scb = b.search(para, tagl, opt: opt_b)
299
+ else
300
+ scb = b.search(para, pb + 1, opt: opt_b)
301
+ tagl = opt_b.irep.para_call(para, *scb)
302
+ sca = a.search(para, tagl, opt: opt_a)
303
+ end
304
+ else
305
+ sca = a.search(para, pa + 1, opt: opt_a)
306
+ tagl = opt_a.irep.para_call(para, *sca)
307
+ scb = b.search(para, tagl, opt: opt_b)
308
+ end
309
+ end
310
+ if ret.nil?
311
+ tagu = next_tagu
312
+ next_sca[-1] -= 2
313
+ tagl = opt_a.irep.para_call(para, *next_sca)
314
+ if tagl == tagu
315
+ tagl = term
316
+ end
317
+ else
318
+ pa = opt_a.irep.para_call(para, *a.search(para, ret+1, opt: opt_a))
319
+ pb = opt_b.irep.para_call(para, *b.search(para, ret+1, opt: opt_b))
320
+ return [ret, [pa, pb].min]
321
+ end
322
+ end
323
+ raise UnexpectedError
324
+ end
325
+ end
@@ -323,4 +323,10 @@ module Mgmg
323
323
  SystemEquip.store(k.sub(/脛当て\Z/, 'すね当て'), SystemEquip[k])
324
324
  end
325
325
  end
326
+ SystemEquip.freeze
327
+ SystemEquipRegexp = Hash.new
328
+ SystemEquip.keys.each do |k|
329
+ SystemEquipRegexp.store(k.freeze, Regexp.compile(k))
330
+ end
331
+ SystemEquipRegexp.freeze
326
332
  end
data/lib/mgmg/utils.rb CHANGED
@@ -14,6 +14,31 @@ module Mgmg
14
14
  end
15
15
  end
16
16
  end
17
+ refine Float do
18
+ alias :cdiv :quo # Floatの場合は普通の割り算
19
+ def comma3
20
+ s = self.to_s
21
+ case s
22
+ when %r|e|
23
+ s
24
+ when %r|\.|
25
+ ary = s.split('.')
26
+ ary[0].gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,') + '.' + ary[1]
27
+ else
28
+ s
29
+ end
30
+ end
31
+ end
32
+ refine Rational do
33
+ alias :cdiv :quo # Rationalの場合は普通の割り算
34
+ def comma3
35
+ if self.denominator == 1
36
+ self.numerator.comma3
37
+ else
38
+ self.to_f.comma3
39
+ end
40
+ end
41
+ end
17
42
  end
18
43
  using Refiner
19
44
 
@@ -46,7 +71,19 @@ module Mgmg
46
71
  end
47
72
  attr_accessor :equip
48
73
  end
74
+ class InvalidReinforcementNameError < StandardError
75
+ def initialize(str)
76
+ @name = str
77
+ super("Unknown skill or preset cuisine name `#{@name}' is given.")
78
+ end
79
+ attr_accessor :name
80
+ end
49
81
  class SearchCutException < StandardError; end
82
+ class UnexpectedError < StandardError
83
+ def initialize()
84
+ super("There is a bug in `mgmg' gem. Please report to https://github.com/cycloawaodorin/mgmg/issues .")
85
+ end
86
+ end
50
87
 
51
88
  module_function def exp(smith, armor, comp=armor.tap{armor=0})
52
89
  if armor <= 0
@@ -86,7 +123,7 @@ module Mgmg
86
123
  Math.sqrt(exp - ((sa-1)**2) - (2*((comp-1)**2)) - 4).round + 1
87
124
  end
88
125
 
89
- CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/
126
+ CharacterList = /[^\(\)\+0123456789\[\]あきくしすたてなねのびりるイウガクグサジスタダチツデトドニノフブペボムラリルロンヴー一万二光兜典刀剣劣匠双古名吹咆品哮地大天太子安宝小帽弓弩当息悪戦手指斧書服木本杖業樹歴殺水氷法火炎牙物玉王産用界異的皮盾短石砕竜紫綿耳聖脛腕腿般良色衣袋覇質軍軽輝輪重量金鉄鎧闇陽靴額飾首骨鬼龍]/.freeze
90
127
  module_function def check_string(str)
91
128
  str = str.gsub(/[\s \\]/, '')
92
129
  if m = CharacterList.match(str)
@@ -130,6 +167,15 @@ module Mgmg
130
167
  str
131
168
  end
132
169
 
170
+ module_function def parse_material(str)
171
+ m = /\A.+?(\d+)\Z/.match(str)
172
+ mat = MaterialIndex[str.to_sym]
173
+ if m.nil? || mat.nil?
174
+ raise InvalidMaterialError.new(str)
175
+ end
176
+ [mat, m[1].to_i, mat<90 ? mat.div(10) : 9]
177
+ end
178
+
133
179
  class Vec < Array
134
180
  def add!(other)
135
181
  case other
data/lib/mgmg/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mgmg
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end