mastermind_ruby 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/Rakefile +21 -0
- data/bin/statistics +88 -0
- data/lib/mastermind_ruby/code.rb +4 -0
- data/lib/mastermind_ruby/console_interface.rb +1 -1
- data/lib/mastermind_ruby/game.rb +1 -1
- data/lib/mastermind_ruby/solver/brute_force_solver.rb +23 -0
- data/lib/mastermind_ruby/solver/intelligent_brute_force_solver.rb +40 -0
- data/lib/mastermind_ruby/solver/solve_interface.rb +40 -0
- data/lib/mastermind_ruby/version.rb +1 -1
- data/mastermind_ruby.gemspec +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bbcb52ce824fef8cce1bce5461618f53133a32a3
|
4
|
+
data.tar.gz: b708ecc974c04d200f814460b896844badcaa40c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13ccf32aa18f9e82191c6293a6258f3b2e3f640f655d4ebb8a6476543c0c4c129f986dbdfe9715353d5e914567dd460c602d49042468278a2def6169162e300f
|
7
|
+
data.tar.gz: f44a9251273c8efb78049c44eb86898c7155fc1503941c1b72580e133b658b587d736a78f4a40e9e72ba8c951206398c4418dde6412b222ee128b752f81a623d
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
@@ -2,9 +2,26 @@ require "bundler/gem_tasks"
|
|
2
2
|
|
3
3
|
task :default => :test
|
4
4
|
|
5
|
+
desc 'Run all solvers'
|
6
|
+
task :solve => ["solve:intelligent_brute_force", "solve:brute_force"]
|
7
|
+
|
5
8
|
desc 'Run all tests'
|
6
9
|
task :test => ["test:unit", "test:integration"]
|
7
10
|
|
11
|
+
namespace :solve do
|
12
|
+
desc 'Brute force solve'
|
13
|
+
task :brute_force do
|
14
|
+
puts "----------- Running brute force solve ------------"
|
15
|
+
require_relative 'lib/mastermind_ruby/solver/brute_force_solver.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Intelligent brute force solve'
|
19
|
+
task :intelligent_brute_force do
|
20
|
+
puts "----------- Intelligent brute force solve ------------"
|
21
|
+
require_relative 'lib/mastermind_ruby/solver/intelligent_brute_force_solver.rb'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
8
25
|
namespace :test do
|
9
26
|
desc 'Run all unit tests'
|
10
27
|
task :unit do
|
@@ -21,6 +38,10 @@ namespace :test do
|
|
21
38
|
end
|
22
39
|
end
|
23
40
|
|
41
|
+
task :statistics do
|
42
|
+
trap(0) { system "bin/statistics" }
|
43
|
+
end
|
44
|
+
|
24
45
|
task :run do
|
25
46
|
trap(0) { system "exe/mastermind" }
|
26
47
|
end
|
data/bin/statistics
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/mastermind_ruby/solver/brute_force_solver'
|
3
|
+
require_relative '../lib/mastermind_ruby/solver/intelligent_brute_force_solver'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
def show_wait_spinner(fps=10)
|
7
|
+
chars = %w[| / - \\]
|
8
|
+
delay = 1.0/fps
|
9
|
+
iter = 0
|
10
|
+
spinner = Thread.new do
|
11
|
+
while iter do # Keep spinning until told otherwise
|
12
|
+
print chars[(iter+=1) % chars.length]
|
13
|
+
sleep delay
|
14
|
+
print "\b"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
yield.tap{ # After yielding to the block, save the return value
|
18
|
+
iter = false # Tell the thread to exit, cleaning up after itself…
|
19
|
+
spinner.join # …and wait for it to do so.
|
20
|
+
} # Use the block's return value as the method's
|
21
|
+
end
|
22
|
+
|
23
|
+
def standard_devitation(arr)
|
24
|
+
avg = arr.inject(:+) / arr.length
|
25
|
+
devitations = arr.map do |item|
|
26
|
+
(item - avg)**2
|
27
|
+
end
|
28
|
+
Math.sqrt(devitations.inject(:+) / arr.length)
|
29
|
+
end
|
30
|
+
|
31
|
+
def median(arr)
|
32
|
+
sorted = arr.sort
|
33
|
+
len = sorted.length
|
34
|
+
(sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
|
35
|
+
end
|
36
|
+
|
37
|
+
# Game count input
|
38
|
+
games = 10
|
39
|
+
print 'How many games should the solvers solve: '
|
40
|
+
games_input = gets.strip.to_i
|
41
|
+
unless games_input == 0
|
42
|
+
games = games_input
|
43
|
+
end
|
44
|
+
|
45
|
+
# Code length input
|
46
|
+
code_length = 4
|
47
|
+
print 'Code length (Hit enter for default): '
|
48
|
+
code_length_input = gets.strip.to_i
|
49
|
+
unless code_length_input == 0
|
50
|
+
code_length = code_length_input
|
51
|
+
end
|
52
|
+
|
53
|
+
solvers = [IntelligentBruteForceSolver, BruteForceSolver]
|
54
|
+
counts = {}
|
55
|
+
benchmarks = {}
|
56
|
+
|
57
|
+
puts "Generating statistics..."
|
58
|
+
|
59
|
+
show_wait_spinner{
|
60
|
+
games.times do
|
61
|
+
generated_code = MastermindRuby::Code.random(code_length)
|
62
|
+
solvers.each do |solver_class|
|
63
|
+
counts[solver_class] ||= []
|
64
|
+
benchmarks[solver_class] ||= []
|
65
|
+
solver = solver_class.new(code_length: code_length)
|
66
|
+
ui = SolveInterface.new(solver)
|
67
|
+
game = MastermindRuby::Game.new(ui, solution: generated_code)
|
68
|
+
time = Benchmark.realtime do
|
69
|
+
game.start
|
70
|
+
end
|
71
|
+
benchmarks[solver_class] << time
|
72
|
+
counts[solver_class] << ui.current_try
|
73
|
+
end
|
74
|
+
end
|
75
|
+
}
|
76
|
+
puts "------------------ Statistics for #{games} games with code length #{code_length} ----------------"
|
77
|
+
puts ''
|
78
|
+
solvers.each do |solver|
|
79
|
+
tries = counts[solver].sort
|
80
|
+
puts "---------- #{solver} -----------"
|
81
|
+
puts "- Total time needed to solve \033[1m#{games}\033[0m games: \033[1m#{'%.4f' % benchmarks[solver].inject(:+)}\033[0m seconds"
|
82
|
+
puts "- Total: \033[1m#{tries.inject(:+)}\033[0m tries"
|
83
|
+
puts "- Average per game: \033[1m#{tries.inject(:+) / tries.length}\033[0m tries"
|
84
|
+
puts "- Standard devitation: \033[1m#{'%.4f' % standard_devitation(tries)}\033[0m"
|
85
|
+
puts "- Median: \033[1m#{median(tries)}\033[0m"
|
86
|
+
puts "- Best: \033[1m#{tries.first}\033[0m tries"
|
87
|
+
puts "- Worst: \033[1m#{tries.last}\033[0m tries"
|
88
|
+
end
|
data/lib/mastermind_ruby/code.rb
CHANGED
data/lib/mastermind_ruby/game.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'solve_interface'
|
2
|
+
|
3
|
+
class BruteForceSolver
|
4
|
+
attr_reader :code_length
|
5
|
+
|
6
|
+
def initialize(code_length: 4)
|
7
|
+
@code_length = code_length
|
8
|
+
@input = generate_start_codes
|
9
|
+
end
|
10
|
+
|
11
|
+
def request_quess(count)
|
12
|
+
MastermindRuby::Code.parse(@input[count])
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_start_codes
|
16
|
+
MastermindRuby::Code::AVAILABLE_CHARACTERS.repeated_permutation(@code_length).map &:join
|
17
|
+
end
|
18
|
+
|
19
|
+
def assessment_received(result)
|
20
|
+
# idiot solver ignores what assessment is received
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'solve_interface'
|
2
|
+
|
3
|
+
class IntelligentBruteForceSolver
|
4
|
+
attr_reader :code_length
|
5
|
+
|
6
|
+
def initialize(code_length: 4)
|
7
|
+
@code_length = code_length
|
8
|
+
@basic_codes = generate_start_codes
|
9
|
+
@basic_try = -1
|
10
|
+
@code_try = -1
|
11
|
+
@existing_chars = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def request_quess(count)
|
15
|
+
if @basic_try < 5
|
16
|
+
@basic_try += 1
|
17
|
+
MastermindRuby::Code.parse(@basic_codes[@basic_try])
|
18
|
+
else
|
19
|
+
@code_try += 1
|
20
|
+
@tryable_codes ||= generate_codes
|
21
|
+
MastermindRuby::Code.new(@tryable_codes[@code_try])
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def assessment_received(result)
|
26
|
+
unless result == @code_length.times.map { '-' }.join
|
27
|
+
result.count('B').times { @existing_chars << MastermindRuby::Code::AVAILABLE_CHARACTERS[@basic_try] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate_start_codes
|
32
|
+
MastermindRuby::Code::AVAILABLE_CHARACTERS.map do |char|
|
33
|
+
char * @code_length
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def generate_codes
|
38
|
+
@existing_chars.permutation.to_a.uniq
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative '../../mastermind_ruby'
|
2
|
+
|
3
|
+
|
4
|
+
class SolveInterface
|
5
|
+
attr_reader :current_try
|
6
|
+
|
7
|
+
def initialize(solver)
|
8
|
+
@solver = solver
|
9
|
+
@code_length = solver.code_length
|
10
|
+
@current_try = -1
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_playername
|
14
|
+
@solver.class.name
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_code_length
|
18
|
+
@code_length
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_next_guess(try_count)
|
22
|
+
@current_try += 1
|
23
|
+
@solver.request_quess(try_count -1)
|
24
|
+
end
|
25
|
+
|
26
|
+
def display_welcome_message(playername)
|
27
|
+
end
|
28
|
+
|
29
|
+
def display_assessment(result)
|
30
|
+
@solver.assessment_received(result)
|
31
|
+
end
|
32
|
+
|
33
|
+
def display_invalid_code(code)
|
34
|
+
raise ArgumentError, "#{code.inspect} is not a valid code"
|
35
|
+
# raise ArgumentError.new('Please enter a valid code')
|
36
|
+
end
|
37
|
+
|
38
|
+
def display_end_game(try_count)
|
39
|
+
end
|
40
|
+
end
|
data/mastermind_ruby.gemspec
CHANGED
@@ -3,7 +3,7 @@ require_relative 'lib/mastermind_ruby/version'
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = 'mastermind_ruby'
|
5
5
|
s.version = MastermindRuby::VERSION
|
6
|
-
s.date = '2015-08-
|
6
|
+
s.date = '2015-08-10'
|
7
7
|
s.summary = "A mastermind library"
|
8
8
|
s.description = "Mastermind or Master Mind is a code-breaking game for two players.
|
9
9
|
The modern game with pegs was invented in 1970 by Mordecai Meirowitz, an Israeli postmaster and telecommunications expert.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mastermind_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yves Siegrist
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-08-
|
12
|
+
date: 2015-08-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -58,11 +58,15 @@ files:
|
|
58
58
|
- Rakefile
|
59
59
|
- TODO.md
|
60
60
|
- bin/rake
|
61
|
+
- bin/statistics
|
61
62
|
- exe/mastermind
|
62
63
|
- lib/mastermind_ruby.rb
|
63
64
|
- lib/mastermind_ruby/code.rb
|
64
65
|
- lib/mastermind_ruby/console_interface.rb
|
65
66
|
- lib/mastermind_ruby/game.rb
|
67
|
+
- lib/mastermind_ruby/solver/brute_force_solver.rb
|
68
|
+
- lib/mastermind_ruby/solver/intelligent_brute_force_solver.rb
|
69
|
+
- lib/mastermind_ruby/solver/solve_interface.rb
|
66
70
|
- lib/mastermind_ruby/version.rb
|
67
71
|
- mastermind_ruby.gemspec
|
68
72
|
homepage: https://github.com/Elektron1c97/Mastermind_ruby
|