codebreaker_Shkidchenko 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6c5c06df49bb80367c749333a9110133da2372a9511c94e5b0109ae3bb4cb016
4
+ data.tar.gz: 12306c6cbf5a127bdcf4a4cc259cc9aa73feaae980da9d1d17ccdd14fbfd715a
5
+ SHA512:
6
+ metadata.gz: 69d5376b28f8f33f419f6a55a49b5c91dd2d71a8222eda03e674afe68afb6c8a06d5fff17c93b0d02ce8d66fed47ede37be7ccdbd1a86de80226861eed2888a4
7
+ data.tar.gz: 6f270583d11ee1a55fd0714dc39de6f6f010896a10b3867b0b1d2be5e4fa6efb7d107bccba85fb215583e88b91b7105dd818ae8368b012dadcbba7f352d7c909
@@ -0,0 +1,47 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ - image: circleci/ruby:2.5.1-node-browsers
10
+
11
+ working_directory: ~/repo
12
+
13
+ steps:
14
+ - checkout
15
+
16
+ # Download and cache dependencies
17
+ - restore_cache:
18
+ keys:
19
+ - v1-dependencies-{{ checksum "Gemfile.lock" }}
20
+ # fallback to using the latest cache if no exact match is found
21
+ - v1-dependencies-
22
+
23
+ - run:
24
+ name: install dependencies
25
+ command: |
26
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
27
+ - save_cache:
28
+ paths:
29
+ - ./vendor/bundle
30
+ key: v1-dependencies-{{ checksum "Gemfile.lock" }}
31
+
32
+ - run:
33
+ name: run tests
34
+ command: |
35
+ mkdir /tmp/test-results
36
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
37
+
38
+ bundle exec rspec --format progress \
39
+ --out /tmp/test-results/rspec.xml \
40
+ --format progress \
41
+ $TEST_FILES
42
+ # collect reports
43
+ - store_test_results:
44
+ path: /tmp/test-results
45
+ - store_artifacts:
46
+ path: /tmp/test-results
47
+ destination: test-results
data/.fasterer.yml ADDED
@@ -0,0 +1,19 @@
1
+ speedups:
2
+ rescue_vs_respond_to: true
3
+ module_eval: true
4
+ shuffle_first_vs_sample: true
5
+ for_loop_vs_each: true
6
+ each_with_index_vs_while: false
7
+ map_flatten_vs_flat_map: true
8
+ reverse_each_vs_reverse_each: true
9
+ select_first_vs_detect: true
10
+ sort_vs_sort_by: true
11
+ fetch_with_argument_vs_block: true
12
+ keys_each_vs_each_key: true
13
+ hash_merge_bang_vs_hash_brackets: true
14
+ block_vs_symbol_to_proc: true
15
+ proc_call_vs_yield: true
16
+ gsub_vs_tr: true
17
+ select_last_vs_reverse_detect: true
18
+ getter_vs_attr_reader: true
19
+ setter_vs_attr_writer: true
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ coverage
2
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ require: rubocop-rspec
2
+
3
+ Metrics/LineLength:
4
+ Max: 120
5
+
6
+ Documentation:
7
+ Enabled: false
8
+
9
+ Metrics/BlockLength:
10
+ ExcludedMethods: ['describe']
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in codebreaker.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,82 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ codebreaker_rack (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ coderay (1.1.2)
11
+ colorize (0.8.1)
12
+ concurrent-ruby (1.1.4)
13
+ diff-lcs (1.3)
14
+ docile (1.3.1)
15
+ fasterer (0.4.1)
16
+ colorize (~> 0.7)
17
+ ruby_parser (~> 3.11.0)
18
+ i18n (1.2.0)
19
+ concurrent-ruby (~> 1.0)
20
+ jaro_winkler (1.5.1)
21
+ json (2.1.0)
22
+ method_source (0.9.2)
23
+ parallel (1.12.1)
24
+ parser (2.5.3.0)
25
+ ast (~> 2.4.0)
26
+ powerpack (0.1.2)
27
+ pry (0.12.2)
28
+ coderay (~> 1.1.0)
29
+ method_source (~> 0.9.0)
30
+ rainbow (3.0.0)
31
+ rake (10.5.0)
32
+ rspec (3.8.0)
33
+ rspec-core (~> 3.8.0)
34
+ rspec-expectations (~> 3.8.0)
35
+ rspec-mocks (~> 3.8.0)
36
+ rspec-core (3.8.0)
37
+ rspec-support (~> 3.8.0)
38
+ rspec-expectations (3.8.2)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.8.0)
41
+ rspec-mocks (3.8.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.8.0)
44
+ rspec-support (3.8.0)
45
+ rubocop (0.61.1)
46
+ jaro_winkler (~> 1.5.1)
47
+ parallel (~> 1.10)
48
+ parser (>= 2.5, != 2.5.1.1)
49
+ powerpack (~> 0.1)
50
+ rainbow (>= 2.2.2, < 4.0)
51
+ ruby-progressbar (~> 1.7)
52
+ unicode-display_width (~> 1.4.0)
53
+ rubocop-rspec (1.30.1)
54
+ rubocop (>= 0.60.0)
55
+ ruby-progressbar (1.10.0)
56
+ ruby_parser (3.11.0)
57
+ sexp_processor (~> 4.9)
58
+ sexp_processor (4.11.0)
59
+ simplecov (0.16.1)
60
+ docile (~> 1.1)
61
+ json (>= 1.8, < 3)
62
+ simplecov-html (~> 0.10.0)
63
+ simplecov-html (0.10.2)
64
+ unicode-display_width (1.4.0)
65
+
66
+ PLATFORMS
67
+ ruby
68
+
69
+ DEPENDENCIES
70
+ bundler (~> 1.16)
71
+ codebreaker_rack!
72
+ fasterer
73
+ i18n
74
+ pry
75
+ rake (~> 10.0)
76
+ rspec (~> 3.0)
77
+ rubocop
78
+ rubocop-rspec
79
+ simplecov
80
+
81
+ BUNDLED WITH
82
+ 1.17.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 IgorShkidchenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ [![Maintainability](https://api.codeclimate.com/v1/badges/826fb86917afb95e0b3a/maintainability)](https://codeclimate.com/github/IgorShkidchenko/rg_codebreaker/maintainability)
2
+ [![CircleCI](https://circleci.com/gh/IgorShkidchenko/rg_codebreaker/tree/develop.svg?style=svg)](https://circleci.com/gh/IgorShkidchenko/rg_codebreaker/tree/develop)
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/autoload.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'i18n'
4
+ require 'yaml'
5
+ require_relative './config/i18n'
6
+ require_relative './lib/app/modules/uploader/uploader'
7
+ require_relative './lib/app/modules/validator/validator'
8
+ require_relative './lib/app/entities/validatable_entity'
9
+ require_relative './lib/app/entities/navigator'
10
+ require_relative './lib/app/entities/representer'
11
+ require_relative './lib/app/entities/game'
12
+ require_relative './lib/app/entities/console'
13
+ require_relative './lib/app/entities/user'
14
+ require_relative './lib/app/entities/difficulty'
15
+ require_relative './lib/app/entities/guess'
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'codebreaker'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'codebreaker/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'codebreaker_Shkidchenko'
9
+ spec.version = Codebreaker::VERSION
10
+ spec.authors = ['IgorShkidchenko']
11
+ spec.email = ['igorshkidchenko@gmail.com']
12
+
13
+ spec.summary = 'RubyGarage HW'
14
+ spec.description = 'Logic game'
15
+ spec.homepage = 'https://github.com/IgorShkidchenko/rg_codebreaker'
16
+ spec.license = 'MIT'
17
+
18
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
19
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
+ else
23
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
24
+ 'public gem pushes.'
25
+ end
26
+
27
+ # Specify which files should be added to the gem when it is released.
28
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
29
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
30
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
31
+ end
32
+ spec.bindir = 'exe'
33
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ['lib']
35
+
36
+ spec.add_development_dependency 'bundler', '~> 1.16'
37
+ spec.add_development_dependency 'fasterer'
38
+ spec.add_development_dependency 'i18n'
39
+ spec.add_development_dependency 'pry'
40
+ spec.add_development_dependency 'rake', '~> 10.0'
41
+ spec.add_development_dependency 'rspec', '~> 3.0'
42
+ spec.add_development_dependency 'rubocop'
43
+ spec.add_development_dependency 'rubocop-rspec'
44
+ spec.add_development_dependency 'simplecov'
45
+ end
data/config/i18n.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ I18n.load_path << Dir[File.expand_path('locales') + '/*.yml']
File without changes
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Console < ValidatableEntity
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 Codebreaker
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
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
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 = []
21
+ end
22
+
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
27
+ end
28
+
29
+ def hint
30
+ return if @hints.zero?
31
+
32
+ @hints -= 1
33
+ @showed_hints << @breaker_numbers_copy.pop
34
+ @showed_hints.last
35
+ end
36
+
37
+ def win?(result)
38
+ @breaker_numbers == result
39
+ end
40
+
41
+ def lose?(result)
42
+ @attempts == 1 && @breaker_numbers != result
43
+ end
44
+
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
+ }
55
+ end
56
+
57
+ private
58
+
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
62
+
63
+ @game_numbers[:code][index] = nil
64
+ @game_numbers[:input][index] = nil
65
+ GUESS_PLACE
66
+ end.compact
67
+ end
68
+
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
76
+ end
77
+
78
+ def generate_random_code
79
+ Array.new(CODE_SIZE) { rand(INCLUDE_IN_GAME_NUMBERS) }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Guess < ValidatableEntity
5
+ attr_reader :input, :errors
6
+
7
+ HINT = 'hint'
8
+
9
+ def initialize(input)
10
+ super()
11
+ @input = input
12
+ end
13
+
14
+ def validate
15
+ return if hint?
16
+
17
+ @errors << I18n.t('invalid.include_error') unless check_numbers?(@input, valid_numbers)
18
+ @errors << I18n.t('invalid.size_error') unless check_size?(@input, Game::CODE_SIZE)
19
+ end
20
+
21
+ def as_array_of_numbers
22
+ @as_array_of_numbers ||= @input.chars.map(&:to_i)
23
+ end
24
+
25
+ def hint?
26
+ @input == HINT
27
+ end
28
+
29
+ private
30
+
31
+ def valid_numbers
32
+ Game::INCLUDE_IN_GAME_NUMBERS.map(&:to_s)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Navigator < ValidatableEntity
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,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Representer
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', difficults: 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
+ private
75
+
76
+ def sort_db(loaded_db)
77
+ loaded_db.sort_by { |user| [user[:all_attempts], -user[:left_attempts], -user[:left_hints]] }
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class User < ValidatableEntity
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,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class ValidatableEntity
5
+ include Validator
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
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
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
+ 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 Codebreaker
4
+ module Validator
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,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'codebreaker/version'
4
+ require_relative '../autoload'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ VERSION = '0.1.0'
5
+ end
data/locales/en.yml 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: %{difficults}'
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 application 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/main.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'autoload'
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: codebreaker_Shkidchenko
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - IgorShkidchenko
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fasterer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: i18n
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Logic game
140
+ email:
141
+ - igorshkidchenko@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".circleci/config.yml"
147
+ - ".fasterer.yml"
148
+ - ".gitignore"
149
+ - ".rspec"
150
+ - ".rubocop.yml"
151
+ - ".ruby-version"
152
+ - Gemfile
153
+ - Gemfile.lock
154
+ - LICENSE.txt
155
+ - README.md
156
+ - Rakefile
157
+ - autoload.rb
158
+ - bin/console
159
+ - bin/setup
160
+ - codebreaker.gemspec
161
+ - config/i18n.rb
162
+ - data_base/database.yaml
163
+ - lib/app/entities/console.rb
164
+ - lib/app/entities/difficulty.rb
165
+ - lib/app/entities/game.rb
166
+ - lib/app/entities/guess.rb
167
+ - lib/app/entities/navigator.rb
168
+ - lib/app/entities/representer.rb
169
+ - lib/app/entities/user.rb
170
+ - lib/app/entities/validatable_entity.rb
171
+ - lib/app/modules/uploader/uploader.rb
172
+ - lib/app/modules/validator/validator.rb
173
+ - lib/codebreaker.rb
174
+ - lib/codebreaker/version.rb
175
+ - locales/en.yml
176
+ - main.rb
177
+ homepage: https://github.com/IgorShkidchenko/rg_codebreaker
178
+ licenses:
179
+ - MIT
180
+ metadata:
181
+ allowed_push_host: https://rubygems.org
182
+ post_install_message:
183
+ rdoc_options: []
184
+ require_paths:
185
+ - lib
186
+ required_ruby_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ required_rubygems_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ requirements: []
197
+ rubygems_version: 3.0.1
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: RubyGarage HW
201
+ test_files: []