codebreaker-ga 0.2.5 → 0.2.6
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 +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
|