codebreaker_manfly 0.1.1 → 0.1.2

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: 712151060b79bacafe34e148dedc46708adacf8693e92dc1c7fc34a4c67d0acd
4
- data.tar.gz: 15b66fc81ee87dd9dc5d4e26b7b81ed007daa8f64e7b9255b8d1d3aa1595b458
3
+ metadata.gz: caf1cf44404ee764b74c32a9a2894f98bd2aa73b184ec73399a40a69c17f5165
4
+ data.tar.gz: 980294f275d01d27b699612232b017307c8d4272c2f73c3f7a8c3fab26398089
5
5
  SHA512:
6
- metadata.gz: 8e5b79427b3d0d997407b029d9edde67cb2bd797d95e3b9ba1f2059d5dd0d567cab514d23ce0df5a5505fdec9f670d1fb5a6b46c783a7d054ab76ff9dbf13a61
7
- data.tar.gz: '019a5fdb7dc2fe2292aec262226e1b843bb20cc4d57389e14eed40537dde74af30f1019791acb601689862977dfa3d53c6b94b20384e5d1c763311c4159377c3'
6
+ metadata.gz: 7277c3b2aa8a8ac2eea2c8c0aedeff2d4df7cc128364bbcd4636eeeed52694143848e42fd590c4fe3a6add886d5b730a02908c5696aea02f9f70ca0f3dec6f8b
7
+ data.tar.gz: b382f9504b6448445f2246d1af75a4cfe775897ff1ac39b0a8365dd17d696459915b2ff611e4b5095a097d459c2b6bcaaddf3ea353e5cd15386ae6c597aa254a
data/.rubocop.yml CHANGED
@@ -1,9 +1,13 @@
1
+
1
2
  AllCops:
2
3
  TargetRubyVersion: 2.7
3
4
 
4
5
  Style/Documentation:
5
6
  Enabled: false
6
7
 
8
+ Lint/UnreachableLoop:
9
+ Enabled: false
10
+
7
11
  Metrics/BlockLength:
8
12
  ExcludedMethods: ['describe', 'context']
9
13
 
data/Gemfile CHANGED
@@ -4,7 +4,3 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in codebreaker.gemspec
6
6
  gemspec
7
-
8
- gem 'rake', '~> 13.0'
9
- gem 'rspec', '~> 3.10'
10
- gem 'rubocop', '~> 1.7'
data/Gemfile.lock CHANGED
@@ -1,16 +1,31 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- codebreaker_manfly (0.1.1)
4
+ codebreaker_manfly (0.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  ast (2.4.2)
10
+ byebug (11.1.3)
11
+ coderay (1.1.3)
12
+ concurrent-ruby (1.1.9)
10
13
  diff-lcs (1.4.4)
14
+ docile (1.4.0)
15
+ faker (2.19.0)
16
+ i18n (>= 1.6, < 2)
17
+ i18n (1.8.10)
18
+ concurrent-ruby (~> 1.0)
19
+ method_source (1.0.0)
11
20
  parallel (1.21.0)
12
21
  parser (3.0.2.0)
13
22
  ast (~> 2.4.1)
23
+ pry (0.13.1)
24
+ coderay (~> 1.1)
25
+ method_source (~> 1.0)
26
+ pry-byebug (3.9.0)
27
+ byebug (~> 11.0)
28
+ pry (~> 0.13.0)
14
29
  rainbow (3.0.0)
15
30
  rake (13.0.6)
16
31
  regexp_parser (2.1.1)
@@ -28,7 +43,7 @@ GEM
28
43
  diff-lcs (>= 1.2.0, < 2.0)
29
44
  rspec-support (~> 3.10.0)
30
45
  rspec-support (3.10.2)
31
- rubocop (1.22.1)
46
+ rubocop (1.22.3)
32
47
  parallel (~> 1.10)
33
48
  parser (>= 3.0.0.0)
34
49
  rainbow (>= 2.2.2, < 4.0)
@@ -40,6 +55,12 @@ GEM
40
55
  rubocop-ast (1.12.0)
41
56
  parser (>= 3.0.1.1)
42
57
  ruby-progressbar (1.11.0)
58
+ simplecov (0.21.2)
59
+ docile (~> 1.1)
60
+ simplecov-html (~> 0.11)
61
+ simplecov_json_formatter (~> 0.1)
62
+ simplecov-html (0.12.3)
63
+ simplecov_json_formatter (0.1.3)
43
64
  unicode-display_width (2.1.0)
44
65
 
45
66
  PLATFORMS
@@ -47,9 +68,12 @@ PLATFORMS
47
68
 
48
69
  DEPENDENCIES
49
70
  codebreaker_manfly!
71
+ faker
72
+ pry-byebug
50
73
  rake (~> 13.0)
51
74
  rspec (~> 3.10)
52
75
  rubocop (~> 1.7)
76
+ simplecov
53
77
 
54
78
  BUNDLED WITH
55
79
  2.2.28
data/README.md CHANGED
@@ -1,15 +1,19 @@
1
1
  # Codebreaker
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/codebreaker`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Codebreaker is a logic game in which a code-breaker tries to break a secret code created by a code-maker. The code-maker, which will be played by the application we’re going to write, creates a secret code of four numbers between 1 and 6.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ The code-breaker then gets some number of chances to break the code. In each turn, the code-breaker makes a guess of four numbers. The code-maker then marks the guess with up to four + and - signs.
6
+
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 and in the same position.
8
+
9
+ 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.
6
10
 
7
11
  ## Installation
8
12
 
9
13
  Add this line to your application's Gemfile:
10
14
 
11
15
  ```ruby
12
- gem 'codebreaker_manfly'
16
+ gem 'codebreaker_manfly', '~> 0.1.0'
13
17
  ```
14
18
 
15
19
  And then execute:
@@ -18,26 +22,14 @@ And then execute:
18
22
 
19
23
  Or install it yourself as:
20
24
 
21
- $ gem install codebreaker
25
+ $ gem install codebreaker_manfly
22
26
 
23
27
  ## Usage
24
28
 
25
- TODO: Write usage instructions here
26
-
27
- ## Development
28
-
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
-
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
-
33
- ## Contributing
34
-
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/codebreaker. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/codebreaker/blob/master/CODE_OF_CONDUCT.md).
36
-
37
- ## License
29
+ To use this game it should be installed in a console or web vesion of the game
38
30
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
31
+ Create an instance of the game:
40
32
 
41
- ## Code of Conduct
33
+ game = Codebreacker::Game.new
42
34
 
43
- Everyone interacting in the Codebreaker project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/codebreaker/blob/master/CODE_OF_CONDUCT.md).
35
+ During instantiation you can set matcher (object that will be used for guesses matching) and storage (object that will be used for storing scores).
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class BaseEntity
5
+ include Validation
6
+ def initialize(*)
7
+ validate
8
+ end
9
+
10
+ def validate; end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml/store'
4
+ require 'date'
5
+
6
+ require_relative 'validation'
7
+ require_relative 'base_entity'
8
+ require_relative 'code_generate'
9
+ require_relative 'code_matcher'
10
+ require_relative 'difficulty_factory'
11
+ require_relative 'difficulty'
12
+ require_relative 'storage'
13
+ require_relative 'user'
14
+ require_relative 'winners'
15
+ require_relative 'version'
16
+ require_relative '../codebreaker'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class CodeGenerator < BaseEntity
5
+ CODE_RANGE = (1..6).freeze
6
+ CODE_LENGTH = 4
7
+
8
+ def self.generate(length = CODE_LENGTH)
9
+ Array.new(length) { rand(CODE_RANGE) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class CodeMatcher
5
+ EXACT = '+'
6
+ NON_EXACT = '-'
7
+
8
+ attr_reader :guess, :secret_code
9
+
10
+ def match(secret_code, guess)
11
+ @secret_code = secret_code.split('')
12
+ @guess = guess.split('')
13
+ handle_matched_digits.join + handle_matched_digits_with_wrong_position.join
14
+ end
15
+
16
+ private
17
+
18
+ def handle_matched_digits
19
+ secret_code.map.with_index do |_, index|
20
+ next unless secret_code[index] == guess[index]
21
+
22
+ @guess[index], @secret_code[index] = nil
23
+ EXACT
24
+ end
25
+ end
26
+
27
+ def handle_matched_digits_with_wrong_position
28
+ guess.compact.map do |number|
29
+ next unless @secret_code.include?(number)
30
+
31
+ @secret_code.delete_at(secret_code.index(number))
32
+ NON_EXACT
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Difficulty
5
+ attr_reader :name, :attempts, :hints
6
+
7
+ NEGATIVE_INTEGER = 0
8
+
9
+ def initialize(name:, attempts:, hints:)
10
+ @name = name
11
+ @attempts = attempts
12
+ @hints = hints
13
+ end
14
+
15
+ private
16
+
17
+ def validate
18
+ raise Errors::ClassValidError unless valid_class?(String, difficulty)
19
+ raise Errors::NegativeIntegerError unless valid_non_negative_integer?(attempts, NEGATIVE_INTEGER)
20
+ raise Errors::NegativeIntegerError unless valid_non_negative_integer?(hints, NEGATIVE_INTEGER)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class DifficultyFactory
5
+ DIFFICULTIES = {
6
+
7
+ easy: {
8
+ name: 'easy',
9
+ attempts: 15,
10
+ hints: 2
11
+ },
12
+ medium: {
13
+ name: 'medium',
14
+ attempts: 10,
15
+ hints: 1
16
+ },
17
+ hell: {
18
+ name: 'hell',
19
+ attempts: 5,
20
+ hints: 1
21
+ }
22
+
23
+ }.freeze
24
+ def self.generate(difficulty_name)
25
+ case difficulty_name
26
+ when DIFFICULTIES[:easy] then Difficulty.new(DIFFICULTIES[:easy])
27
+ when DIFFICULTIES[:medium] then Difficulty.new(DIFFICULTIES[:medium])
28
+ when DIFFICULTIES[:hell] then Difficulty.new(DIFFICULTIES[:hell])
29
+ else raise Errors::InvalidDifficultyError
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class ClassValidError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class EmptyStringsError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class InvalidDifficultyError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class MaxLengthError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class MinLengthError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class NegativeIntegerError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class NonNumericStringError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class NotImplementedError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Errors
5
+ class RangeError < StandardError
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ module Storage
5
+ FILE_NAME = './store/statistics.yml'
6
+
7
+ def init_store
8
+ save
9
+ end
10
+
11
+ def load
12
+ store.transaction do
13
+ @winners = store[:winners]
14
+ end
15
+ end
16
+
17
+ def save
18
+ store.transaction do
19
+ store[:winners] = @winners
20
+ end
21
+ end
22
+
23
+ def storage_exists?
24
+ File.exist?(FILE_NAME)
25
+ end
26
+
27
+ def store
28
+ @store ||= YAML::Store.new(FILE_NAME)
29
+ end
30
+ end
31
+ end
@@ -1,16 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Codebreaker
4
- class User
5
- include Validation
3
+ require_relative 'bootstrap'
6
4
 
7
- attr_reader :name
5
+ module Codebreaker
6
+ class User < BaseEntity
7
+ attr_reader :name, :difficulty, :used_attempts, :used_hints
8
8
 
9
- NAME_LENGTH = (3..20).freeze
9
+ NAME_MIN_LENGTH = 3
10
+ NAME_MAX_LENGTH = 20
10
11
 
11
- def initialize(name:)
12
- validate_user_name(name, NAME_LENGTH)
12
+ def initialize(name, difficulty)
13
13
  @name = name
14
+ @difficulty = difficulty
15
+ @used_attempts = 0
16
+ @used_hints = 0
17
+ super
18
+ end
19
+
20
+ def hints?
21
+ difficulty.hints = used_hints
22
+ end
23
+
24
+ def attempts?
25
+ difficulty.attempts = used_attempts
26
+ end
27
+
28
+ def hint
29
+ @used_hints += 1
30
+ end
31
+
32
+ def attempt
33
+ @used_attempts += 1
34
+ end
35
+
36
+ private
37
+
38
+ def validate
39
+ raise Errors::ClassValidError unless valid_class?(String, name)
40
+ raise Errors::MinLengthError unless valid_string_min_length?(name, NAME_MIN_LENGTH)
41
+ raise Errors::MaxLengthError unless valid_string_max_length?(name, NAME_MAX_LENGTH)
14
42
  end
15
43
  end
16
44
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors/range_error'
4
+ require_relative 'errors/non_numeric_string_error'
5
+ require_relative 'errors/empty_strings_error'
6
+ require_relative 'errors/class_validate_error'
7
+ require_relative 'errors/min_length_error'
8
+ require_relative 'errors/max_length_error'
9
+ require_relative 'errors/negative_integer_error'
10
+ require_relative 'errors/invalid_difficulty_error'
11
+
12
+ module Codebreaker
13
+ module Validation
14
+ def valid_class?(expected_class, instance)
15
+ instance.is_a?(expected_class)
16
+ end
17
+
18
+ def valid_non_empty_string?(string)
19
+ !string.empty?
20
+ end
21
+
22
+ def valid_positive_integer?(number)
23
+ number.positive?
24
+ end
25
+
26
+ def valid_non_negative_integer?(number)
27
+ !number.negative?
28
+ end
29
+
30
+ def valid_string_min_length?(string, min_length)
31
+ string.length >= min_length
32
+ end
33
+
34
+ def valid_string_max_length?(string, max_length)
35
+ string.length <= max_length
36
+ end
37
+
38
+ def valid_only_numeric_string?(string)
39
+ /\A\d+\Z/.match?(string)
40
+ end
41
+
42
+ def valid_range?(range, code)
43
+ code.each { |digit| return false unless range.cover?(digit) }
44
+ true
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Codebreaker
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Codebreaker
4
+ class Winner
5
+ attr_reader :user, :created_at
6
+
7
+ def initialize(_user)
8
+ @user = user
9
+ @created_at = DateTime.now
10
+ end
11
+ end
12
+ end
data/lib/codebreaker.rb CHANGED
@@ -1,100 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml/store'
4
- require 'date'
3
+ require_relative 'codebreaker/bootstrap'
5
4
 
6
- require_relative 'codebreaker/module/validation'
7
- require_relative 'codebreaker/gameload'
8
- require_relative 'codebreaker/user'
9
- require_relative 'codebreaker/file_loader'
10
- require_relative 'codebreaker/version'
5
+ class Game
6
+ extend Codebreaker::Storage
11
7
 
12
- module Codebreaker
13
- class Game
14
- include Validation
8
+ attr_reader :user
15
9
 
16
- attr_reader :clues, :user, :difficulty,
17
- :attempts_used, :hints_used, :very_secret_code,
18
- :date
10
+ STATUS_IN_PROGRESS = :in_progress
11
+ STATUS_WIN = :win
12
+ STATUS_LOSE = :lose
19
13
 
20
- DIFFICULTIES = {
21
- easy: { attempts: 15, hints: 2 },
22
- medium: { attempts: 10, hints: 1 },
23
- hell: { attempts: 5, hints: 1 }
24
- }.freeze
25
-
26
- CODE_LENGTH = 4
27
- RANGE_GUESS_CODE = (1..6).freeze
28
-
29
- def initialize(difficulty:, user:, date: Date.today)
30
- validate_difficulty(difficulty, DIFFICULTIES)
31
-
32
- @user = user
33
- @difficulty = difficulty
34
- @date = date
35
-
36
- attempts
37
- number_of_hints
38
- end
39
-
40
- def start_new_game
41
- @very_secret_code = generate_random_code
42
- @hints = @very_secret_code.clone
43
- @attempts_used = 0
44
- @hints_used = 0
45
- @user_guess = []
46
- @clues = []
47
- end
14
+ def initialize
15
+ @secret_code = Codebreaker::CodeGenerator.generate
16
+ @status = STATUS_IN_PROGRESS
17
+ @hints = @secret_code.sample(@secret_code.length)
18
+ @storage = Game.store
19
+ save_storage unless Game.storage_exists?
20
+ end
48
21
 
49
- def guess(user_guess)
50
- guess = user_guess.each_char.map(&:to_i)
51
- validate_guess(guess, CODE_LENGTH, RANGE_GUESS_CODE)
52
- check_guess(guess, very_secret_code)
22
+ def create_user(name, difficulty)
23
+ @user = Codebreaker::User.new(name, difficulty)
24
+ end
53
25
 
54
- increase_attempts
55
- end
26
+ def create_difficulty(difficulty_name)
27
+ @difficulty = Codebreaker::DifficultyFactory.generate(difficulty_name)
28
+ end
56
29
 
57
- def show_hint
58
- validate_hints(hints_used, number_of_hints)
30
+ def win?
31
+ @status == STATUS_WIN
32
+ end
59
33
 
60
- @hints_used += 1
61
- @hints.shuffle!.pop
62
- end
34
+ def lose?
35
+ @status == STATUS_LOSE
36
+ end
63
37
 
64
- def won?
65
- @user_guess.nil?
66
- end
38
+ def take_hint
39
+ user.hint if user.hints?
67
40
 
68
- def lost?
69
- @attempts_used >= @attempts
70
- end
41
+ @hints.pop
42
+ end
71
43
 
72
- def save_game
73
- FileLoader.new.save(self)
74
- end
44
+ def take_attempt(guess)
45
+ return equal(@secret_code, guess.to_s) if user.attempts?
75
46
 
76
- def attempts
77
- @attempts ||= DIFFICULTIES[difficulty.to_sym][:attempts]
78
- end
47
+ @status = STATUS_LOSE
48
+ nil
49
+ end
79
50
 
80
- def number_of_hints
81
- @number_of_hints ||= DIFFICULTIES[difficulty.to_sym][:hints]
51
+ def save_storage
52
+ @storage.transaction do
53
+ @storage[:winners] = @winners || []
82
54
  end
55
+ end
83
56
 
84
- private
85
-
86
- def generate_random_code
87
- Array.new(CODE_LENGTH) { rand(RANGE_GUESS_CODE) }
88
- end
57
+ private
89
58
 
90
- def check_guess(guess, secret_code)
91
- gameload = Codebreaker::Gameload.new(guess, secret_code)
92
- @user_guess = gameload.match
93
- @clues = gameload.clues
94
- end
59
+ def win
60
+ @winners << CodebreakerGame::Winner.new(user)
61
+ @status = STATUS_WIN
62
+ end
95
63
 
96
- def increase_attempts
97
- @attempts_used += 1
98
- end
64
+ def equal(_secret_code, guess)
65
+ user.attempt
66
+ Codebreaker::CodeMatcher.match(@secret_code, guess)
99
67
  end
100
68
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codebreaker_manfly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrii Ivaniuk
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-19 00:00:00.000000000 Z
11
+ date: 2021-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faker
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry-byebug
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'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rake
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '1.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
55
97
  description: Longer description or delete this line.
56
98
  email:
57
99
  - aivanuyk0@gmail.com
@@ -61,7 +103,6 @@ extra_rdoc_files: []
61
103
  files:
62
104
  - ".rspec"
63
105
  - ".rubocop.yml"
64
- - ".ruby-gemset"
65
106
  - ".ruby-version"
66
107
  - CHANGELOG.md
67
108
  - CODE_OF_CONDUCT.md
@@ -72,13 +113,27 @@ files:
72
113
  - Rakefile
73
114
  - bin/console
74
115
  - bin/setup
75
- - db/results_test.yml
76
116
  - lib/codebreaker.rb
77
- - lib/codebreaker/file_loader.rb
78
- - lib/codebreaker/gameload.rb
79
- - lib/codebreaker/module/validation.rb
117
+ - lib/codebreaker/base_entity.rb
118
+ - lib/codebreaker/bootstrap.rb
119
+ - lib/codebreaker/code_generate.rb
120
+ - lib/codebreaker/code_matcher.rb
121
+ - lib/codebreaker/difficulty.rb
122
+ - lib/codebreaker/difficulty_factory.rb
123
+ - lib/codebreaker/errors/class_validate_error.rb
124
+ - lib/codebreaker/errors/empty_strings_error.rb
125
+ - lib/codebreaker/errors/invalid_difficulty_error.rb
126
+ - lib/codebreaker/errors/max_length_error.rb
127
+ - lib/codebreaker/errors/min_length_error.rb
128
+ - lib/codebreaker/errors/negative_integer_error.rb
129
+ - lib/codebreaker/errors/non_numeric_string_error.rb
130
+ - lib/codebreaker/errors/not_implemented_error.rb
131
+ - lib/codebreaker/errors/range_error.rb
132
+ - lib/codebreaker/storage.rb
80
133
  - lib/codebreaker/user.rb
134
+ - lib/codebreaker/validation.rb
81
135
  - lib/codebreaker/version.rb
136
+ - lib/codebreaker/winners.rb
82
137
  homepage:
83
138
  licenses:
84
139
  - MIT
data/.ruby-gemset DELETED
File without changes
data/db/results_test.yml DELETED
@@ -1,220 +0,0 @@
1
- --- !ruby/object:Codebreaker::Game
2
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
3
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
4
- const_name: User
5
- __expired: false
6
- name:
7
- __sending_message:
8
- difficulty: :easy
9
- date: 2021-10-08
10
- attempts: 15
11
- number_of_hints: 2
12
- --- !ruby/object:Codebreaker::Game
13
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
14
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
15
- const_name: User
16
- __expired: false
17
- name:
18
- __sending_message:
19
- difficulty: :easy
20
- date: 2021-10-08
21
- attempts: 15
22
- number_of_hints: 2
23
- --- !ruby/object:Codebreaker::Game
24
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
25
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
26
- const_name: User
27
- __expired: false
28
- name:
29
- __sending_message:
30
- difficulty: :easy
31
- date: 2021-10-08
32
- attempts: 15
33
- number_of_hints: 2
34
- --- !ruby/object:Codebreaker::Game
35
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
36
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
37
- const_name: User
38
- __expired: false
39
- name:
40
- __sending_message:
41
- difficulty: :easy
42
- date: 2021-10-08
43
- attempts: 15
44
- number_of_hints: 2
45
- --- !ruby/object:Codebreaker::Game
46
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
47
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
48
- const_name: User
49
- __expired: false
50
- name:
51
- __sending_message:
52
- difficulty: :easy
53
- date: 2021-10-08
54
- attempts: 15
55
- number_of_hints: 2
56
- --- !ruby/object:Codebreaker::Game
57
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
58
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
59
- const_name: User
60
- __expired: false
61
- name:
62
- __sending_message:
63
- difficulty: :easy
64
- date: 2021-10-08
65
- attempts: 15
66
- number_of_hints: 2
67
- --- !ruby/object:Codebreaker::Game
68
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
69
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
70
- const_name: User
71
- __expired: false
72
- name:
73
- __sending_message:
74
- difficulty: :easy
75
- date: 2021-10-08
76
- attempts: 15
77
- number_of_hints: 2
78
- --- !ruby/object:Codebreaker::Game
79
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
80
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
81
- const_name: User
82
- __expired: false
83
- name:
84
- __sending_message:
85
- difficulty: :easy
86
- date: 2021-10-08
87
- attempts: 15
88
- number_of_hints: 2
89
- --- !ruby/object:Codebreaker::Game
90
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
91
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
92
- const_name: User
93
- __expired: false
94
- name:
95
- __sending_message:
96
- difficulty: :easy
97
- date: 2021-10-08
98
- attempts: 15
99
- number_of_hints: 2
100
- --- !ruby/object:Codebreaker::Game
101
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
102
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
103
- const_name: User
104
- __expired: false
105
- name:
106
- __sending_message:
107
- difficulty: :easy
108
- date: 2021-10-08
109
- attempts: 15
110
- number_of_hints: 2
111
- --- !ruby/object:Codebreaker::Game
112
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
113
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
114
- const_name: User
115
- __expired: false
116
- name:
117
- __sending_message:
118
- difficulty: :easy
119
- date: 2021-10-19
120
- attempts: 15
121
- number_of_hints: 2
122
- --- !ruby/object:Codebreaker::Game
123
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
124
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
125
- const_name: User
126
- __expired: false
127
- name:
128
- __sending_message:
129
- difficulty: :easy
130
- date: 2021-10-19
131
- attempts: 15
132
- number_of_hints: 2
133
- --- !ruby/object:Codebreaker::Game
134
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
135
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
136
- const_name: User
137
- __expired: false
138
- name:
139
- __sending_message:
140
- difficulty: :easy
141
- date: 2021-10-19
142
- attempts: 15
143
- number_of_hints: 2
144
- --- !ruby/object:Codebreaker::Game
145
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
146
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
147
- const_name: User
148
- __expired: false
149
- name:
150
- __sending_message:
151
- difficulty: :easy
152
- date: 2021-10-19
153
- attempts: 15
154
- number_of_hints: 2
155
- --- !ruby/object:Codebreaker::Game
156
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
157
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
158
- const_name: User
159
- __expired: false
160
- name:
161
- __sending_message:
162
- difficulty: :easy
163
- date: 2021-10-19
164
- attempts: 15
165
- number_of_hints: 2
166
- --- !ruby/object:Codebreaker::Game
167
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
168
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
169
- const_name: User
170
- __expired: false
171
- name:
172
- __sending_message:
173
- difficulty: :easy
174
- date: 2021-10-19
175
- attempts: 15
176
- number_of_hints: 2
177
- --- !ruby/object:Codebreaker::Game
178
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
179
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
180
- const_name: User
181
- __expired: false
182
- name:
183
- __sending_message:
184
- difficulty: :easy
185
- date: 2021-10-19
186
- attempts: 15
187
- number_of_hints: 2
188
- --- !ruby/object:Codebreaker::Game
189
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
190
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
191
- const_name: User
192
- __expired: false
193
- name:
194
- __sending_message:
195
- difficulty: :easy
196
- date: 2021-10-19
197
- attempts: 15
198
- number_of_hints: 2
199
- --- !ruby/object:Codebreaker::Game
200
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
201
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
202
- const_name: User
203
- __expired: false
204
- name:
205
- __sending_message:
206
- difficulty: :easy
207
- date: 2021-10-19
208
- attempts: 15
209
- number_of_hints: 2
210
- --- !ruby/object:Codebreaker::Game
211
- user: !ruby/object:RSpec::Mocks::InstanceVerifyingDouble
212
- doubled_module: !ruby/object:RSpec::Mocks::NamedObjectReference
213
- const_name: User
214
- __expired: false
215
- name:
216
- __sending_message:
217
- difficulty: :easy
218
- date: 2021-10-19
219
- attempts: 15
220
- number_of_hints: 2
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Codebreaker
4
- class FileLoader
5
- include Validation
6
-
7
- FILE_PATH = "#{ENV['DB_PATH']}#{ENV['DB_FILE']}"
8
-
9
- def initialize(db_file_path = FILE_PATH)
10
- @db_file_path = db_file_path
11
- end
12
-
13
- def load
14
- validate_file_existens(FILE_PATH)
15
-
16
- File.open(FILE_PATH, 'r') do |file|
17
- YAML.load_stream(file)
18
- end
19
- end
20
-
21
- def save(object)
22
- create_directory('DB_PATH') unless Dir.exist?(ENV['DB_PATH'])
23
- File.open(FILE_PATH, 'a') { |file| file.write(object.to_yaml) }
24
- end
25
-
26
- def create_directory(path)
27
- Dir.mkdir(ENV[path])
28
- end
29
- end
30
- end
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Codebreaker
4
- class Gameload
5
- attr_reader :clues
6
-
7
- CLUES = {
8
- exact: :exact,
9
- non_exact: :non_exact
10
- }.freeze
11
-
12
- def initialize(guess, secret_code)
13
- @secret_code = secret_code
14
- @guess = guess
15
- @clues = []
16
- end
17
-
18
- def match
19
- collected = @secret_code.zip(@guess).delete_if { |code, guess| write_to_clues(CLUES[:exact]) if code == guess }
20
- @secret_code, @guess = collected.transpose
21
- return unless @guess
22
-
23
- non_exact_match
24
- end
25
-
26
- def non_exact_match
27
- @guess.compact.each do |num|
28
- next unless @secret_code.any?(num)
29
-
30
- write_to_clues(CLUES[:non_exact])
31
- @secret_code[@secret_code.index(num)] = nil
32
- end
33
- end
34
-
35
- def write_to_clues(clue)
36
- @clues.push(clue)
37
- end
38
- end
39
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Codebreaker
4
- module Validation
5
- ERROR_MESSAGES = {
6
- invalid_name: 'Name should be of 3 to 20 characters',
7
- invalid_guess: 'Expect 4 digits from 1 to 6',
8
- no_hints_left: 'No hints left, mate',
9
- no_difficulty: 'No such difficulty',
10
- no_save_data: 'No saved data is found'
11
- }.freeze
12
-
13
- class GameError < StandardError; end
14
-
15
- class NoSavedData < GameError; end
16
-
17
- class UnknownDifficulty < GameError; end
18
-
19
- class InvalidGuess < GameError; end
20
-
21
- class NoHintsLeft < GameError; end
22
-
23
- class InvalidName < GameError; end
24
-
25
- def validate_user_name(name, length)
26
- raise_error(InvalidName, :invalid_name) unless length.cover?(name.length)
27
- end
28
-
29
- def validate_difficulty(difficulty, difficulties)
30
- raise_error(UnknownDifficulty, :no_difficulty) unless difficulties.keys.any?(difficulty.to_sym)
31
- end
32
-
33
- def validate_guess(guess, length, range)
34
- raise_error(InvalidGuess, :invalid_guess) unless guess.compact.length == length
35
- raise_error(InvalidGuess, :invalid_guess) if guess.compact.any? { |num| !range.cover? num }
36
- end
37
-
38
- def validate_hints(hints_used, hints_total)
39
- raise_error(NoHintsLeft, :no_hints_left) if hints_used >= hints_total
40
- end
41
-
42
- def validate_file_existens(file_path)
43
- raise_error(NoSavedData, :no_save_data) unless File.exist?(file_path)
44
- end
45
-
46
- def raise_error(error_class, error_message)
47
- raise error_class, ERROR_MESSAGES[error_message]
48
- end
49
- end
50
- end