mastermind_ruby 0.0.4 → 0.0.5
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.
- 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
|