codebreaker_vk 0.3.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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