numeron 1.0.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in numeron.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'tapp', :git => 'git://github.com/esminc/tapp.git'
8
+ gem 'guard'
9
+ gem 'guard-rspec'
10
+ gem 'fuubar'
11
+ gem 'libnotify', :require => false
12
+ gem 'rb-inotify', :require => false
13
+ gem 'rb-fsevent', :require => false
14
+ gem 'growl', :require => false
15
+ end
@@ -0,0 +1,5 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 kengos
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,109 @@
1
+ # Numeron
2
+
3
+ ヌメロンの解の探索プログラム (Ruby版)
4
+
5
+ Androidアプリ ... https://play.google.com/store/apps/details?id=com.jpn.gemstone.numer0n.android
6
+
7
+ iPhoneアプリ ... https://itunes.apple.com/jp/app/numer0n-numeron/id512484171?mt=8
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'numeron'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install numeron
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ irb
27
+ ```
28
+
29
+ ```
30
+ > require 'numeron'
31
+ true
32
+ > Numeron::Solver.new.run
33
+ Attack number: 123 # <= callした数値を入力
34
+ Eat number: 0 # <= callした結果 eatの数を入力
35
+ Bite number: 0 # <= callした結果 biteの数を入力
36
+ ... thinking
37
+ possibilities: 210 # <= 計算した結果、答えとして可能性がある数値の個数
38
+ Analyzer Answer: 372 # <= Analyzerがおすすめの答えとして選んだ数
39
+ Possibilitiy list random: 798 # <= 答えの可能性の一覧からランダムで選んだ数
40
+
41
+ finish? [yes|no] # <= yes or yで終了, noで続行
42
+ ```
43
+
44
+ ## Numeron::Calculator
45
+
46
+ ヌメロンの解の可能性として考えられるものを計算する部分。
47
+
48
+
49
+ 基本
50
+
51
+ ```ruby
52
+ calc = Numeron::Calculator.new
53
+ calc.input('123', 0, 1) # callした番号, Eatの数, Biteの数
54
+ p calc.possibilities # 答えの可能性の一覧がでてくる
55
+
56
+ # 続いて以下のように245をcallして 2Eat, 0Biteだった場合 11個に絞りこまれる
57
+ calc.input('245', 2, 0)
58
+ p calc.possibilities
59
+ # => ["240", "246", "247", "248", "249", "205", "265", "275", "285", "295", "345"]
60
+ ```
61
+
62
+ Shuffle対応(ほとんどテストはしていない)
63
+
64
+ ```ruby
65
+ calc = Numeron::Calculator.new
66
+ calc.input('123', 0, 3)
67
+ calc.shuffle # シャッフルされた
68
+ p calc.possibilities.size
69
+ # => 6
70
+
71
+ calc = Numeron::Calculator.new
72
+ calc.input('123', 1, 1)
73
+ p calc.possibilities.size
74
+ # => 42
75
+ calc.shuffle
76
+ p calc.possibilities.size
77
+ # => 126
78
+ ```
79
+
80
+ 以下の2つの変数を用いている
81
+
82
+ `@mays`
83
+
84
+ @mays[0]が左側の数値の可能性リスト(初期値0-9)<br>
85
+ @mays[1]が真ん中の数値の可能性リスト(初期値0-9)<br>
86
+ @mays[2]が右側の数値の可能性リスト(初期値0-9)<br>
87
+
88
+ `@possibilities`
89
+
90
+ 解の可能性リスト
91
+
92
+ ## Numeron::Analyzer
93
+
94
+ 案がなかったので、以下3つの分析方法を適当に実装。<br>
95
+ 計算量はまったく考慮していない
96
+
97
+ 0e1bを最悪ケースとして、このケースが出た場合に、最も可能性リストが少なくなる数値を計算する機能
98
+
99
+ 0e1b, 1e0bを最悪ケースとして、これらのケースが出た場合に、最も可能性リストの平均値が少なくなる数値を計算する機能
100
+
101
+ 可能性リスト中から、最も可能性リストが少なくなる数値を計算する機能
102
+
103
+ ## Contributing
104
+
105
+ 1. Fork it
106
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
107
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
108
+ 4. Push to the branch (`git push origin my-new-feature`)
109
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ require 'numeron/version'
4
+ require 'numeron/calculator'
5
+ require 'numeron/solver'
6
+ require 'numeron/analyzer'
7
+
8
+ module Numeron
9
+ end
@@ -0,0 +1,140 @@
1
+ # coding: utf-8
2
+
3
+ module Numeron
4
+ class Analyzer
5
+ attr_accessor :calculator
6
+ def initialize(calculator)
7
+ @calculator = calculator
8
+ end
9
+
10
+ # 次の1手の計算
11
+ # @param [Symbol] mode :average or :worst
12
+ # @return [Hash] {recommend: [Array], size: Number}
13
+ def run(mode = :average, options = {})
14
+ case mode
15
+ when :average
16
+ run_average_mode(options[:cases])
17
+ when :worst
18
+ run_worstcase_mode(options[:worst_case])
19
+ when :possibilities
20
+ run_possibilities
21
+ end
22
+ end
23
+
24
+ # 最悪のケースを0e1b, 1e0bと想定し、それぞれの結果が出た際に可能性の平均値が最も少なくなるケースを推定する
25
+ def run_average_mode(cases = nil)
26
+ cases ||= [
27
+ {eat: 0, bite: 1},
28
+ {eat: 1, bite: 0}
29
+ ]
30
+ recommend = []
31
+ min_size = 10000
32
+ all_list.each do |f|
33
+ average = calc_average(f, cases)
34
+ if min_size == average
35
+ recommend << f
36
+ elsif min_size > average
37
+ recommend = [f]
38
+ min_size = average
39
+ end
40
+ end
41
+
42
+ { recommend: recommend, size: min_size }
43
+ end
44
+
45
+ # 最悪のケースを0e1bと推定し、その結果として最も可能性の数が最も少なくなるケースを推定する
46
+ def run_worstcase_mode(worst_case = {})
47
+ worst_case = {eat: 0, bite: 1}.merge(worst_case)
48
+ min_size = 10000
49
+ recommend = []
50
+ all_list.each do |f|
51
+ _calculator = build_calculator
52
+ _calculator.input(f, worst_case[:eat], worst_case[:bite])
53
+ if min_size == _calculator.possibilities.size
54
+ recommend << f
55
+ elsif min_size > _calculator.possibilities.size
56
+ recommend = [f]
57
+ min_size = _calculator.possibilities.size
58
+ end
59
+ end
60
+
61
+ { recommend: recommend, size: min_size }
62
+ end
63
+
64
+ def run_possibilities
65
+ possibilities = @calculator.possibilities.clone
66
+
67
+ recommend = []
68
+ min_size = 10000
69
+ cases = [
70
+ {eat: 0, bite: 0},
71
+ {eat: 0, bite: 1},
72
+ {eat: 0, bite: 2},
73
+ {eat: 1, bite: 0},
74
+ {eat: 1, bite: 1},
75
+ {eat: 2, bite: 0}
76
+ ]
77
+ possibilities.each do |f|
78
+ average = calc_average(f, cases, true)
79
+ if min_size == average
80
+ recommend << f
81
+ elsif min_size > average
82
+ recommend = [f]
83
+ min_size = average
84
+ end
85
+ end
86
+
87
+ { recommend: recommend, size: min_size }
88
+ end
89
+
90
+ # attackの結果、推定される結果に対する可能性の数の平均を計算する
91
+ # @example
92
+ # [10, 20, 10, 0, 5, 0, 5]の場合は ( 10 + 20 + 10 + 5 + 5 ) / 5 = 10
93
+ def calc_average(attack, cases, can_zero = false)
94
+ result = []
95
+ cases.each do |pattern|
96
+ _calculator = build_calculator
97
+ _calculator.input(attack, pattern[:eat], pattern[:bite])
98
+ result << _calculator.possibilities.size
99
+ end
100
+
101
+ n = 0
102
+ sum = 0
103
+ result.each do |f|
104
+ sum = sum + f
105
+ n = n + 1 if f > 0
106
+ end
107
+
108
+ if n > 0
109
+ return sum.to_f / n.to_f
110
+ elsif can_zero
111
+ return 0
112
+ else
113
+ return 10000
114
+ end
115
+ end
116
+
117
+ def build_calculator
118
+ _calculator = Numeron::Calculator.new
119
+ _calculator.possibilities = @calculator.possibilities.clone
120
+ _calculator.mays = @calculator.mays.clone
121
+ _calculator.histories = @calculator.histories.clone
122
+ return _calculator
123
+ end
124
+
125
+ def all_list
126
+ [].tap do |f|
127
+ (0..9).to_a.each { |i|
128
+ (0..9).to_a.each { |j|
129
+ next if i == j
130
+ (0..9).to_a.each { |k|
131
+ next if i == k || j == k
132
+ f << i.to_s + j.to_s + k.to_s
133
+ }
134
+ }
135
+ }
136
+ end
137
+ end
138
+
139
+ end
140
+ end
@@ -0,0 +1,320 @@
1
+ # coding: utf-8
2
+
3
+ module Numeron
4
+ class Calculator
5
+ attr_accessor :histories, :possibilities, :mays
6
+
7
+ def initialize(card_size = 3)
8
+ @histories = []
9
+ @mays = [(0..9).to_a, (0..9).to_a, (0..9).to_a]
10
+ @possibilities = nil
11
+ end
12
+
13
+ def input(attack, eat, bite)
14
+ attack = attack.split(//).map(&:to_i)
15
+ eat = eat.to_i
16
+ bite = bite.to_i
17
+ @histories << {attack: attack, eat: eat, bite: bite}
18
+
19
+ if eat == 0 && bite == 0
20
+ zero_eat_zero_bite(attack)
21
+ elsif eat == 0 && bite == 3
22
+ zero_eat_three_bite(attack)
23
+ elsif eat == 0 && bite == 2
24
+ zero_eat_two_bite(attack)
25
+ elsif eat == 0 && bite == 1
26
+ zero_eat_one_bite(attack)
27
+ elsif eat == 1 && bite == 2
28
+ one_eat_two_bite(attack)
29
+ elsif eat == 1 && bite == 1
30
+ one_eat_one_bite(attack)
31
+ elsif eat == 1 && bite == 0
32
+ one_eat_zero_bite(attack)
33
+ elsif eat == 2 && bite == 0
34
+ two_eat_zero_bite(attack)
35
+ else
36
+ return false
37
+ end
38
+ return true
39
+ end
40
+
41
+ def zero_eat_zero_bite(attack)
42
+ @mays[0] = @mays[0] - attack
43
+ @mays[1] = @mays[1] - attack
44
+ @mays[2] = @mays[2] - attack
45
+
46
+ list = []
47
+ @mays[0].each do |i|
48
+ @mays[1].each do |j|
49
+ next if i == j
50
+ @mays[2].each do |k|
51
+ next if i == k || j == k
52
+ list << validation(i, j, k)
53
+ end
54
+ end
55
+ end
56
+ update_possibilities(list)
57
+ end
58
+
59
+ def zero_eat_one_bite(attack)
60
+ # 各桁のeatの可能性がなくなる
61
+ @mays[0] = @mays[0] - [attack[0]]
62
+ @mays[1] = @mays[1] - [attack[1]]
63
+ @mays[2] = @mays[2] - [attack[2]]
64
+
65
+ list = []
66
+ (@mays[0] - attack).each do |i|
67
+ (@mays[1] - attack).each do |j|
68
+ next if i == j
69
+ list << validation(i, j, attack[0]) if attack[0] != i || attack[0] != j
70
+ list << validation(i, j, attack[1]) if attack[1] != i || attack[1] != j
71
+ end
72
+ end
73
+
74
+ (@mays[0] - attack).each do |i|
75
+ (@mays[2] - attack).each do |k|
76
+ next if i == k
77
+ list << validation(i, attack[0], k) if attack[0] != i || attack[0] != j
78
+ list << validation(i, attack[2], k) if attack[1] != i || attack[1] != j
79
+ end
80
+ end
81
+
82
+ (@mays[1] - attack).each do |j|
83
+ (@mays[2] - attack).each do |k|
84
+ next if j == k
85
+ list << validation(attack[1], j, k) if attack[1] != j || attack[1] != k
86
+ list << validation(attack[2], j, k) if attack[2] != j || attack[2] != k
87
+ end
88
+ end
89
+ update_possibilities(list)
90
+ end
91
+
92
+ def zero_eat_two_bite(attack)
93
+ @mays[0] = @mays[0] - [attack[0]]
94
+ @mays[1] = @mays[1] - [attack[1]]
95
+ @mays[2] = @mays[2] - [attack[2]]
96
+ list = []
97
+
98
+ # 先頭不明
99
+ (@mays[0] - attack).each do |f|
100
+ list << validation(f, attack[0], attack[1])
101
+ list << validation(f, attack[2], attack[0])
102
+ list << validation(f, attack[2], attack[1])
103
+ end
104
+
105
+ # 中央不明
106
+ (@mays[1] - attack).each do |f|
107
+ list << validation(attack[1], f, attack[0])
108
+ list << validation(attack[2], f, attack[0])
109
+ list << validation(attack[2], f, attack[1])
110
+ end
111
+
112
+ # 末尾不明
113
+ (@mays[2] - attack).each do |f|
114
+ list << validation(attack[1], attack[0], f)
115
+ list << validation(attack[1], attack[2], f)
116
+ list << validation(attack[2], attack[0], f)
117
+ end
118
+ update_possibilities(list)
119
+ end
120
+
121
+ def zero_eat_three_bite(attack)
122
+ # 各桁の可能性が2つに絞られる
123
+ @mays[0] = @mays[0] & [attack[1], attack[2]]
124
+ @mays[1] = @mays[1] & [attack[0], attack[2]]
125
+ @mays[2] = @mays[2] & [attack[0], attack[1]]
126
+ list = [
127
+ validation(attack[1], attack[2], attack[0]),
128
+ validation(attack[2], attack[0], attack[1])
129
+ ].compact
130
+ update_possibilities(list)
131
+ end
132
+
133
+ def one_eat_zero_bite(attack)
134
+ list = []
135
+ # 先頭eat
136
+ (@mays[1] - attack).each do |j|
137
+ (@mays[2] - attack).each do |k|
138
+ next if j == k
139
+ list << validation(attack[0], j, k)
140
+ end
141
+ end
142
+
143
+ # 真ん中eat
144
+ (@mays[0] - attack).each do |i|
145
+ (@mays[2] - attack).each do |k|
146
+ next if i == k
147
+ list << validation(i, attack[1], k)
148
+ end
149
+ end
150
+
151
+ # 末尾eat
152
+ (@mays[0] - attack).each do |i|
153
+ (@mays[1] - attack).each do |j|
154
+ next if i == j
155
+ list << validation(i, j, attack[2])
156
+ end
157
+ end
158
+ update_possibilities(list)
159
+ end
160
+
161
+ def one_eat_one_bite(attack)
162
+ list = []
163
+ (@mays[2] - attack).each do |f|
164
+ list << validation(attack[0], attack[2], f)
165
+ end
166
+ (@mays[1] - attack).each do |f|
167
+ list << validation(attack[0], f, attack[1])
168
+ end
169
+ # 2桁目があっている
170
+ (@mays[2] - attack).each do |f|
171
+ list << validation(attack[2], attack[1], f)
172
+ end
173
+ (@mays[0] - attack).each do |f|
174
+ list << validation(f, attack[1], attack[0])
175
+ end
176
+ # 3桁目があっている
177
+ (@mays[0] - attack).each do |f|
178
+ list << validation(f, attack[0], attack[2])
179
+ end
180
+ (@mays[1] - attack).each do |f|
181
+ list << validation(attack[1], f, attack[2])
182
+ end
183
+ update_possibilities(list)
184
+ end
185
+
186
+ def one_eat_two_bite(attack)
187
+ # attack以外の可能性がなくなるので、積
188
+ @mays[0] = @mays[0] & attack
189
+ @mays[1] = @mays[1] & attack
190
+ @mays[2] = @mays[2] & attack
191
+ list = [
192
+ validation(attack[0], attack[2], attack[1]),
193
+ validation(attack[2], attack[1], attack[0]),
194
+ validation(attack[1], attack[0], attack[2])
195
+ ].compact
196
+ update_possibilities(list)
197
+ end
198
+
199
+ def two_eat_zero_bite(attack)
200
+ # 先頭2つがeat
201
+ list = []
202
+ (@mays[2] - attack).each do |k|
203
+ list << validation(attack[0], attack[1], k)
204
+ end
205
+ # 先頭、末尾がeat
206
+ (@mays[1] - attack).each do |j|
207
+ list << validation(attack[0], j, attack[2])
208
+ end
209
+ # 真ん中、末尾がeat
210
+ (@mays[0] - attack).each do |i|
211
+ list << validation(i ,attack[1], attack[2])
212
+ end
213
+ update_possibilities(list)
214
+ end
215
+
216
+ def validation(i, j, k)
217
+ return nil if i == j || i == k || j == k
218
+ if @mays[0].include?(i) && @mays[1].include?(j) && @mays[2].include?(k)
219
+ return i.to_s + j.to_s + k.to_s
220
+ else
221
+ return nil
222
+ end
223
+ end
224
+
225
+ # シャッフル
226
+ def shuffle
227
+ @mays[0] = @mays[0] | @mays[1] | @mays[2]
228
+ @mays[1] = @mays[0] | @mays[1] | @mays[2]
229
+ @mays[2] = @mays[0] | @mays[1] | @mays[2]
230
+ list = []
231
+ @mays[0].each do |i|
232
+ @mays[1].each do |j|
233
+ next if i == j
234
+ @mays[2].each do |k|
235
+ next if i == k || j == k
236
+ list << validation(i, j, k)
237
+ end
238
+ end
239
+ end
240
+ @possibilities = list.compact
241
+ @histories.each do |history|
242
+ eat_and_bite = history[:eat] + history[:bite]
243
+ if eat_and_bite == 1
244
+ one_eat_or_one_bite(history[:attack])
245
+ elsif eat_and_bite == 2
246
+ two_eat_or_two_bite(history[:attack])
247
+ end
248
+ end
249
+ end
250
+
251
+ def one_eat_or_one_bite(attack)
252
+ list = []
253
+ # attack[0] - attack[3]が一桁目に含まれている
254
+ (@mays[1] - attack).each do |j|
255
+ (@mays[2] - attack).each do |k|
256
+ next if j == k
257
+ list << validation(attack[0], j, k)
258
+ list << validation(attack[1], j, k)
259
+ list << validation(attack[2], j, k)
260
+ end
261
+ end
262
+ (@mays[0] - attack).each do |i|
263
+ # attack[0..3]が2桁目に含まれている
264
+ (@mays[2] - attack).each do |k|
265
+ next if i == k
266
+ list << validation(i, attack[0], k)
267
+ list << validation(i, attack[1], k)
268
+ list << validation(i, attack[2], k)
269
+ end
270
+ # attack[0..3]が3桁目に含まれている
271
+ (@mays[1] - attack).each do |j|
272
+ next if i == j
273
+ list << validation(i, j, attack[0])
274
+ list << validation(i, j, attack[1])
275
+ list << validation(i, j, attack[2])
276
+ end
277
+ end
278
+ update_possibilities(list)
279
+ end
280
+
281
+ def two_eat_or_two_bite(attack)
282
+ list = []
283
+ # 末尾が不明
284
+ (@mays[2] - attack).each do |k|
285
+ list << validation(attack[0], attack[1], k)
286
+ list << validation(attack[0], attack[2], k)
287
+ list << validation(attack[1], attack[0], k)
288
+ list << validation(attack[1], attack[2], k)
289
+ list << validation(attack[2], attack[0], k)
290
+ list << validation(attack[2], attack[1], k)
291
+ end
292
+
293
+ # 真ん中が不明
294
+ (@mays[1] - attack).each do |j|
295
+ list << validation(attack[0], j, attack[1])
296
+ list << validation(attack[0], j, attack[2])
297
+ list << validation(attack[1], j, attack[0])
298
+ list << validation(attack[1], j, attack[2])
299
+ list << validation(attack[2], j, attack[0])
300
+ list << validation(attack[2], j, attack[1])
301
+ end
302
+
303
+ # 先頭が不明
304
+ (@mays[0] - attack).each do |i|
305
+ list << validation(i, attack[0], attack[1])
306
+ list << validation(i, attack[0], attack[2])
307
+ list << validation(i, attack[1], attack[0])
308
+ list << validation(i, attack[1], attack[2])
309
+ list << validation(i, attack[2], attack[0])
310
+ list << validation(i, attack[2], attack[1])
311
+ end
312
+ update_possibilities(list)
313
+ end
314
+
315
+ def update_possibilities(possibilities)
316
+ possibilities.compact!
317
+ @possibilities = @possibilities.nil? ? possibilities : possibilities & @possibilities
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,88 @@
1
+ # coding: utf-8
2
+
3
+ module Numeron
4
+ class Solver
5
+ attr_accessor :calc, :card_size
6
+ def initialize
7
+ @calc = Numeron::Calculator.new
8
+ @card_size = 3
9
+ end
10
+
11
+ def run
12
+ while 1
13
+ next unless question
14
+ think
15
+ finish
16
+ end
17
+ end
18
+
19
+ def question
20
+ attack_number = nil
21
+ eat = 0
22
+ bite = 0
23
+ while 1
24
+ print "Attack number: "
25
+ attack_number = STDIN.gets.chomp
26
+ if @card_size == attack_number.split(//).size
27
+ break
28
+ else
29
+ puts 'Required ' + @card_size.to_s + ' digits.'
30
+ end
31
+ end
32
+
33
+ while 1
34
+ while 1
35
+ print "Eat number: "
36
+ eat = STDIN.gets.chomp.to_i
37
+ if @card_size > eat
38
+ break
39
+ else
40
+ puts 'Required less than ' + @card_size.to_s + ' digits.'
41
+ end
42
+ end
43
+
44
+ while 1
45
+ print "Bite number: "
46
+ bite = STDIN.gets.chomp.to_i
47
+ if @card_size >= bite
48
+ break
49
+ else
50
+ print 'Required ' + @card_size.to_s + ' digits or less'
51
+ end
52
+ end
53
+ if eat + bite <= @card_size
54
+ break
55
+ else
56
+ puts "Error, Eat + Bite > " + @card_size.to_s
57
+ end
58
+ end
59
+
60
+ @calc.input(attack_number, eat, bite)
61
+ end
62
+
63
+ def think
64
+ puts "... thinking"
65
+ puts "possibilities: " + @calc.possibilities.size.to_s
66
+ analyzer = Numeron::Analyzer.new(@calc)
67
+ result = @calc.possibilities.size <= 64 ? analyzer.run(:possibilities) : analyzer.run(:average)
68
+ if result[:recommend].size > 0
69
+ puts "Analyzer Answer: " + result[:recommend].sample.to_s
70
+ else
71
+ puts "Calculator Error."
72
+ end
73
+ puts "Possibilitiy list random: " + @calc.possibilities.sample.to_s
74
+ end
75
+
76
+ def finish
77
+ while 1
78
+ print "\nfinish? [yes|no] "
79
+ f = STDIN.gets.chomp
80
+ if(f == 'yes' || f == 'y')
81
+ exit
82
+ elsif f == 'no' || f == 'n'
83
+ break
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,3 @@
1
+ module Numeron
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'numeron/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "numeron"
8
+ gem.version = Numeron::VERSION
9
+ gem.authors = ["kengos"]
10
+ gem.email = ["kengo@kengos.jp"]
11
+ gem.description = %q{numer0nの解を計算します。}
12
+ gem.summary = %q{numer0n solver}
13
+ gem.homepage = "https://github.com/kengos/numeron"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Numeron::Analyzer do
6
+ let(:analyzer) { Numeron::Analyzer.new(calc) }
7
+ describe '#run_average_mode' do
8
+ context '0e1b' do
9
+ let(:calc) { Numeron::Calculator.new.tap{|f| f.input('123', 0, 1) } }
10
+ it do
11
+ result = analyzer.run_average_mode
12
+ result[:recommend].should have(378).items
13
+ result[:size].should == 60.0
14
+ end
15
+ end
16
+ end
17
+
18
+ describe '#run_worstcase_mode' do
19
+ let(:calc) { Numeron::Calculator.new.tap{|f| f.input('123', 0, 1) } }
20
+ it do
21
+ result = analyzer.run_worstcase_mode
22
+ result[:recommend].should have(21).items
23
+ result[:size].should == 72
24
+ end
25
+ end
26
+
27
+ describe '#run_possibilities' do
28
+ let(:calc) { Numeron::Calculator.new.tap{|f| f.input('123', 0, 3) } }
29
+ it do
30
+ result = analyzer.run_possibilities
31
+ result[:recommend].should =~ %w(312 231)
32
+ result[:size].should == 0
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,136 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Numeron::Calculator do
6
+ let(:calc) { Numeron::Calculator.new }
7
+ describe '#input' do
8
+ it "0e0b" do
9
+ calc.input('123', 0, 0)
10
+ calc.possibilities.should have(7 * 6 * 5).items
11
+ end
12
+
13
+ it "0e1b" do
14
+ calc.input('123', 0, 1)
15
+ calc.possibilities.should have(252).items
16
+ end
17
+
18
+ it "0e2b" do
19
+ calc.input('123', 0, 2)
20
+ calc.possibilities.should have(63).items
21
+ calc.input('231', 0, 2)
22
+ calc.possibilities.should have(21).items
23
+ end
24
+
25
+ it "0e3b" do
26
+ calc.input('123', 0, 3)
27
+ calc.possibilities.should =~ %w(231 312)
28
+ calc.input('231', 0, 3)
29
+ calc.possibilities.should =~ %w(312)
30
+ end
31
+
32
+ it "1e0b" do
33
+ calc.input('123', 1, 0)
34
+ calc.possibilities.should have(126).items
35
+ end
36
+
37
+ it "1e1b" do
38
+ calc.input('123', 1, 1)
39
+ calc.possibilities.should have(42).items
40
+ end
41
+
42
+ it "1e2b" do
43
+ calc.input('123', 1, 2)
44
+ calc.possibilities.should =~ %w(132 321 213)
45
+ end
46
+
47
+ it "2e0b" do
48
+ calc.input('123', 2, 0)
49
+ calc.possibilities.should have(21).items
50
+ end
51
+ end
52
+
53
+ describe "#shuffle" do
54
+ it "0e3b" do
55
+ calc.input('123', 0, 3)
56
+ calc.shuffle
57
+ calc.possibilities.should =~ %w(123 132 213 231 312 321)
58
+ end
59
+
60
+ it "2e0b" do
61
+ calc.input('123', 2, 0)
62
+ calc.shuffle
63
+ # 12?, 13?, 21?, 23?, 31?, 32? が3パターン, ? = [0, 4, 5, 6, 7, 8, 9]
64
+ # => 6 * 3 * 7= 126
65
+ calc.possibilities.should have(126).items
66
+ end
67
+
68
+ it "1e1b" do
69
+ calc.input('123', 1, 1)
70
+ calc.shuffle
71
+ calc.possibilities.should have(126).items
72
+ end
73
+
74
+ it "1e0b" do
75
+ calc.input('123', 1, 0)
76
+ calc.shuffle
77
+ calc.possibilities.should have(378).items
78
+ end
79
+ end
80
+
81
+ describe "scenario" do
82
+ it "1e0b, 1e2b" do
83
+ calc.input('348', 1, 0)
84
+ calc.input('123', 1, 2)
85
+ calc.possibilities.should == ['321']
86
+ end
87
+
88
+ it "0e1b, 0e1b 0e0b 1e0b 1e2b" do
89
+ calc.input('123', 0, 1)
90
+ calc.input('210', 0, 1)
91
+ calc.input('340', 0, 0)
92
+ calc.input('562', 1, 0)
93
+ calc.input('892', 1, 2)
94
+ calc.possibilities.should == %w(982)
95
+ end
96
+
97
+ it "3eat is 571" do
98
+ calc.input('123', 0, 1)
99
+ calc.input('245', 0, 1)
100
+ calc.input('367', 0, 1)
101
+ calc.input('890', 0, 0)
102
+ calc.input('416', 0, 1)
103
+ calc.possibilities.should =~ ['571', '751']
104
+ end
105
+
106
+ it "0e1b, 0e1b" do
107
+ calc.input('123', 0, 1)
108
+ calc.input('245', 0, 1)
109
+ calc.possibilities.should have(75).items
110
+ end
111
+
112
+ it "0e1b, 0e1b 2" do
113
+ calc.input('123', 0, 1)
114
+ calc.input('235', 0, 1)
115
+ calc.possibilities.should have(78).items
116
+ end
117
+
118
+ it "0e1b, 0e1b 3" do
119
+ calc.input('123', 0, 1)
120
+ calc.input('145', 0, 1)
121
+ calc.possibilities.should have(90).items
122
+ end
123
+
124
+ it "0e1b, 0e1b 4" do
125
+ calc.input('123', 0, 1)
126
+ calc.input('456', 0, 1)
127
+ calc.possibilities.should have(96).items
128
+ end
129
+
130
+ it "0e1b, 2e0b" do
131
+ calc.input('123', 0, 1)
132
+ calc.input('245', 2, 0)
133
+ calc.possibilities.should have(11).items
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Numeron do
6
+ end
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'tapp'
3
+ rescue Exception
4
+ end
5
+
6
+ require 'rspec'
7
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/numeron')
8
+
9
+ RSpec.configure do |config|
10
+ config.mock_with :rspec
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.filter_run focus: true
13
+ config.run_all_when_everything_filtered = true
14
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: numeron
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - kengos
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: numer0nの解を計算します。
15
+ email:
16
+ - kengo@kengos.jp
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - Guardfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - lib/numeron.rb
28
+ - lib/numeron/analyzer.rb
29
+ - lib/numeron/calculator.rb
30
+ - lib/numeron/solver.rb
31
+ - lib/numeron/version.rb
32
+ - numeron.gemspec
33
+ - spec/lib/numeron/analyzer_spec.rb
34
+ - spec/lib/numeron/calculator_spec.rb
35
+ - spec/lib/numeron_spec.rb
36
+ - spec/spec_helper.rb
37
+ homepage: https://github.com/kengos/numeron
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.24
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: numer0n solver
61
+ test_files:
62
+ - spec/lib/numeron/analyzer_spec.rb
63
+ - spec/lib/numeron/calculator_spec.rb
64
+ - spec/lib/numeron_spec.rb
65
+ - spec/spec_helper.rb
66
+ has_rdoc: