numeron 1.0.0 → 1.1.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/README.md +34 -16
- data/examples/simulator_example.rb +58 -0
- data/lib/numeron.rb +1 -0
- data/lib/numeron/analyzer.rb +2 -4
- data/lib/numeron/simulator.rb +93 -0
- data/lib/numeron/solver.rb +24 -7
- data/lib/numeron/version.rb +1 -1
- data/numeron.gemspec +1 -1
- data/spec/lib/numeron/simulator_spec.rb +92 -0
- metadata +6 -2
data/README.md
CHANGED
@@ -1,32 +1,27 @@
|
|
1
1
|
# Numeron
|
2
2
|
|
3
|
-
ヌメロンの解の探索プログラム (Ruby
|
3
|
+
ヌメロンの解の探索プログラム (Ruby版, 3桁Only)
|
4
|
+
|
5
|
+
1. 解として可能性のある数値を自動計算
|
6
|
+
2. Shuffle可能
|
7
|
+
3. 次に出すべき1手を計算してくれるAnalyzer
|
8
|
+
4. シミュレーター付き(要実装)
|
4
9
|
|
5
10
|
Androidアプリ ... https://play.google.com/store/apps/details?id=com.jpn.gemstone.numer0n.android
|
6
11
|
|
7
12
|
iPhoneアプリ ... https://itunes.apple.com/jp/app/numer0n-numeron/id512484171?mt=8
|
8
13
|
|
9
|
-
##
|
10
|
-
|
11
|
-
Add this line to your application's Gemfile:
|
12
|
-
|
13
|
-
gem 'numeron'
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle
|
14
|
+
## インストール
|
18
15
|
|
19
|
-
|
16
|
+
ruby 1.9以上が必要です
|
20
17
|
|
21
18
|
$ gem install numeron
|
22
19
|
|
23
|
-
##
|
20
|
+
## Solverの使い方
|
24
21
|
|
25
|
-
|
26
|
-
irb
|
27
|
-
```
|
22
|
+
irbで実行します
|
28
23
|
|
29
|
-
```
|
24
|
+
```ruby
|
30
25
|
> require 'numeron'
|
31
26
|
true
|
32
27
|
> Numeron::Solver.new.run
|
@@ -41,6 +36,29 @@ Possibilitiy list random: 798 # <= 答えの可能性の一覧からランダム
|
|
41
36
|
finish? [yes|no] # <= yes or yで終了, noで続行
|
42
37
|
```
|
43
38
|
|
39
|
+
## Simulatorの使い方
|
40
|
+
|
41
|
+
コンピューターが何手で解にたどり着くかのシミュレーションをすることができます。
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
require 'numeron'
|
45
|
+
|
46
|
+
simulator = Numeron::Simulator.new
|
47
|
+
# 最初にコールする番号
|
48
|
+
first_attack = '123'
|
49
|
+
# シミュレーションする答えのリスト
|
50
|
+
answers = ['403', '256']
|
51
|
+
|
52
|
+
result = simulator.run(answers, first_attack) do |calculator|
|
53
|
+
# ここにシミュレーションしたいコードを書く
|
54
|
+
# calculatorはNumeron::Calculatorオブジェクト
|
55
|
+
end
|
56
|
+
|
57
|
+
p result
|
58
|
+
```
|
59
|
+
|
60
|
+
詳細は https://github.com/kengos/numeron/blob/master/examples/simulator_example.rb を参照
|
61
|
+
|
44
62
|
## Numeron::Calculator
|
45
63
|
|
46
64
|
ヌメロンの解の可能性として考えられるものを計算する部分。
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require 'numeron'
|
5
|
+
|
6
|
+
simulator = Numeron::Simulator.new
|
7
|
+
# 結果を標準出力
|
8
|
+
simulator.verbose = true
|
9
|
+
|
10
|
+
# 適当に検証用の答えの一覧を作る()内の数値は作成する答えの数
|
11
|
+
answers = Numeron::Simulator.build_sample_answers(100)
|
12
|
+
|
13
|
+
# 最初の攻撃文字列
|
14
|
+
first_attack = '123'
|
15
|
+
|
16
|
+
result = simulator.run(answers, first_attack) do |calculator|
|
17
|
+
## ここにシミュレーションしたいものを記述する(引数はNumeron::Calculator)
|
18
|
+
## 下は計算結果において、正解の可能性のリストから1つランダムで選択するパターン
|
19
|
+
## ちなみに10000件回してみたところ上記の可能性があるリストから1つ抜き出す方法の平均手数は 5.213 であった。
|
20
|
+
# calculator.possibilities.sample
|
21
|
+
|
22
|
+
## Analyzerを使うパターン
|
23
|
+
## max: 8, min: 2, median: 6, average: 5.74 (n=100)
|
24
|
+
# if calculator.possibilities.size > 21
|
25
|
+
# analyzer = Numeron::Analyzer.new(calculator)
|
26
|
+
# recommend = analyzer.run_worstcase_mode[:recommend]
|
27
|
+
# if recommend.size > 0
|
28
|
+
# recommend.sample
|
29
|
+
# else
|
30
|
+
# calculator.possibilities.sample
|
31
|
+
# end
|
32
|
+
# else
|
33
|
+
# calculator.possibilities.sample
|
34
|
+
# end
|
35
|
+
|
36
|
+
## max: 8, min: 3, median: 6, average: 5.9
|
37
|
+
analyzer = Numeron::Analyzer.new(calculator)
|
38
|
+
if calculator.possibilities.size > 21
|
39
|
+
recommend = analyzer.run_worstcase_mode[:recommend]
|
40
|
+
if recommend.size > 0
|
41
|
+
recommend.sample
|
42
|
+
else
|
43
|
+
calculator.possibilities.sample
|
44
|
+
end
|
45
|
+
else
|
46
|
+
recommend = analyzer.run_possibilities[:recommend]
|
47
|
+
if recommend.size > 0
|
48
|
+
recommend.sample
|
49
|
+
else
|
50
|
+
calculator.possibilities.sample
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
Numeron::Simulator.calc_statistics(result).each do |k, v|
|
57
|
+
puts k.to_s + ': ' + v.to_s
|
58
|
+
end
|
data/lib/numeron.rb
CHANGED
data/lib/numeron/analyzer.rb
CHANGED
@@ -52,7 +52,7 @@ module Numeron
|
|
52
52
|
_calculator.input(f, worst_case[:eat], worst_case[:bite])
|
53
53
|
if min_size == _calculator.possibilities.size
|
54
54
|
recommend << f
|
55
|
-
elsif min_size > _calculator.possibilities.size
|
55
|
+
elsif _calculator.possibilities.size > 0 && min_size > _calculator.possibilities.size
|
56
56
|
recommend = [f]
|
57
57
|
min_size = _calculator.possibilities.size
|
58
58
|
end
|
@@ -67,12 +67,10 @@ module Numeron
|
|
67
67
|
recommend = []
|
68
68
|
min_size = 10000
|
69
69
|
cases = [
|
70
|
-
{eat: 0, bite: 0},
|
71
70
|
{eat: 0, bite: 1},
|
72
71
|
{eat: 0, bite: 2},
|
73
72
|
{eat: 1, bite: 0},
|
74
|
-
{eat: 1, bite: 1}
|
75
|
-
{eat: 2, bite: 0}
|
73
|
+
{eat: 1, bite: 1}
|
76
74
|
]
|
77
75
|
possibilities.each do |f|
|
78
76
|
average = calc_average(f, cases, true)
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Numeron
|
4
|
+
class Simulator
|
5
|
+
attr_accessor :verbose
|
6
|
+
def initialize
|
7
|
+
@verbose = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(answers, first_attack, &block)
|
11
|
+
[].tap do |result|
|
12
|
+
answers.each {|answer|
|
13
|
+
result << {answer: answer, times: calc_answer(answer, first_attack, &block)}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# 答えが見つかる回数を計算する
|
19
|
+
def calc_answer(answer, first_attack, &block)
|
20
|
+
calculator = Numeron::Calculator.new
|
21
|
+
times = 1
|
22
|
+
result = eat_and_bite(answer, first_attack)
|
23
|
+
return times if result[:eat] == 3
|
24
|
+
calculator.input(first_attack, result[:eat], result[:bite])
|
25
|
+
output(times, first_attack, result[:eat], result[:bite], calculator.possibilities.size)
|
26
|
+
|
27
|
+
while times <= 20 # 計算機不具合での無限ループ回避
|
28
|
+
times += 1
|
29
|
+
input = block.call(calculator)
|
30
|
+
result = eat_and_bite(answer, input)
|
31
|
+
if result[:eat] == 3
|
32
|
+
output(times, input, result[:eat], result[:bite], 0)
|
33
|
+
break if result[:eat] == 3
|
34
|
+
else
|
35
|
+
calculator.input(input, result[:eat], result[:bite])
|
36
|
+
output(times, input, result[:eat], result[:bite], calculator.possibilities.size)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
times
|
40
|
+
end
|
41
|
+
|
42
|
+
def output(*args)
|
43
|
+
if @verbose
|
44
|
+
puts args.join(',')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def eat_and_bite(answer, input)
|
49
|
+
inputs = input.split(//).map(&:to_i)
|
50
|
+
answers = answer.split(//).map(&:to_i)
|
51
|
+
|
52
|
+
# eatの計算
|
53
|
+
{ eat: 0, bite: 0 }.tap do |result|
|
54
|
+
inputs.each_with_index{|f, i|
|
55
|
+
if answers[i] == f
|
56
|
+
result[:eat] = result[:eat] + 1
|
57
|
+
elsif answers.include?(f)
|
58
|
+
result[:bite] = result[:bite] + 1
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.build_sample_answers(num = 10)
|
65
|
+
lists = []
|
66
|
+
(0..9).to_a.each do |i|
|
67
|
+
(0..9).to_a.each do |j|
|
68
|
+
next if i == j
|
69
|
+
(0..9).to_a.each do |k|
|
70
|
+
next if i == k || j == k
|
71
|
+
lists << i.to_s + j.to_s + k.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
[].tap do |result|
|
77
|
+
num.times { result << lists.sample }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.calc_statistics(result)
|
82
|
+
sum = 0
|
83
|
+
_result = []
|
84
|
+
result.each do |f|
|
85
|
+
sum += f[:times]
|
86
|
+
_result << f[:times]
|
87
|
+
end
|
88
|
+
_result.sort!
|
89
|
+
|
90
|
+
{ max: _result.max, min: _result.min, median: _result[_result.size / 2], average: (sum.to_f / result.size.to_f) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/numeron/solver.rb
CHANGED
@@ -64,22 +64,39 @@ module Numeron
|
|
64
64
|
puts "... thinking"
|
65
65
|
puts "possibilities: " + @calc.possibilities.size.to_s
|
66
66
|
analyzer = Numeron::Analyzer.new(@calc)
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
if @calc.possibilities.size > 2
|
68
|
+
result = {recommend: 0}
|
69
|
+
if @calc.possibilities.size > 64
|
70
|
+
result = analyzer.run_average_mode
|
71
|
+
elsif @calc.possibilities.size > 21
|
72
|
+
result = analyzer.run_possibilities
|
73
|
+
else
|
74
|
+
cases = [
|
75
|
+
{eat: 0, bite: 0},
|
76
|
+
{eat: 0, bite: 1},
|
77
|
+
{eat: 0, bite: 2},
|
78
|
+
{eat: 1, bite: 0},
|
79
|
+
{eat: 1, bite: 1},
|
80
|
+
{eat: 2, bite: 0}
|
81
|
+
]
|
82
|
+
result = analyzer.run_average_mode(cases)
|
83
|
+
end
|
84
|
+
if result[:recommend].size > 0
|
85
|
+
puts "Analyzer Answer: " + result[:recommend].sample.to_s
|
86
|
+
else
|
87
|
+
puts "Calculator Error."
|
88
|
+
end
|
72
89
|
end
|
73
90
|
puts "Possibilitiy list random: " + @calc.possibilities.sample.to_s
|
74
91
|
end
|
75
92
|
|
76
93
|
def finish
|
77
94
|
while 1
|
78
|
-
print "\nfinish? [yes
|
95
|
+
print "\nfinish? [yes] "
|
79
96
|
f = STDIN.gets.chomp
|
80
97
|
if(f == 'yes' || f == 'y')
|
81
98
|
exit
|
82
|
-
|
99
|
+
else
|
83
100
|
break
|
84
101
|
end
|
85
102
|
end
|
data/lib/numeron/version.rb
CHANGED
data/numeron.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.version = Numeron::VERSION
|
9
9
|
gem.authors = ["kengos"]
|
10
10
|
gem.email = ["kengo@kengos.jp"]
|
11
|
-
gem.description = %q{numer0nの解を計算します。}
|
11
|
+
gem.description = %q{numer0nの解を計算します。(Shuffle対応,シミュレーター付き,Analyzer未完成)}
|
12
12
|
gem.summary = %q{numer0n solver}
|
13
13
|
gem.homepage = "https://github.com/kengos/numeron"
|
14
14
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Numeron::Simulator do
|
6
|
+
|
7
|
+
describe '#run' do
|
8
|
+
let(:simulator) { Numeron::Simulator.new }
|
9
|
+
it 'should give a block' do
|
10
|
+
result = simulator.run(['308', '259'], '123') do |calculator|
|
11
|
+
calculator.possibilities.sample
|
12
|
+
end
|
13
|
+
result.should have(2).items
|
14
|
+
result[0][:answer].should eql '308'
|
15
|
+
result[0][:times].should > 0
|
16
|
+
result[1][:answer].should eql '259'
|
17
|
+
result[1][:times].should > 0
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#calc_answer' do
|
22
|
+
let(:simulator) { Numeron::Simulator.new }
|
23
|
+
it 'should give a block' do
|
24
|
+
simulator.calc_answer('630', '123') do |calculator|
|
25
|
+
calculator.possibilities.sample
|
26
|
+
end.should >= 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '.build_sample_answers' do
|
31
|
+
it { Numeron::Simulator::build_sample_answers(5).should have(5).items }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.calc_statistics' do
|
35
|
+
let(:result) {
|
36
|
+
[
|
37
|
+
{times: 4}, {times: 2}, {times: 5}, {times: 4}, {times: 3}
|
38
|
+
]
|
39
|
+
}
|
40
|
+
it { Numeron::Simulator::calc_statistics(result).should == {max: 5, min: 2, median: 4, average: 3.6} }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#eat_and_bite' do
|
44
|
+
let(:answer) { '987' }
|
45
|
+
subject { Numeron::Simulator.new.eat_and_bite(answer, input) }
|
46
|
+
|
47
|
+
context '123' do
|
48
|
+
let(:input) { '123' }
|
49
|
+
it { should == {eat: 0, bite: 0} }
|
50
|
+
end
|
51
|
+
|
52
|
+
context '812' do
|
53
|
+
let(:input) { '812' }
|
54
|
+
it { should == {eat: 0, bite: 1} }
|
55
|
+
end
|
56
|
+
|
57
|
+
context '871' do
|
58
|
+
let(:input) { '871' }
|
59
|
+
it { should == {eat: 0, bite: 2} }
|
60
|
+
end
|
61
|
+
|
62
|
+
context '879' do
|
63
|
+
let(:input) { '879' }
|
64
|
+
it { should == {eat: 0, bite: 3} }
|
65
|
+
end
|
66
|
+
|
67
|
+
context '912' do
|
68
|
+
let(:input) { '912' }
|
69
|
+
it { should == {eat: 1, bite: 0} }
|
70
|
+
end
|
71
|
+
|
72
|
+
context '971' do
|
73
|
+
let(:input) { '971' }
|
74
|
+
it { should == {eat: 1, bite: 1} }
|
75
|
+
end
|
76
|
+
|
77
|
+
context '978' do
|
78
|
+
let(:input) { '978' }
|
79
|
+
it { should == {eat: 1, bite: 2} }
|
80
|
+
end
|
81
|
+
|
82
|
+
context '981' do
|
83
|
+
let(:input) { '981' }
|
84
|
+
it { should == {eat: 2, bite: 0} }
|
85
|
+
end
|
86
|
+
|
87
|
+
context '987' do
|
88
|
+
let(:input) { '987' }
|
89
|
+
it { should == {eat: 3, bite: 0} }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: numeron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2012-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: numer0nの解を計算します。
|
14
|
+
description: numer0nの解を計算します。(Shuffle対応,シミュレーター付き,Analyzer未完成)
|
15
15
|
email:
|
16
16
|
- kengo@kengos.jp
|
17
17
|
executables: []
|
@@ -24,14 +24,17 @@ files:
|
|
24
24
|
- LICENSE.txt
|
25
25
|
- README.md
|
26
26
|
- Rakefile
|
27
|
+
- examples/simulator_example.rb
|
27
28
|
- lib/numeron.rb
|
28
29
|
- lib/numeron/analyzer.rb
|
29
30
|
- lib/numeron/calculator.rb
|
31
|
+
- lib/numeron/simulator.rb
|
30
32
|
- lib/numeron/solver.rb
|
31
33
|
- lib/numeron/version.rb
|
32
34
|
- numeron.gemspec
|
33
35
|
- spec/lib/numeron/analyzer_spec.rb
|
34
36
|
- spec/lib/numeron/calculator_spec.rb
|
37
|
+
- spec/lib/numeron/simulator_spec.rb
|
35
38
|
- spec/lib/numeron_spec.rb
|
36
39
|
- spec/spec_helper.rb
|
37
40
|
homepage: https://github.com/kengos/numeron
|
@@ -61,6 +64,7 @@ summary: numer0n solver
|
|
61
64
|
test_files:
|
62
65
|
- spec/lib/numeron/analyzer_spec.rb
|
63
66
|
- spec/lib/numeron/calculator_spec.rb
|
67
|
+
- spec/lib/numeron/simulator_spec.rb
|
64
68
|
- spec/lib/numeron_spec.rb
|
65
69
|
- spec/spec_helper.rb
|
66
70
|
has_rdoc:
|