codebreaker_vk 0.2.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.overcommit.yml +5 -3
- data/.rubocop.yml +10 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +9 -6
- data/Rakefile +2 -0
- data/autoload.rb +16 -0
- data/codebreaker_vk-0.2.3.gem +0 -0
- data/codebreaker_vk.gemspec +6 -9
- data/config/i18n.rb +3 -0
- data/config/locales/en.yml +41 -0
- data/lib/codebreaker_vk.rb +1 -8
- data/lib/codebreaker_vk/check_errors.rb +16 -0
- data/lib/codebreaker_vk/console.rb +111 -0
- data/lib/codebreaker_vk/difficulty.rb +38 -0
- data/lib/codebreaker_vk/game.rb +54 -61
- data/lib/codebreaker_vk/game_messages.rb +79 -0
- data/lib/codebreaker_vk/game_process.rb +19 -25
- data/lib/codebreaker_vk/game_user.rb +18 -0
- data/lib/codebreaker_vk/uploader/uploader.rb +18 -0
- data/lib/codebreaker_vk/validate/validate.rb +21 -0
- data/lib/codebreaker_vk/validating_data.rb +20 -0
- data/lib/codebreaker_vk/version.rb +1 -1
- metadata +15 -7
- data/lib/codebreaker_vk/config.rb +0 -17
- data/lib/codebreaker_vk/errors/autoload.rb +0 -5
- data/lib/codebreaker_vk/errors/difficulty_level_error.rb +0 -5
- data/lib/codebreaker_vk/errors/format_error.rb +0 -5
- data/lib/codebreaker_vk/errors/max_hint_error.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz: '
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08ab1117ccd9224ff33761dce7aa30a1cd572e67001b7e58b9499b9c3af850b5'
|
4
|
+
data.tar.gz: 90ffb5d6bbe399a0a762b6828bd202496818871d714dff4a6716d95e15280163
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ca02359a5f01b2cafbb9e9ce3b1724dbe1a0014b994a9e81f931961089e2c188d7f3e2c4ee4cbdc3772f4e09938d59ea7ea1b4e377281e14156280d88450713
|
7
|
+
data.tar.gz: 92b9a4df7cc29020a358499c560b3a427f4a07ca07eb2178acc3ebc2497dd1d4005bcda269d5b3e0faea8a9a26ebd0125ede18aaf8bf6ca9a8aeb74fbf5d0267
|
data/.overcommit.yml
CHANGED
@@ -43,14 +43,16 @@ PreCommit:
|
|
43
43
|
enabled: true
|
44
44
|
|
45
45
|
BundleOutdated:
|
46
|
-
enabled:
|
46
|
+
enabled: false
|
47
47
|
|
48
48
|
ExecutePermissions:
|
49
49
|
enabled: false
|
50
50
|
|
51
51
|
ForbiddenBranches:
|
52
|
-
enabled:
|
52
|
+
enabled: false
|
53
53
|
branch_patterns: ['master']
|
54
54
|
|
55
55
|
LineEndings:
|
56
|
-
enabled:
|
56
|
+
enabled: false
|
57
|
+
|
58
|
+
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,28 +1,30 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
codebreaker_vk (0.
|
4
|
+
codebreaker_vk (0.3.1)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
ast (2.4.0)
|
10
|
-
childprocess (0.
|
11
|
-
|
10
|
+
childprocess (1.0.1)
|
11
|
+
rake (< 13.0)
|
12
12
|
coderay (1.1.2)
|
13
13
|
colorize (0.8.1)
|
14
|
+
concurrent-ruby (1.1.5)
|
14
15
|
diff-lcs (1.3)
|
15
16
|
docile (1.3.2)
|
16
17
|
fasterer (0.5.1)
|
17
18
|
colorize (~> 0.7)
|
18
19
|
ruby_parser (>= 3.13.0)
|
19
|
-
|
20
|
+
i18n (1.6.0)
|
21
|
+
concurrent-ruby (~> 1.0)
|
20
22
|
iniparse (1.4.4)
|
21
23
|
jaro_winkler (1.5.3)
|
22
24
|
json (2.2.0)
|
23
25
|
method_source (0.9.2)
|
24
|
-
overcommit (0.
|
25
|
-
childprocess (
|
26
|
+
overcommit (0.49.0)
|
27
|
+
childprocess (>= 0.6.3, < 2.0)
|
26
28
|
iniparse (~> 1.4)
|
27
29
|
parallel (1.17.0)
|
28
30
|
parser (2.6.3.0)
|
@@ -74,6 +76,7 @@ DEPENDENCIES
|
|
74
76
|
bundler (~> 2.0)
|
75
77
|
codebreaker_vk!
|
76
78
|
fasterer (~> 0.5.1)
|
79
|
+
i18n
|
77
80
|
overcommit
|
78
81
|
pry (~> 0.12.2)
|
79
82
|
rake (~> 10.0)
|
data/Rakefile
CHANGED
data/autoload.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'i18n'
|
4
|
+
require 'yaml'
|
5
|
+
require_relative 'config/i18n'
|
6
|
+
require_relative 'lib/codebreaker_vk/uploader/uploader'
|
7
|
+
require_relative 'lib/codebreaker_vk/validate/validate'
|
8
|
+
require_relative 'lib/codebreaker_vk/validating_data'
|
9
|
+
require_relative 'lib/codebreaker_vk/check_errors'
|
10
|
+
require_relative 'lib/codebreaker_vk/difficulty'
|
11
|
+
require_relative 'lib/codebreaker_vk/game'
|
12
|
+
require_relative 'lib/codebreaker_vk/console'
|
13
|
+
require_relative 'lib/codebreaker_vk/game_user'
|
14
|
+
require_relative 'lib/codebreaker_vk/game_messages'
|
15
|
+
require_relative 'lib/codebreaker_vk/game_process'
|
16
|
+
require_relative 'lib/codebreaker_vk/version'
|
Binary file
|
data/codebreaker_vk.gemspec
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path(
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require
|
5
|
+
require 'codebreaker_vk/version'
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name =
|
8
|
+
spec.name = 'codebreaker_vk'
|
9
9
|
spec.version = CodebreakerVk::VERSION
|
10
|
-
spec.authors = [
|
10
|
+
spec.authors = ['VKuzmich']
|
11
11
|
spec.email = ["vjk1976@ukr.net"]
|
12
12
|
|
13
13
|
spec.summary = 'Codebreaker game'
|
@@ -15,15 +15,12 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.homepage = 'https://github.com/VKuzmich/codebreaker_vk'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|
18
|
-
|
19
|
-
# Specify which files should be added to the gem when it is released.
|
20
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
18
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
22
19
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
20
|
end
|
24
|
-
spec.bindir =
|
21
|
+
spec.bindir = 'exe'
|
25
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
-
spec.require_paths = [
|
23
|
+
spec.require_paths = ['lib']
|
27
24
|
|
28
25
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
29
26
|
spec.add_development_dependency 'fasterer', '~> 0.5.1'
|
data/config/i18n.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
en:
|
2
|
+
goodbye: 'Goodbye'
|
3
|
+
console:
|
4
|
+
greeting: "Hello, lets play the 'Codebreaker' game"
|
5
|
+
choose_the_command: "Choose the command\n
|
6
|
+
-Enter %{rules} if you want to see rules of the game\n
|
7
|
+
-Enter %{stats} if you want to see the statistics of users results\n
|
8
|
+
-Enter %{start} if you want to start the game\n
|
9
|
+
-Enter %{exit} if you want to quite the game\n"
|
10
|
+
what_name: "What is your name?\nName must be from 3 to 20 characters"
|
11
|
+
showed_hint: 'Code contains this number: %{showed}'
|
12
|
+
zero_hints: "You don't have any hints"
|
13
|
+
result: 'Your result is %{result}'
|
14
|
+
make_guess: "Make your guess\nYou need to enter four numbers between 1 and 6 "
|
15
|
+
enter_hint: "Or enter 'hint' to open one digit from code"
|
16
|
+
left_attempts_and_hints: "You have %{attempts} attempts and %{hints} hints"
|
17
|
+
win: "You win\n-Enter %{yes} if you want to save your progress"
|
18
|
+
lose: 'Game over, you lose if you want you can start a new game'
|
19
|
+
empty_db: 'You are the first one'
|
20
|
+
select_difficulty: 'Select difficulty: %{difficulties}'
|
21
|
+
stats_user_info: "%{position}) Name: %{name} difficulty: %{level}\n"
|
22
|
+
stats_lefts: "Attempts: %{all_attempts}/%{attempts} Hints: %{all_hints}/%{hints}"
|
23
|
+
rules: "Game Rules\n
|
24
|
+
• Codebreaker is a logic game in which a code-breaker tries to break a secret code created by a code-maker. The codemaker, which will be played by the codebreaker_vk we’re going to write, creates a secret code of four numbers between 1 and 6.\n
|
25
|
+
• The codebreaker gets some number of chances to break the code (depends on chosen difficulty). In each turn, the codebreaker makes a guess of 4 numbers. The codemaker then marks the guess with up to 4 signs - + or - or empty spaces.\n
|
26
|
+
• A + indicates an exact match - one of the numbers in the guess is the same as one of the numbers in the secret code and in the same position. For example\n
|
27
|
+
Secret number - 1234\n
|
28
|
+
Input number - 6264\n
|
29
|
+
Number of pluses - 2 (second and fourth position)\n
|
30
|
+
• A - indicates a number match - one of the numbers in the guess is the same as one of the numbers in the secret code but in a different position. For example\n
|
31
|
+
Secret number - 1234\n
|
32
|
+
Input number - 6462\n
|
33
|
+
Number of minuses - 2 (second and fourth position)\n
|
34
|
+
• An empty space indicates that there is not a current digit in a secret number.\n
|
35
|
+
• If codebreaker inputs the exact number as a secret number - codebreaker wins the game. If all attempts are spent - codebreaker loses.\n
|
36
|
+
• Codebreaker also has some number of hints(depends on chosen difficulty). If a user takes a hint - he receives back a separate digit of the secret code.\n"
|
37
|
+
error: "Unexpected input, it was '%{error}', try one more time"
|
38
|
+
invalid:
|
39
|
+
cover_error: 'Improper size'
|
40
|
+
include_error: 'Not include in propose inputs'
|
41
|
+
size_error: 'Invalid size'
|
data/lib/codebreaker_vk.rb
CHANGED
@@ -1,11 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'codebreaker_vk/game'
|
4
|
-
require_relative 'codebreaker_vk/game_process'
|
5
|
-
require_relative 'codebreaker_vk/errors/autoload'
|
6
3
|
require_relative 'codebreaker_vk/version'
|
7
|
-
|
8
|
-
module CodebreakerVk
|
9
|
-
class Error < StandardError; end
|
10
|
-
# Your code goes here...
|
11
|
-
end
|
4
|
+
require_relative '../autoload'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class CheckErrors < ValidatingData
|
5
|
+
attr_reader :input, :errors
|
6
|
+
|
7
|
+
def initialize(input)
|
8
|
+
super()
|
9
|
+
@input = input
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate
|
13
|
+
@errors << I18n.t('invalid.include_error') unless check_include?(@input, Console::COMMANDS.values)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class Console < ValidatingData
|
5
|
+
include Uploader
|
6
|
+
|
7
|
+
ACCEPT_SAVING_RESULT = 'yes'
|
8
|
+
COMMANDS = { rules: 'rules',
|
9
|
+
start: 'start',
|
10
|
+
stats: 'stats',
|
11
|
+
exit: 'exit' }.freeze
|
12
|
+
|
13
|
+
def greeting
|
14
|
+
Representer.greeting_msg
|
15
|
+
end
|
16
|
+
|
17
|
+
def main_menu
|
18
|
+
loop do
|
19
|
+
Representer.what_next_text
|
20
|
+
case make_valid_input_for_class(Navigator).input
|
21
|
+
when COMMANDS[:start] then return registration
|
22
|
+
when COMMANDS[:rules] then Representer.show_rules
|
23
|
+
when COMMANDS[:stats] then statistics
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def statistics
|
31
|
+
loaded_db = load_db
|
32
|
+
loaded_db.empty? ? Representer.empty_db_msg : Representer.show_db(loaded_db)
|
33
|
+
end
|
34
|
+
|
35
|
+
def registration
|
36
|
+
Representer.what_name_msg
|
37
|
+
@user = make_valid_input_for_class(User)
|
38
|
+
@difficulty = choose_difficulty
|
39
|
+
@game = Game.new(@difficulty, @user)
|
40
|
+
make_guess
|
41
|
+
end
|
42
|
+
|
43
|
+
def choose_difficulty
|
44
|
+
Representer.select_difficulty_msg
|
45
|
+
loop do
|
46
|
+
finded_level = Difficulty.find(user_input)
|
47
|
+
return finded_level if finded_level
|
48
|
+
|
49
|
+
Representer.error_msg(I18n.t('invalid.include_error'))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def make_guess
|
54
|
+
loop do
|
55
|
+
Representer.make_guess_msg
|
56
|
+
guess = make_valid_input_for_class(Guess)
|
57
|
+
guess.hint? ? show_hint : check_round_result(guess.as_array_of_numbers)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_round_result(guess)
|
62
|
+
return win if @game.win?(guess)
|
63
|
+
return lose if @game.lose?(guess)
|
64
|
+
|
65
|
+
round_result = @game.start_round(guess)
|
66
|
+
Representer.round_info_text(round_result, @game.attempts, @game.hints)
|
67
|
+
end
|
68
|
+
|
69
|
+
def show_hint
|
70
|
+
@game.hints.positive? ? Representer.showed_hint_msg(@game.hint) : Representer.zero_hints_msg
|
71
|
+
end
|
72
|
+
|
73
|
+
def lose
|
74
|
+
Representer.lose_msg
|
75
|
+
start_new_game
|
76
|
+
end
|
77
|
+
|
78
|
+
def win
|
79
|
+
Representer.win_msg
|
80
|
+
save_result if user_input == ACCEPT_SAVING_RESULT
|
81
|
+
start_new_game
|
82
|
+
end
|
83
|
+
|
84
|
+
def start_new_game
|
85
|
+
Console.new.main_menu
|
86
|
+
end
|
87
|
+
|
88
|
+
def save_result
|
89
|
+
save_to_db(@game.to_h)
|
90
|
+
end
|
91
|
+
|
92
|
+
def make_valid_input_for_class(klass)
|
93
|
+
loop do
|
94
|
+
input = klass.new(user_input)
|
95
|
+
return input if input.valid?
|
96
|
+
|
97
|
+
Representer.error_msg(input.errors.join(', '))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def user_input
|
102
|
+
input = gets.chomp.downcase
|
103
|
+
input == COMMANDS[:exit] ? exit_console : input
|
104
|
+
end
|
105
|
+
|
106
|
+
def exit_console
|
107
|
+
Representer.goodbye
|
108
|
+
exit
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class Difficulty
|
5
|
+
attr_reader :level
|
6
|
+
|
7
|
+
DIFFICULTIES = {
|
8
|
+
simple: {
|
9
|
+
hints: 2,
|
10
|
+
attempts: 15,
|
11
|
+
level: 'simple'
|
12
|
+
},
|
13
|
+
|
14
|
+
middle: {
|
15
|
+
hints: 1,
|
16
|
+
attempts: 10,
|
17
|
+
level: 'middle'
|
18
|
+
},
|
19
|
+
|
20
|
+
hard: {
|
21
|
+
hints: 1,
|
22
|
+
attempts: 5,
|
23
|
+
level: 'hard'
|
24
|
+
}
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
def initialize(input)
|
28
|
+
@level = DIFFICULTIES[input]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.find(input)
|
32
|
+
input_as_key = input.to_sym
|
33
|
+
return unless DIFFICULTIES.key?(input_as_key)
|
34
|
+
|
35
|
+
new(input_as_key)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/codebreaker_vk/game.rb
CHANGED
@@ -1,89 +1,82 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'config'
|
4
|
-
|
5
3
|
module CodebreakerVk
|
6
4
|
class Game
|
7
|
-
attr_reader :
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
|
18
|
-
@
|
19
|
-
@
|
20
|
-
|
21
|
-
@
|
22
|
-
|
23
|
-
@matches = ''
|
5
|
+
attr_reader :hints, :attempts, :difficulty, :breaker_numbers, :showed_hints, :player_name
|
6
|
+
|
7
|
+
INCLUDE_IN_GAME_NUMBERS = (1..6).freeze
|
8
|
+
CODE_SIZE = 4
|
9
|
+
|
10
|
+
GUESS_PLACE = '+'
|
11
|
+
GUESS_PRESENCE = '-'
|
12
|
+
|
13
|
+
def initialize(difficulty, user)
|
14
|
+
@breaker_numbers = generate_random_code
|
15
|
+
@breaker_numbers_copy = @breaker_numbers.clone.shuffle
|
16
|
+
@hints = difficulty.level[:hints]
|
17
|
+
@attempts = difficulty.level[:attempts]
|
18
|
+
@difficulty = difficulty.level
|
19
|
+
@player_name = user.name
|
20
|
+
@showed_hints = []
|
24
21
|
end
|
25
22
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@tries_count -= 1
|
32
|
-
|
33
|
-
resolver = GameProcess.new(@secret, input)
|
34
|
-
|
35
|
-
@matches = resolver.matches
|
23
|
+
def start_round(user_input)
|
24
|
+
@attempts -= 1
|
25
|
+
@game_numbers = { code: @breaker_numbers.clone, input: user_input }
|
26
|
+
collect_place_guess + collect_presence_guess
|
36
27
|
end
|
37
28
|
|
38
|
-
def
|
39
|
-
return
|
40
|
-
|
41
|
-
index = @hint_indexes.sample
|
42
|
-
|
43
|
-
hint = @secret[index]
|
29
|
+
def hint
|
30
|
+
return if @hints.zero?
|
44
31
|
|
45
|
-
@
|
46
|
-
|
47
|
-
@
|
48
|
-
|
49
|
-
hint
|
32
|
+
@hints -= 1
|
33
|
+
@showed_hints << @breaker_numbers_copy.pop
|
34
|
+
@showed_hints.last
|
50
35
|
end
|
51
36
|
|
52
|
-
def win?
|
53
|
-
@
|
37
|
+
def win?(result)
|
38
|
+
@breaker_numbers == result
|
54
39
|
end
|
55
40
|
|
56
|
-
def lose?
|
57
|
-
@
|
41
|
+
def lose?(result)
|
42
|
+
@attempts == 1 && @breaker_numbers != result
|
58
43
|
end
|
59
44
|
|
60
|
-
def
|
45
|
+
def to_h
|
61
46
|
{
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
47
|
+
player_name: @player_name,
|
48
|
+
level: @difficulty[:level],
|
49
|
+
all_hints: @difficulty[:hints],
|
50
|
+
all_attempts: @difficulty[:attempts],
|
51
|
+
left_hints: @hints,
|
52
|
+
left_attempts: @attempts,
|
53
|
+
date: Time.now
|
68
54
|
}
|
69
55
|
end
|
70
56
|
|
71
57
|
private
|
72
58
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
59
|
+
def collect_place_guess
|
60
|
+
@game_numbers[:input].map.with_index do |user_num, index|
|
61
|
+
next if @game_numbers[:code][index] != user_num
|
76
62
|
|
77
|
-
|
78
|
-
|
63
|
+
@game_numbers[:code][index] = nil
|
64
|
+
@game_numbers[:input][index] = nil
|
65
|
+
GUESS_PLACE
|
66
|
+
end.compact
|
79
67
|
end
|
80
68
|
|
81
|
-
def
|
82
|
-
input.
|
69
|
+
def collect_presence_guess
|
70
|
+
@game_numbers[:input].compact.map do |user_num|
|
71
|
+
next unless @game_numbers[:code].include?(user_num)
|
72
|
+
|
73
|
+
@game_numbers[:code].delete_at(@game_numbers[:code].index(user_num))
|
74
|
+
GUESS_PRESENCE
|
75
|
+
end.compact
|
83
76
|
end
|
84
77
|
|
85
|
-
def
|
86
|
-
|
78
|
+
def generate_random_code
|
79
|
+
Array.new(CODE_SIZE) { rand(INCLUDE_IN_GAME_NUMBERS) }
|
87
80
|
end
|
88
81
|
end
|
89
|
-
end
|
82
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class GameMessages
|
5
|
+
class << self
|
6
|
+
def greeting_msg
|
7
|
+
puts I18n.t('console.greeting')
|
8
|
+
end
|
9
|
+
|
10
|
+
def goodbye
|
11
|
+
puts I18n.t(:goodbye)
|
12
|
+
end
|
13
|
+
|
14
|
+
def what_next_text
|
15
|
+
puts I18n.t('console.choose_the_command', stats: Console::COMMANDS[:stats], rules: Console::COMMANDS[:rules],
|
16
|
+
start: Console::COMMANDS[:start], exit: Console::COMMANDS[:exit])
|
17
|
+
end
|
18
|
+
|
19
|
+
def what_name_msg
|
20
|
+
puts I18n.t('console.what_name')
|
21
|
+
end
|
22
|
+
|
23
|
+
def select_difficulty_msg
|
24
|
+
puts I18n.t('console.select_difficulty', difficulties: Difficulty::DIFFICULTIES.keys.join(', '))
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_guess_msg
|
28
|
+
puts I18n.t('console.make_guess')
|
29
|
+
end
|
30
|
+
|
31
|
+
def showed_hint_msg(showed)
|
32
|
+
puts I18n.t('console.showed_hint', showed: showed)
|
33
|
+
end
|
34
|
+
|
35
|
+
def zero_hints_msg
|
36
|
+
puts I18n.t('console.zero_hints')
|
37
|
+
end
|
38
|
+
|
39
|
+
def round_info_text(result, attempts, hints)
|
40
|
+
puts I18n.t('console.result', result: result)
|
41
|
+
puts I18n.t('console.left_attempts_and_hints', attempts: attempts, hints: hints)
|
42
|
+
puts I18n.t('console.make_guess')
|
43
|
+
puts I18n.t('console.enter_hint') if hints.positive?
|
44
|
+
end
|
45
|
+
|
46
|
+
def win_msg
|
47
|
+
puts I18n.t('console.win', yes: Console::ACCEPT_SAVING_RESULT)
|
48
|
+
end
|
49
|
+
|
50
|
+
def lose_msg
|
51
|
+
puts I18n.t('console.lose')
|
52
|
+
end
|
53
|
+
|
54
|
+
def empty_db_msg
|
55
|
+
puts I18n.t('console.empty_db')
|
56
|
+
end
|
57
|
+
|
58
|
+
def show_db(loaded_db)
|
59
|
+
sort_db(loaded_db).each_with_index do |user, index|
|
60
|
+
puts I18n.t('console.stats_user_info', position: index + 1, name: user[:name], level: user[:level])
|
61
|
+
puts I18n.t('console.stats_lefts', attempts: user[:left_attempts], all_attempts: user[:all_attempts],
|
62
|
+
hints: user[:left_hints], all_hints: user[:all_hints])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def show_rules
|
67
|
+
puts I18n.t('console.rules')
|
68
|
+
end
|
69
|
+
|
70
|
+
def error_msg(error)
|
71
|
+
puts I18n.t('error', error: error)
|
72
|
+
end
|
73
|
+
|
74
|
+
def sort_db(loaded_db)
|
75
|
+
loaded_db.sort_by { |user| [user[:all_attempts], -user[:left_attempts], -user[:left_hints]] }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -1,43 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'difficulty'
|
4
4
|
|
5
5
|
module CodebreakerVk
|
6
|
-
class GameProcess
|
7
|
-
attr_reader :
|
6
|
+
class GameProcess < ValidatingData
|
7
|
+
attr_reader :input, :errors
|
8
8
|
|
9
|
-
|
10
|
-
@secret_code = secret_code.clone
|
11
|
-
@user_code = user_code
|
9
|
+
HINT = 'hint'
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@matches = obtain_matches
|
11
|
+
def initialize(input)
|
12
|
+
super()
|
13
|
+
@input = input
|
17
14
|
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
def obtain_matches
|
22
|
-
calculate_matches unless @secret_code.empty?
|
16
|
+
def validate
|
17
|
+
return if hint?
|
23
18
|
|
24
|
-
|
19
|
+
@errors << I18n.t('invalid.include_error') unless check_numbers?(@input, valid_numbers)
|
20
|
+
@errors << I18n.t('invalid.size_error') unless check_size?(@input, Game::CODE_SIZE)
|
25
21
|
end
|
26
22
|
|
27
|
-
def
|
28
|
-
@
|
29
|
-
|
30
|
-
|
31
|
-
next add_match(user_code_number, exact: true) if secret_code_number == user_code_number
|
23
|
+
def as_array_of_numbers
|
24
|
+
@as_array_of_numbers ||= @input.chars.map(&:to_i)
|
25
|
+
end
|
32
26
|
|
33
|
-
|
34
|
-
|
27
|
+
def hint?
|
28
|
+
@input == HINT
|
35
29
|
end
|
36
30
|
|
37
|
-
|
38
|
-
exact ? @exact_matches += 1 : @number_matches += 1
|
31
|
+
private
|
39
32
|
|
40
|
-
|
33
|
+
def valid_numbers
|
34
|
+
Game::INCLUDE_IN_GAME_NUMBERS.map(&:to_s)
|
41
35
|
end
|
42
36
|
end
|
43
37
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class GameUser < ValidatingData
|
5
|
+
attr_reader :name, :errors
|
6
|
+
|
7
|
+
VALID_NAME_SIZE = (3..20).freeze
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
super()
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate
|
15
|
+
@errors << I18n.t('invalid.cover_error') unless check_cover?(@name, VALID_NAME_SIZE)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
module Uploader
|
5
|
+
PATH_FOLDER = './data_base/'
|
6
|
+
PATH_NAME = 'database'
|
7
|
+
PATH_FORMAT = '.yaml'
|
8
|
+
PATH = PATH_FOLDER + PATH_NAME + PATH_FORMAT
|
9
|
+
|
10
|
+
def load_db
|
11
|
+
File.exist?(PATH) ? YAML.load_stream(File.open(PATH)) : []
|
12
|
+
end
|
13
|
+
|
14
|
+
def save_to_db(results)
|
15
|
+
File.open(PATH, 'a') { |f| f.write results.to_yaml }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
module Validate
|
5
|
+
def check_cover?(cheackable, valid_numbers)
|
6
|
+
valid_numbers.cover?(cheackable.size)
|
7
|
+
end
|
8
|
+
|
9
|
+
def check_include?(cheackable, valid_collection)
|
10
|
+
valid_collection.include?(cheackable)
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_size?(cheackable, valid_size)
|
14
|
+
cheackable.size == valid_size
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_numbers?(cheackable, valid_numbers)
|
18
|
+
cheackable.each_char.all? { |guess_char| valid_numbers.include?(guess_char) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodebreakerVk
|
4
|
+
class ValidatingData
|
5
|
+
include Validate
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@errors = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
validate
|
17
|
+
@errors.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: codebreaker_vk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- VKuzmich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- ".gitignore"
|
162
162
|
- ".overcommit.yml"
|
163
163
|
- ".rspec"
|
164
|
+
- ".rubocop.yml"
|
164
165
|
- ".ruby-gemset"
|
165
166
|
- ".travis.yml"
|
166
167
|
- CODE_OF_CONDUCT.md
|
@@ -169,21 +170,28 @@ files:
|
|
169
170
|
- LICENSE.txt
|
170
171
|
- README.md
|
171
172
|
- Rakefile
|
173
|
+
- autoload.rb
|
172
174
|
- bin/console
|
173
175
|
- bin/setup
|
174
176
|
- codebreaker_vk-0.1.0.gem
|
175
177
|
- codebreaker_vk-0.2.0.gem
|
176
178
|
- codebreaker_vk-0.2.1.gem
|
177
179
|
- codebreaker_vk-0.2.2.gem
|
180
|
+
- codebreaker_vk-0.2.3.gem
|
178
181
|
- codebreaker_vk.gemspec
|
182
|
+
- config/i18n.rb
|
183
|
+
- config/locales/en.yml
|
179
184
|
- lib/codebreaker_vk.rb
|
180
|
-
- lib/codebreaker_vk/
|
181
|
-
- lib/codebreaker_vk/
|
182
|
-
- lib/codebreaker_vk/
|
183
|
-
- lib/codebreaker_vk/errors/format_error.rb
|
184
|
-
- lib/codebreaker_vk/errors/max_hint_error.rb
|
185
|
+
- lib/codebreaker_vk/check_errors.rb
|
186
|
+
- lib/codebreaker_vk/console.rb
|
187
|
+
- lib/codebreaker_vk/difficulty.rb
|
185
188
|
- lib/codebreaker_vk/game.rb
|
189
|
+
- lib/codebreaker_vk/game_messages.rb
|
186
190
|
- lib/codebreaker_vk/game_process.rb
|
191
|
+
- lib/codebreaker_vk/game_user.rb
|
192
|
+
- lib/codebreaker_vk/uploader/uploader.rb
|
193
|
+
- lib/codebreaker_vk/validate/validate.rb
|
194
|
+
- lib/codebreaker_vk/validating_data.rb
|
187
195
|
- lib/codebreaker_vk/version.rb
|
188
196
|
homepage: https://github.com/VKuzmich/codebreaker_vk
|
189
197
|
licenses:
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CodebreakerVk
|
4
|
-
CODE_LENGTH = 4
|
5
|
-
|
6
|
-
EXACT_MATCH_SIGN = '+'
|
7
|
-
NUMBER_MATCH_SIGN = '-'
|
8
|
-
|
9
|
-
MIN_CODE_NUMBER = 1
|
10
|
-
MAX_CODE_NUMBER = 6
|
11
|
-
|
12
|
-
DIFFICULTIES = {
|
13
|
-
easy: { tries: 15, hints: 2 },
|
14
|
-
medium: { tries: 10, hints: 1 },
|
15
|
-
hell: { tries: 5, hints: 1 }
|
16
|
-
}.freeze
|
17
|
-
end
|