codebreaker-ga 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -2
- data/codebreaker.gemspec +1 -1
- data/lib/codebreaker.rb +2 -0
- data/lib/codebreaker/compare_codes.rb +46 -0
- data/lib/codebreaker/game.rb +26 -65
- data/lib/codebreaker/game_stage.rb +3 -3
- data/lib/codebreaker/init_difficulties.rb +5 -4
- data/lib/codebreaker/user.rb +2 -2
- data/lib/codebreaker/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e647e6d8cb566c0a1f3c8898876d13ac451f7271429ae361fb9750162eeb0e3b
|
4
|
+
data.tar.gz: ee54eee43f35693f60ec86ee5cbbb31ef735a6a662c1cde88a7698832f09f5fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c50dc7181c2161a182ee4edb114d36d54795c4de8f81dae72aa948ea580e63cec486516c94357a126572270dd938d6a5861cf4bfc89216bd382d77e44cf83d43
|
7
|
+
data.tar.gz: 904ba288e4f486c88398a7a3297b3d3ba6df35b188367280b19d8d81a6bcd6f6d85776117bd1a781e8e677a2a5402b009ba5719862d4e24ee2e560a8a21e1c8a
|
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
codebreaker-ga (0.2.
|
4
|
+
codebreaker-ga (0.2.6)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.0)
|
10
|
+
coderay (1.1.2)
|
10
11
|
colorize (0.8.1)
|
11
12
|
diff-lcs (1.3)
|
12
13
|
docile (1.3.2)
|
@@ -15,9 +16,13 @@ GEM
|
|
15
16
|
ruby_parser (>= 3.14.1)
|
16
17
|
jaro_winkler (1.5.4)
|
17
18
|
json (2.3.0)
|
19
|
+
method_source (0.9.2)
|
18
20
|
parallel (1.19.1)
|
19
21
|
parser (2.6.5.0)
|
20
22
|
ast (~> 2.4.0)
|
23
|
+
pry (0.12.2)
|
24
|
+
coderay (~> 1.1.0)
|
25
|
+
method_source (~> 0.9.0)
|
21
26
|
rainbow (3.0.0)
|
22
27
|
rake (12.3.3)
|
23
28
|
rspec (3.9.0)
|
@@ -33,7 +38,7 @@ GEM
|
|
33
38
|
diff-lcs (>= 1.2.0, < 2.0)
|
34
39
|
rspec-support (~> 3.9.0)
|
35
40
|
rspec-support (3.9.0)
|
36
|
-
rubocop (0.
|
41
|
+
rubocop (0.78.0)
|
37
42
|
jaro_winkler (~> 1.5.1)
|
38
43
|
parallel (~> 1.10)
|
39
44
|
parser (>= 2.6)
|
@@ -60,6 +65,7 @@ DEPENDENCIES
|
|
60
65
|
bundler (~> 2.0)
|
61
66
|
codebreaker-ga!
|
62
67
|
fasterer (~> 0.8.0)
|
68
|
+
pry (~> 0.12.2)
|
63
69
|
rake (~> 12.3.1)
|
64
70
|
rspec (~> 3.0)
|
65
71
|
rubocop-rspec
|
data/codebreaker.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
23
23
|
spec.add_development_dependency 'fasterer', '~> 0.8.0'
|
24
|
-
|
24
|
+
spec.add_development_dependency 'pry', '~> 0.12.2'
|
25
25
|
spec.add_development_dependency 'rake', '~> 12.3.1'
|
26
26
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
27
27
|
spec.add_development_dependency 'rubocop-rspec'
|
data/lib/codebreaker.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
module Codebreaker
|
2
|
+
require 'pry'
|
2
3
|
require 'codebreaker/version'
|
3
4
|
require 'codebreaker/yaml_file.rb'
|
4
5
|
require 'codebreaker/validator.rb'
|
6
|
+
require 'codebreaker/compare_codes.rb'
|
5
7
|
require 'codebreaker/base_class.rb'
|
6
8
|
require 'codebreaker/difficulty.rb'
|
7
9
|
require 'codebreaker/init_difficulties.rb'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Codebreaker
|
2
|
+
class CompareCodes
|
3
|
+
def initialize(secret_code)
|
4
|
+
@secret_code = secret_code
|
5
|
+
@secret_code_positions = get_code_positions(@secret_code)
|
6
|
+
end
|
7
|
+
|
8
|
+
def compare(match_code)
|
9
|
+
@match_code_positions = get_code_positions(match_code)
|
10
|
+
crossing_values = @secret_code & match_code
|
11
|
+
crossing_values.each_with_object([]) { |value, cross_result| cross_result << get_cross_value(value) }
|
12
|
+
.flatten.sort_by { |item| item ? 0 : 1 }
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_cross_value(value)
|
16
|
+
guess_position(value) + guess_value(value)
|
17
|
+
end
|
18
|
+
|
19
|
+
def guess_position(value)
|
20
|
+
crossing_positions = @match_code_positions[value] & @secret_code_positions[value]
|
21
|
+
crossing_positions.empty? ? [] : Array.new(crossing_positions.size, true)
|
22
|
+
end
|
23
|
+
|
24
|
+
def guess_value(value)
|
25
|
+
crossing_positions = @match_code_positions[value] & @secret_code_positions[value]
|
26
|
+
|
27
|
+
match_code_positions = crossing_code_position(value, @match_code_positions, crossing_positions)
|
28
|
+
secret_code_positions = crossing_code_position(value, @secret_code_positions, crossing_positions)
|
29
|
+
|
30
|
+
size_no_cross_code = [secret_code_positions[value].size, match_code_positions[value].size].min
|
31
|
+
crossing_positions.empty? && size_no_cross_code.zero? ? [] : Array.new(size_no_cross_code, false)
|
32
|
+
end
|
33
|
+
|
34
|
+
def crossing_code_position(value, code_array, crossing_positions)
|
35
|
+
code_positions = code_array.dup
|
36
|
+
code_positions[value] -= crossing_positions
|
37
|
+
code_positions
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_code_positions(code_array)
|
41
|
+
return if code_array.nil? || code_array.empty?
|
42
|
+
|
43
|
+
code_array.each_with_object(Hash.new([])).with_index { |(value, code), index| code[value] += [index] }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/codebreaker/game.rb
CHANGED
@@ -1,46 +1,45 @@
|
|
1
1
|
module Codebreaker
|
2
|
-
class
|
2
|
+
class Game < BaseClass
|
3
3
|
include InitDifficulties
|
4
4
|
|
5
5
|
CODE_LENGTH = 4
|
6
6
|
CODE_NUMBERS = ('1'..'6').freeze
|
7
7
|
|
8
|
-
attr_reader :statistic, :
|
8
|
+
attr_reader :statistic, :difficulties, :difficulty, :errors #:game_stage
|
9
9
|
attr_accessor :user, :hint_code
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@errors = {}
|
13
13
|
@statistic = Statistic.new
|
14
|
-
@
|
14
|
+
@difficulties = init_difficulties
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
return true if validate_length?(
|
17
|
+
def match_code_valid_length?(match_code)
|
18
|
+
return true if validate_length?(match_code, CODE_LENGTH..CODE_LENGTH)
|
19
19
|
|
20
|
-
|
20
|
+
(@errors[:match_code] = 'error_match_code_length') && false
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
24
|
-
return true if validate_number_range?(
|
23
|
+
def validate_match_code_number_range?(match_code)
|
24
|
+
return true if validate_number_range?(match_code, CODE_NUMBERS)
|
25
25
|
|
26
|
-
|
26
|
+
(@errors[:match_code] = 'error_match_code_number') && false
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
@
|
29
|
+
def difficulty=(difficulty)
|
30
|
+
@difficulty = @difficulties.detect { |value| value.name == difficulty }
|
31
31
|
end
|
32
32
|
|
33
33
|
def game_start
|
34
34
|
generate_secret_code
|
35
|
-
generate_hints
|
36
|
-
@game_stage = GameStage.new(
|
35
|
+
generate_hints
|
36
|
+
@game_stage = GameStage.new(match_code_length: CODE_LENGTH, attempts: @difficulty.attempts)
|
37
37
|
end
|
38
38
|
|
39
|
-
def game_step(
|
40
|
-
return unless
|
39
|
+
def game_step(match_codes)
|
40
|
+
return unless match_code_valid?(match_codes)
|
41
41
|
|
42
|
-
@
|
43
|
-
@game_stage.step(compare_codes(user_code))
|
42
|
+
@game_stage.step(@compare_codes.compare(match_codes))
|
44
43
|
@game_stage.compare_result
|
45
44
|
end
|
46
45
|
|
@@ -57,78 +56,40 @@ module Codebreaker
|
|
57
56
|
end
|
58
57
|
|
59
58
|
def statistic_save
|
60
|
-
@statistic.statistic_add_item(name: user.username, difficulty:
|
59
|
+
@statistic.statistic_add_item(name: user.username, difficulty: @difficulty, game_stage: @game_stage)
|
61
60
|
@statistic.statistic_save
|
62
61
|
end
|
63
62
|
|
64
63
|
private
|
65
64
|
|
66
|
-
def
|
67
|
-
return unless
|
68
|
-
return unless
|
65
|
+
def match_code_valid?(match_code)
|
66
|
+
return unless match_code_valid_length?(match_code)
|
67
|
+
return unless validate_match_code_number_range?(match_code)
|
69
68
|
|
70
69
|
true
|
71
70
|
end
|
72
71
|
|
73
72
|
def difficulty_valid?
|
74
|
-
return true unless @
|
73
|
+
return true unless @difficulty.nil? || @difficulty.empty?
|
75
74
|
|
76
75
|
@errors[:difficulty] = 'difficulty_change_error'
|
77
76
|
false
|
78
77
|
end
|
79
78
|
|
80
|
-
def compare_codes(user_code)
|
81
|
-
crossing_values = @secret_code & user_code
|
82
|
-
crossing_values.each_with_object([]) { |value, cross_result| cross_result << get_cross_value(value) }
|
83
|
-
.flatten.sort_by { |item| item ? 0 : 1 }
|
84
|
-
end
|
85
|
-
|
86
79
|
def generate_number
|
87
80
|
Array.new(CODE_LENGTH) { CODE_NUMBERS.to_a.sample }
|
88
81
|
end
|
89
82
|
|
90
|
-
def generate_secret_code
|
91
|
-
@secret_code = generate_number
|
92
|
-
@secret_code_positions = get_code_positions(@secret_code)
|
93
|
-
generate_hints
|
94
|
-
end
|
95
|
-
|
96
83
|
def generate_hints
|
97
|
-
@hint_code = @secret_code.nil? ? [] : @secret_code.sample(@
|
84
|
+
@hint_code = @secret_code.nil? ? [] : @secret_code.sample(@difficulty.hints)
|
98
85
|
end
|
99
86
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
def guess_position(value)
|
105
|
-
crossing_positions = @user_code_positions[value] & @secret_code_positions[value]
|
106
|
-
crossing_positions.empty? ? [] : Array.new(crossing_positions.size, true)
|
107
|
-
end
|
108
|
-
|
109
|
-
def guess_value(value)
|
110
|
-
crossing_positions = @user_code_positions[value] & @secret_code_positions[value]
|
111
|
-
|
112
|
-
user_code_positions = crossing_code_position(value, @user_code_positions, crossing_positions)
|
113
|
-
secret_code_positions = crossing_code_position(value, @secret_code_positions, crossing_positions)
|
114
|
-
|
115
|
-
size_no_cross_code = [secret_code_positions[value].size, user_code_positions[value].size].min
|
116
|
-
crossing_positions.empty? && size_no_cross_code.zero? ? [] : Array.new(size_no_cross_code, false)
|
117
|
-
end
|
118
|
-
|
119
|
-
def crossing_code_position(value, code_array, crossing_positions)
|
120
|
-
code_positions = code_array.dup
|
121
|
-
code_positions[value] -= crossing_positions
|
122
|
-
code_positions
|
123
|
-
end
|
124
|
-
|
125
|
-
def get_code_positions(code_array)
|
126
|
-
return if code_array.nil? || code_array.empty?
|
127
|
-
|
128
|
-
code_array.each_with_object(Hash.new([])).with_index { |(value, code), index| code[value] += [index] }
|
87
|
+
def generate_secret_code
|
88
|
+
@secret_code = generate_number
|
89
|
+
@compare_codes = CompareCodes.new(@secret_code)
|
129
90
|
end
|
130
91
|
|
131
|
-
def validate
|
92
|
+
def validate
|
132
93
|
@errors = {}
|
133
94
|
difficulty_valid?
|
134
95
|
end
|
@@ -3,19 +3,19 @@ module Codebreaker
|
|
3
3
|
attr_reader :step_number, :endgame, :attempts, :compare_result, :win
|
4
4
|
attr_accessor :hint_used
|
5
5
|
|
6
|
-
def initialize(
|
6
|
+
def initialize(match_code_length:, attempts:)
|
7
7
|
@step_number = 1
|
8
8
|
@endgame = false
|
9
9
|
@attempts = attempts
|
10
10
|
@compare_result = []
|
11
|
-
@
|
11
|
+
@match_code_length = match_code_length
|
12
12
|
@hint_used = 0
|
13
13
|
end
|
14
14
|
|
15
15
|
def step(compare_result)
|
16
16
|
@compare_result = compare_result
|
17
17
|
@step_number += 1
|
18
|
-
@win = @compare_result.length == @
|
18
|
+
@win = @compare_result.length == @match_code_length && @compare_result.all?
|
19
19
|
@endgame = true if @step_number > @attempts || @win
|
20
20
|
end
|
21
21
|
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Codebreaker
|
2
2
|
module InitDifficulties
|
3
3
|
def init_difficulties
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
[
|
5
|
+
Difficulty.new(name: 'Easy', attempts: 15, hints: 2, level: 0),
|
6
|
+
Difficulty.new(name: 'Medium', attempts: 10, hints: 1, level: 1),
|
7
|
+
Difficulty.new(name: 'Hell', attempts: 5, hints: 1, level: 2)
|
8
|
+
]
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
data/lib/codebreaker/user.rb
CHANGED
@@ -6,13 +6,13 @@ module Codebreaker
|
|
6
6
|
|
7
7
|
def initialize(username_new)
|
8
8
|
@username = username_new
|
9
|
-
@errors =
|
9
|
+
@errors = {}
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def validate
|
15
|
-
@errors
|
15
|
+
@errors[:user] = 'error_name_length' unless validate_length?(@username, USERNAME_LENGTH_RANGE)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/codebreaker/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codebreaker-ga
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GorohovAlex
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.8.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.12.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.12.2
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,6 +129,7 @@ files:
|
|
115
129
|
- codebreaker.gemspec
|
116
130
|
- lib/codebreaker.rb
|
117
131
|
- lib/codebreaker/base_class.rb
|
132
|
+
- lib/codebreaker/compare_codes.rb
|
118
133
|
- lib/codebreaker/difficulty.rb
|
119
134
|
- lib/codebreaker/game.rb
|
120
135
|
- lib/codebreaker/game_stage.rb
|