codebreaker_vk 0.3.1 → 1.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '08ab1117ccd9224ff33761dce7aa30a1cd572e67001b7e58b9499b9c3af850b5'
4
- data.tar.gz: 90ffb5d6bbe399a0a762b6828bd202496818871d714dff4a6716d95e15280163
3
+ metadata.gz: ce6a637c137f2f28c5b4abb77c15dea5b45e9fc642a33a9f7e9cf4e811962df5
4
+ data.tar.gz: e0f628cce3aa5f7d64ec3f65e8971c5890e573fcb1e3c212bb02e544c74c789c
5
5
  SHA512:
6
- metadata.gz: 3ca02359a5f01b2cafbb9e9ce3b1724dbe1a0014b994a9e81f931961089e2c188d7f3e2c4ee4cbdc3772f4e09938d59ea7ea1b4e377281e14156280d88450713
7
- data.tar.gz: 92b9a4df7cc29020a358499c560b3a427f4a07ca07eb2178acc3ebc2497dd1d4005bcda269d5b3e0faea8a9a26ebd0125ede18aaf8bf6ca9a8aeb74fbf5d0267
6
+ metadata.gz: 03ed7c6c1f1e7030416eeed769a1f36c30766b09246549095f89d53963c7a616dcfb52dfc0812aec5e023516f11c68e694b6eba41051a2ebb595a9ef7a2836c1
7
+ data.tar.gz: 124cd40776dfe7f387794d4eadb5b24a5072da6b57c73a83e8010cd5668798ed4ebb2d09ded52bcb161ca23db7788fd8aa80d5f5ea8d8935df9901aa248bca6f
data/.fasterer.yml CHANGED
File without changes
data/.gitignore CHANGED
File without changes
data/.overcommit.yml CHANGED
@@ -37,7 +37,7 @@ PreCommit:
37
37
  enabled: true
38
38
 
39
39
  BundleAudit:
40
- enabled: true
40
+ enabled: false
41
41
 
42
42
  RSpec:
43
43
  enabled: true
data/.rspec CHANGED
File without changes
data/.rubocop.yml CHANGED
File without changes
data/.ruby-gemset CHANGED
File without changes
data/.travis.yml CHANGED
File without changes
data/CODE_OF_CONDUCT.md CHANGED
File without changes
data/Gemfile CHANGED
File without changes
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- codebreaker_vk (0.3.1)
4
+ codebreaker_vk (1.0.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/LICENSE.txt CHANGED
File without changes
data/README.md CHANGED
File without changes
data/Rakefile CHANGED
File without changes
data/autoload.rb CHANGED
@@ -3,14 +3,14 @@
3
3
  require 'i18n'
4
4
  require 'yaml'
5
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'
6
+
7
+ require_relative 'lib/codebreaker_vk/validation'
8
+ require_relative 'lib/codebreaker_vk/output'
9
+ require_relative 'lib/codebreaker_vk/database'
11
10
  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'
11
+ require_relative 'lib/codebreaker_vk/game_console'
12
+ require_relative 'lib/codebreaker_vk/game_menu'
13
+ require_relative 'lib/codebreaker_vk/table_data'
14
+
15
+
16
16
  require_relative 'lib/codebreaker_vk/version'
File without changes
File without changes
File without changes
File without changes
data/config/i18n.rb CHANGED
File without changes
@@ -1,41 +1,38 @@
1
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'
2
+ greeting: "Welcome to codebreaker!\n"
3
+ goodbye: "Goodbye!\n"
4
+ rules: "GAME RULES\n
5
+ # Codebreaker is a logic game in which a code-breaker tries to break a secret code created by a code-maker. The\n codemaker, which will be played by the application we’re going to write, creates a secret code of four numbers between\n 1 and 6.\n
6
+ # The codebreaker gets some number of chances to break the code (depends on chosen difficulty). In each turn, the\n codebreaker makes a guess of 4 numbers. The codemaker then marks the guess with up to 4 signs - + or - or empty\n spaces.\n
7
+ # A + indicates an exact match: one of the numbers in the guess is the same as one of the numbers in the secret code\n and in the same position. For example:\n
8
+ Secret number - 1234\n
9
+ Input number - 6264\n
10
+ Number of pluses - 2 (second and fourth position)\n
11
+ # A - indicates a number match: one of the numbers in the guess is the same as one of the numbers in the secret code\n but in a different position. For example:\n
12
+ Secret number - 1234\n
13
+ Input number - 6462\n
14
+ Number of minuses - 2 (second and fourth position)\n
15
+ # An empty space indicates that there is not a current digit in a secret number.\n
16
+ # If codebreaker inputs the exact number as a secret number - codebreaker wins the game. If all attempts are spent -\n codebreaker loses.\n
17
+ # Codebreaker also has some number of hints(depends on chosen difficulty). If a user takes a hint - he receives back a\n
18
+ separate digit of the secret code.\n"
19
+ menu: "Choose one of next scenarios: 'start', 'rules', 'stats', 'exit'"
20
+ choose_difficulty: "Choose difficulty: easy, medium, hell"
21
+ choose_name: "Choose your name"
22
+ win: "Congratulations! You win!"
23
+ lose: "Sorry, you lose. Maybe another time."
24
+ wrong_difficulty: "There is no such difficulty. Please choose one from listed"
25
+ wrong_input: "wrong input"
26
+ wrong_name: "Choosen name is invalid. Name must be between 3 and 20 characters.\nPlease choose another one"
27
+ wrong_process: "There is no such command or your number is invalid. You can try use hint or exit"
28
+ wrong_run: "You have passed unexpected command. Please choose one from listed commands"
29
+ easy: "easy"
30
+ medium: "medium"
31
+ hell: "hell"
32
+ no_hints: "You have no hints"
33
+ game_process: "%{attempts} attempts and %{hints} hints left. Guess a secret code"
34
+ secret: "The secret code was %{secret}"
35
+ save: "Print 'save' if you want to save your result: "
36
+ game_over: 'Game Over'
37
+ stats: "Player %{name} played with difficulty level %{difficulty} (%{attempts_total} attempts, %{hints_total} hints) and won with %{attempts_used} attempts and %{hints_used} hints used."
38
+ no_stats: "Sorry, you have not any saves yet."
data/database.yaml ADDED
@@ -0,0 +1,8 @@
1
+ ---
2
+ - !ruby/object:CodebreakerVk::TableData
3
+ name: trtr
4
+ difficulty: :easy
5
+ attempts_total: 15
6
+ attempts_used: 11
7
+ hints_total: 3
8
+ hints_used: 3
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodebreakerVk
4
+ module Database
5
+ SEED = 'database.yaml'
6
+
7
+ def load(path = SEED)
8
+ YAML.load_file(path)
9
+ end
10
+
11
+ def save(summary, path = SEED)
12
+ row = TableData.new(summary)
13
+ if File.exist?(path)
14
+ table = load(path)
15
+ table << row
16
+ File.write(path, table.to_yaml)
17
+ else
18
+ File.write(path, [row].to_yaml)
19
+ end
20
+ end
21
+
22
+ def save_results
23
+ attempts_total = Game::DIFFICULTY_LEVEL[@game.difficulty][:attempts]
24
+ hints_total = Game::DIFFICULTY_LEVEL[@game.difficulty][:hints]
25
+ summary = {
26
+ name: @game.name,
27
+ difficulty: @game.difficulty,
28
+ attempts_total: attempts_total,
29
+ attempts_used: attempts_total - @game.attempts,
30
+ hints_total: hints_total,
31
+ hints_used: hints_total - @game.hints
32
+ }
33
+ save(summary)
34
+ end
35
+ end
36
+ end
@@ -2,81 +2,74 @@
2
2
 
3
3
  module CodebreakerVk
4
4
  class Game
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 = []
5
+ include Output
6
+ SECRET_CODE_LENGTH = 4
7
+ RANGE_START = 1
8
+ RANGE_END = 6
9
+ NOT_YET = '-'
10
+ GOT_IT = '+'
11
+ DIFFICULTY_LEVEL = {
12
+ easy: { attempts: 15, hints: 3 },
13
+ medium: { attempts: 10, hints: 2 },
14
+ hell: { attempts: 5, hints: 1 }
15
+ }.freeze
16
+
17
+ attr_accessor :attempts_total, :attempts, :difficulty, :hints_total, :hints, :name, :secret
18
+
19
+ def initialize(name:, difficulty:)
20
+ @name = name
21
+ @difficulty = difficulty
22
+ @attempts = DIFFICULTY_LEVEL[difficulty][:attempts]
23
+ @hints = DIFFICULTY_LEVEL[difficulty][:hints]
24
+ @secret = make_number
25
+ @unused_hints = @secret.chars
21
26
  end
22
27
 
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
28
+ def make_number(numbers = RANGE_END)
29
+ (1..SECRET_CODE_LENGTH).map { rand(RANGE_START..numbers) }.join
27
30
  end
28
31
 
29
- def hint
30
- return if @hints.zero?
31
-
32
- @hints -= 1
33
- @showed_hints << @breaker_numbers_copy.pop
34
- @showed_hints.last
32
+ def check(number)
33
+ @attempts -= 1
34
+ @last_result = check_numbers(@secret.chars, number.chars)
35
35
  end
36
36
 
37
- def win?(result)
38
- @breaker_numbers == result
37
+ def win?
38
+ @last_result == GOT_IT * SECRET_CODE_LENGTH
39
39
  end
40
40
 
41
- def lose?(result)
42
- @attempts == 1 && @breaker_numbers != result
43
- end
41
+ def use_hint
42
+ return I18n.t(:no_hints) unless @hints.positive?
44
43
 
45
- def to_h
46
- {
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
54
- }
44
+ @hints -= 1
45
+ hint(@unused_hints)
55
46
  end
56
47
 
57
48
  private
58
49
 
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
50
+ def check_numbers(secret, numbers)
51
+ exact_matches, non_exact_matches = secret.zip(numbers).partition do |secret_number, input_number|
52
+ secret_number == input_number
53
+ end
54
+
55
+ result = Array.new(exact_matches.count, GOT_IT)
56
+
57
+ find_non_exact_matches(result, non_exact_matches) if non_exact_matches.any?
62
58
 
63
- @game_numbers[:code][index] = nil
64
- @game_numbers[:input][index] = nil
65
- GUESS_PLACE
66
- end.compact
59
+ result.join
67
60
  end
68
61
 
69
- def collect_presence_guess
70
- @game_numbers[:input].compact.map do |user_num|
71
- next unless @game_numbers[:code].include?(user_num)
62
+ def find_non_exact_matches(result, non_exact_matches)
63
+ secret, numbers = non_exact_matches.transpose
64
+ numbers.each do |number_element|
65
+ next unless secret.include? number_element
72
66
 
73
- @game_numbers[:code].delete_at(@game_numbers[:code].index(user_num))
74
- GUESS_PRESENCE
75
- end.compact
67
+ result.push(NOT_YET) && secret.delete_at(secret.index(number_element))
68
+ end
76
69
  end
77
70
 
78
- def generate_random_code
79
- Array.new(CODE_SIZE) { rand(INCLUDE_IN_GAME_NUMBERS) }
71
+ def hint(secret)
72
+ secret.shuffle.pop
80
73
  end
81
74
  end
82
75
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodebreakerVk
4
+ class GameConsole
5
+ include Validation
6
+ include Database
7
+ include Output
8
+
9
+ HINT = 'hint'
10
+ SAVE = 'save'
11
+ INPUT_DATA = /^[1-6]{4}$/.freeze
12
+
13
+ def initialize(name, difficulty)
14
+ @game = Game.new(name: name, difficulty: difficulty)
15
+ end
16
+
17
+ def start
18
+ loop do
19
+ break if @game.attempts.zero? || @game.win?
20
+
21
+ start_info(@game.attempts, @game.hints)
22
+ input = gets.chomp
23
+ case input
24
+ when GameMenu::EXIT then break close
25
+ when HINT then next puts @game.use_hint
26
+ when INPUT_DATA then puts @game.check(input)
27
+ else puts I18n.t(:wrong_process)
28
+ end
29
+ end
30
+ puts I18n.t(:game_over)
31
+ statistics
32
+ end
33
+
34
+ def statistics
35
+ summary_info(@game.secret)
36
+ end_game
37
+ end
38
+
39
+ def end_game
40
+ if @game.win?
41
+ puts I18n.t(:win)
42
+ puts I18n.t(:save)
43
+ save_results if gets.chomp == SAVE
44
+ else
45
+ puts I18n.t(:lose)
46
+ end
47
+ end
48
+
49
+ def close
50
+ puts I18n.t(:goodbye)
51
+ exit
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'database'
4
+
5
+ module CodebreakerVk
6
+ class GameMenu
7
+ extend Validation
8
+ extend Database
9
+ extend Output
10
+
11
+ START = 'start'
12
+ RULES = 'rules'
13
+ STATISTICS = 'stats'
14
+ EXIT = 'exit'
15
+
16
+ class << self
17
+ def welcome
18
+ puts I18n.t(:greeting)
19
+ run
20
+ end
21
+
22
+ def run
23
+ loop do
24
+ puts I18n.t(:menu)
25
+ case gets.chomp
26
+ when START then break registration
27
+ when RULES then rules
28
+ when STATISTICS then stats
29
+ when EXIT then break close
30
+ else puts I18n.t(:wrong_run)
31
+ end
32
+ end
33
+ end
34
+
35
+ def registration
36
+ GameConsole.new(choose_name, choose_difficulty).start
37
+ welcome
38
+ end
39
+
40
+ def choose_name
41
+ loop do
42
+ puts I18n.t(:choose_name)
43
+ name = gets.chomp
44
+ break close if name == EXIT
45
+ break name if valid_string_length?(name)
46
+
47
+ puts I18n.t(:wrong_name)
48
+ end
49
+ end
50
+
51
+ def choose_difficulty
52
+ loop do
53
+ puts I18n.t(:choose_difficulty)
54
+ input = gets.chomp
55
+ break close if input == EXIT
56
+ break input.to_sym if Game::DIFFICULTY_LEVEL.keys.include? input.to_sym
57
+
58
+ puts I18n.t(:wrong_difficulty)
59
+ end
60
+ end
61
+
62
+ def stats
63
+ return puts I18n.t(:no_stats) unless File.exist?('./seed.yaml')
64
+
65
+ table = load.sort_by { |row| [row.hints_total, row.attempts_used] }
66
+ table.each { |row| row.difficulty = Game::DIFFICULTY_LEVEL.key([row.attempts_total, row.hints_total]) }
67
+ puts table
68
+ end
69
+
70
+ def close
71
+ puts I18n.t(:goodbye)
72
+ exit
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodebreakerVk
4
+ module Output
5
+ def start_info(attempts, hints)
6
+ puts I18n.t(:game_process, attempts: attempts, hints: hints)
7
+ end
8
+
9
+ def summary_info(secret)
10
+ puts I18n.t(:secret, secret: secret)
11
+ end
12
+
13
+ def rules
14
+ puts I18n.t(:rules)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodebreakerVk
4
+ class TableData
5
+ attr_accessor :name, :difficulty, :attempts_total, :attempts_used, :hints_total, :hints_used
6
+
7
+ def initialize(name:, difficulty:, attempts_total:, attempts_used:, hints_total:, hints_used:)
8
+ @name = name
9
+ @difficulty = difficulty
10
+ @attempts_total = attempts_total
11
+ @attempts_used = attempts_used
12
+ @hints_total = hints_total
13
+ @hints_used = hints_used
14
+ end
15
+
16
+ def to_s
17
+ I18n.t(:stats,
18
+ name: @name,
19
+ difficulty: @difficulty,
20
+ attempts_total: @attempts_total,
21
+ attempts_used: @attempts_used,
22
+ hints_total: @hints_total,
23
+ hints_used: @hints_used)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CodebreakerVk
4
+ module Validation
5
+ MIN_LETTERS = 3
6
+ MAX_LETTERS = 20
7
+
8
+ def valid_string_length?(name, min = MIN_LETTERS, max = MAX_LETTERS)
9
+ name.is_a?(String) && name.length.between?(min, max)
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CodebreakerVk
4
- VERSION = '0.3.1'
4
+ VERSION = '1.0.1'
5
5
  end
data/main.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'autoload'
4
+
5
+ CodebreakerVk::GameMenu.run
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.3.1
4
+ version: 1.0.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-07 00:00:00.000000000 Z
11
+ date: 2019-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -181,18 +181,17 @@ files:
181
181
  - codebreaker_vk.gemspec
182
182
  - config/i18n.rb
183
183
  - config/locales/en.yml
184
+ - database.yaml
184
185
  - lib/codebreaker_vk.rb
185
- - lib/codebreaker_vk/check_errors.rb
186
- - lib/codebreaker_vk/console.rb
187
- - lib/codebreaker_vk/difficulty.rb
186
+ - lib/codebreaker_vk/database.rb
188
187
  - lib/codebreaker_vk/game.rb
189
- - lib/codebreaker_vk/game_messages.rb
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
188
+ - lib/codebreaker_vk/game_console.rb
189
+ - lib/codebreaker_vk/game_menu.rb
190
+ - lib/codebreaker_vk/output.rb
191
+ - lib/codebreaker_vk/table_data.rb
192
+ - lib/codebreaker_vk/validation.rb
195
193
  - lib/codebreaker_vk/version.rb
194
+ - main.rb
196
195
  homepage: https://github.com/VKuzmich/codebreaker_vk
197
196
  licenses:
198
197
  - MIT
@@ -1,16 +0,0 @@
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
@@ -1,111 +0,0 @@
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
@@ -1,38 +0,0 @@
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
@@ -1,79 +0,0 @@
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,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'difficulty'
4
-
5
- module CodebreakerVk
6
- class GameProcess < ValidatingData
7
- attr_reader :input, :errors
8
-
9
- HINT = 'hint'
10
-
11
- def initialize(input)
12
- super()
13
- @input = input
14
- end
15
-
16
- def validate
17
- return if hint?
18
-
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)
21
- end
22
-
23
- def as_array_of_numbers
24
- @as_array_of_numbers ||= @input.chars.map(&:to_i)
25
- end
26
-
27
- def hint?
28
- @input == HINT
29
- end
30
-
31
- private
32
-
33
- def valid_numbers
34
- Game::INCLUDE_IN_GAME_NUMBERS.map(&:to_s)
35
- end
36
- end
37
- end
@@ -1,18 +0,0 @@
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
@@ -1,18 +0,0 @@
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
@@ -1,21 +0,0 @@
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
@@ -1,20 +0,0 @@
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