digits_solver 0.1.1 → 0.1.3

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: b539861e0a6120403802c85ac9fb08960aa17c7064687064269a2b59b6213f3d
4
- data.tar.gz: c0a746b1c33a7866ed10b39e51ae672806f723b01336b81f63b0563a3b45fd05
3
+ metadata.gz: 3cc76291aaef108bc1e004bb3477fddd31520a414a82027be8111ef746add465
4
+ data.tar.gz: '08302397fba6f31c6c92e8a14e9817f8b2f308c7d0fb2c1e46b17b653a11d20c'
5
5
  SHA512:
6
- metadata.gz: dd7f9d5a8c08a0ad227aa02f1adbdf12b331b69a9e068f8a1586d9e2867766b5bd6eed8c1d7bae93b57cabb310d6f637397aedf9471a5a2aecf1e07b88bea120
7
- data.tar.gz: 0dcb86378227e3184e92b63af05fcd3b2cf210d18e0c3e1e4d92bbe973f333c68a47567ae2ba9bd023906fe673426353052e7a0f86d2c2752932e02875c646d3
6
+ metadata.gz: dd79298b33da986c95ad772b18c3cbad3c8827b2f7e3ab5c76a07fe6d17abb1247000c3d172e557ee78ebcef98bd71df73983348271fe76da0ecea5b240b7fb8
7
+ data.tar.gz: 7fe1e62a96ce0d064628857740f46e1b4b2d54e88a4988581d0524f614a3bf84a11130d9ad589a74fdfb1158a18a5b80f101d3d2f559dcc8d525e988a19367c3
data/.rubocop.yml CHANGED
@@ -3,11 +3,11 @@ AllCops:
3
3
 
4
4
  Style/StringLiterals:
5
5
  Enabled: true
6
- EnforcedStyle: double_quotes
6
+ EnforcedStyle: single_quotes
7
7
 
8
8
  Style/StringLiteralsInInterpolation:
9
9
  Enabled: true
10
10
  EnforcedStyle: double_quotes
11
11
 
12
12
  Layout/LineLength:
13
- Max: 120
13
+ Max: 140
data/Gemfile CHANGED
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in digits_solver.gemspec
6
6
  gemspec
7
-
8
- gem "rake", "~> 13.0"
9
-
10
- gem "rspec", "~> 3.0"
11
-
12
- gem "rubocop", "~> 1.21"
data/README.md CHANGED
@@ -1,24 +1,35 @@
1
1
  # DigitsSolver
2
2
 
3
- This is basically a coding exercice.
3
+ This is basically a coding exercise.
4
4
 
5
- The goal of this gem is to solve puzzles à-la [NY Times Digits game](https://www.nytimes.com/games/digits). You may
6
- actually know this game under a different name. In France this looks like the calculation part of a 40 year old TV
5
+ The goal of this gem is to solve puzzles à-la [NY Times Digits game](https://www.nytimes.com/games/digits). You may
6
+ actually know this game under a different name. In France this looks like the calculation part of an almost 50 year old TV
7
7
  show named 'Les chiffres et les lettres'...
8
8
 
9
- This gem implements a brute-force approach to solve the problem but is ready to host alternative strategies.
9
+ The goal is to use numbers from the draw combined by any basic operation (+ - / *) to reach that goal. You cannot have negative numbers as result of "-" operation, and can only divide number resulting into an integer.
10
10
 
11
+ This gem implements a brute-force approach to solve the problem but is ready to host alternate strategies.
12
+ Basically this strategy won't work beyond 7 numbers in the draw (it is limited in the command line to 6 numbers but not within
13
+ the code), as for a 7 numbers draw it already takes few minutes on my machine. Although this strategy does not
14
+ stop at the first encountered solution but browses the whole tree of possibilities (that could be easily done).
15
+
16
+ To go beyond, you would probably have to go for a more mathematical approach...
11
17
 
12
18
  ## Installation
13
19
 
14
- $ gem install digits_solver
20
+ 1. You need to have the [Ruby language](https://www.ruby-lang.org) working on your machine.
21
+ 2. Install this Ruby gem:
22
+
23
+ $ gem install digits_solver
15
24
 
16
25
  ## Usage
17
26
 
18
- This gem provides an executable named `find_nydigits_solutions`.
27
+ ### Command line
19
28
 
20
- * First argument is the target number.
21
- * All subsequent arguments are the numbers to be used in calculations to reach the target.
29
+ Once this gem installed, it provides an executable named `find_nydigits_solutions`(you may potentially have to log-out/in if it is not available in your shell).
30
+
31
+ * First script argument is the target number.
32
+ * All subsequent arguments are the numbers to be used in calculations to reach the target. You can specify from 2 to 6 numbers in the "draw".
22
33
 
23
34
  ex:
24
35
 
@@ -32,3 +43,81 @@ Solved in 4 operations:
32
43
  => 22 * 20 = 440
33
44
  => 440 - 3 = 437
34
45
  ```
46
+ This program will only display the "best" solution found (ie the one implying the least number of operations), but code does not (you see here above that 67 solutions were found).
47
+
48
+ ### Code usage
49
+
50
+ You have basically access to the same functions but with more flexibility.
51
+
52
+ ```ruby
53
+ # The interface looks a lot like the command line, here as opposed to the command line
54
+ # you are not limited to 6 numbers in the draw, but be aware that 7 takes already few minutes
55
+ # and I never tried beyond...
56
+ r = DigitsSolver.solve_for 437, 3, 5, 7, 13, 20, 25
57
+
58
+ # The object returned is a DigitsSolver::SolutionSet
59
+ # You can query it
60
+ r.size
61
+ # => 67
62
+
63
+ # You can query the "best" solution found. It returns a DigitsSolver::Solution object.
64
+ r.best_solution
65
+ # => #<DigitsSolver::Solution:0x000055b96f5f97a8
66
+ # Solution: '(5 * 7 - 13) * 20 - 3 = 437',
67
+ # @problem_statement=#<DigitsSolver::ProblemStatement:0x000055b96fe71020 @draw=[3, 5, 7, 13, 20, 25], @max_operations_number=5, @target_number=437>,
68
+ # @operands=[5, 7, 13, 20, 3],
69
+ # @operations_to_apply=[:multiply, :minus, :multiply, :minus]>
70
+
71
+ # Or you can query the "best" solutions, then it would return an array of DigitsSolver::Solution
72
+ #
73
+ r.best_solutions 3
74
+ # => [#<DigitsSolver::Solution:0x000055b96f5f97a8
75
+ # Solution: '(5 * 7 - 13) * 20 - 3 = 437',
76
+ # @problem_statement=#<DigitsSolver::ProblemStatement:0x000055b96fe71020 @draw=[3, 5, 7, 13, 20, 25], @max_operations_number=5, @target_number=437>,
77
+ # @operands=[5, 7, 13, 20, 3],
78
+ # @operations_to_apply=[:multiply, :minus, :multiply, :minus]>,
79
+ # #<DigitsSolver::Solution:0x000055b96f663ef0
80
+ # Solution: '(7 * 5 - 13) * 20 - 3 = 437',
81
+ # @problem_statement=#<DigitsSolver::ProblemStatement:0x000055b96fe71020 @draw=[3, 5, 7, 13, 20, 25], @max_operations_number=5, @target_number=437>,
82
+ # @operands=[7, 5, 13, 20, 3],
83
+ # @operations_to_apply=[:multiply, :minus, :multiply, :minus]>,
84
+ # #<DigitsSolver::Solution:0x000055b96f6b2528
85
+ # Solution: '((20 - 3) * 25 + 5) + 7 = 437',
86
+ # @problem_statement=#<DigitsSolver::ProblemStatement:0x000055b96fe71020 @draw=[3, 5, 7, 13, 20, 25], @max_operations_number=5, @target_number=437>,
87
+ # @operands=[20, 3, 25, 5, 7],
88
+ # @operations_to_apply=[:minus, :multiply, :plus, :plus]>]
89
+
90
+ # DigitsSolver::Solution objects can be printed
91
+ puts r.best_solution
92
+ # Solved in 4 operations:
93
+ # => 5 * 7 = 35
94
+ # => 35 - 13 = 22
95
+ # => 22 * 20 = 440
96
+ # => 440 - 3 = 437
97
+ # => nil
98
+
99
+ # or debugged
100
+ pp r.best_solution
101
+ # #<DigitsSolver::Solution:0x000055b96f5f97a8
102
+ # Solution: '(5 * 7 - 13) * 20 - 3 = 437',
103
+ # @problem_statement=#<DigitsSolver::ProblemStatement:0x000055b96fe71020
104
+ # @draw=[3, 5, 7, 13, 20, 25],
105
+ # @max_operations_number=5,
106
+ # @target_number=437>,
107
+ # @operands=[5, 7, 13, 20, 3],
108
+ # @operations_to_apply=[:multiply, :minus, :multiply, :minus]>
109
+
110
+ # And of course it has other methods, you could use. Ex:
111
+ r.sorted_solutions.map(&:to_evaluable_code).take 10
112
+ # => ["(5 * 7 - 13) * 20 - 3",
113
+ # "(7 * 5 - 13) * 20 - 3",
114
+ # "((20 - 3) * 25 + 5) + 7",
115
+ # "((20 - 3) * 25 + 7) + 5",
116
+ # "((20 - 5) + 3) * 25 - 13",
117
+ # "((20 - 7) + 5) * 25 - 13",
118
+ # "((3 * 5 + 20) * 13 + 7) - 25",
119
+ # "((3 * 5 + 20) * 13 - 25) + 7",
120
+ # "((3 * 7 * 20 + 5) - 13) + 25",
121
+ # "((3 * 7 * 20 + 5) + 25) - 13"]
122
+
123
+ ```
data/Rakefile CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- require "rubocop/rake_task"
8
+ require 'rubocop/rake_task'
9
9
 
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[spec rubocop]
12
+ task default: %i[spec]
@@ -1,39 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/digits_solver/version"
3
+ require_relative 'lib/digits_solver/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "digits_solver"
6
+ spec.name = 'digits_solver'
7
7
  spec.version = DigitsSolver::VERSION
8
- spec.authors = ["Laurent B."]
9
- spec.email = ["lbnetid+rb@gmail.com"]
8
+ spec.authors = ['Laurent B.']
9
+ spec.email = ['lbnetid+rb@gmail.com']
10
10
 
11
- spec.summary = "Solves NYTimes Digits puzzle."
12
- spec.description = "Finds solutions to the NYTimes Digits game."
13
- spec.homepage = "https://gitlab.com/coding_exercices/digits_solver"
14
- spec.required_ruby_version = ">= 2.6.0"
11
+ spec.summary = 'Solves NYTimes Digits puzzle.'
12
+ spec.description = 'Finds solutions to the NYTimes Digits game.'
13
+ spec.homepage = 'https://gitlab.com/coding_exercices/digits_solver'
14
+ spec.required_ruby_version = '>= 2.6.0'
15
15
 
16
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
16
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
17
17
 
18
- spec.metadata["homepage_uri"] = spec.homepage
19
- spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+ spec.metadata['source_code_uri'] = spec.homepage
20
20
 
21
21
  # Specify which files should be added to the gem when it is released.
22
22
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ # noinspection RubyMismatchedArgumentType
23
24
  spec.files = Dir.chdir(__dir__) do
24
25
  `git ls-files -z`.split("\x0").reject do |f|
25
26
  (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
26
27
  end
27
28
  end
28
- spec.bindir = "exe"
29
+ spec.bindir = 'exe'
29
30
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
- spec.require_paths = ["lib"]
31
+ spec.require_paths = ['lib']
31
32
 
32
33
  # Uncomment to register a new dependency of your gem
33
34
  # spec.add_dependency "example-gem", "~> 1.0"
34
35
  spec.add_development_dependency 'pry'
35
- spec.add_development_dependency 'rspec'
36
-
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
+ spec.add_development_dependency 'rspec', '~> 3.0'
38
+ spec.add_development_dependency 'rubocop', '~> 1.21'
39
+ spec.add_development_dependency 'rubocop-rake'
40
+ spec.add_development_dependency 'rubocop-rspec'
37
41
  # For more information and examples about making a new gem, check out our
38
42
  # guide at: https://bundler.io/guides/creating_gem.html
39
43
  end
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env ruby
2
- # coding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'rubygems'
5
5
  require 'bundler/setup'
6
6
  require 'digits_solver'
7
7
 
8
- def help(out = STDOUT)
9
- out.puts <<EOM
10
- To run this program:
8
+ def help(out = $stdout)
9
+ out.puts <<~EOM
10
+ To run this program:
11
11
 
12
- find_nydigits_solution <number to find> <space separated list of numbers>
12
+ find_nydigits_solution <number to find> <space separated list of numbers>
13
13
 
14
- This program will solve if possible the NY Digits puzzle.
15
- EOM
14
+ This program will solve if possible the NY Digits puzzle.
15
+ EOM
16
16
  end
17
17
 
18
18
  begin
@@ -26,11 +26,11 @@ begin
26
26
  end
27
27
  puts "Trying to find #{target}"
28
28
  solutions = DigitsSolver.solve_for target, *draw
29
- raise DigitsSolver::Error, %q[Couldn't find any solution !] if solutions.sorted_solutions.empty?
29
+ raise DigitsSolver::Error, "Couldn't find any solution !" if solutions.sorted_solutions.empty?
30
30
 
31
31
  puts "A best solution has been found (total of #{solutions.size} possible solutions found)."
32
32
  puts solutions.best_solution
33
- rescue => e
34
- STDERR.puts e.message
35
- help STDERR
33
+ rescue StandardError => e
34
+ warn e.message
35
+ help $stderr
36
36
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module DigitsSolver
3
- class Error < StandardError ; end
4
+ class Error < StandardError; end
4
5
  end
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module DigitsSolver
3
4
  class ProblemStatement
4
-
5
5
  attr_reader :target_number
6
6
 
7
7
  def draw
8
8
  @draw.dup
9
9
  end
10
10
 
11
+ # noinspection RubyParameterNamingConvention
11
12
  def initialize(target_number_or_problem_statement, *draw)
12
13
  @target_number, @draw = if target_number_or_problem_statement.is_a? DigitsSolver::ProblemStatement
13
- [target_number_or_problem_statement.target_number, target_number_or_problem_statement.draw]
14
- else
15
- [target_number_or_problem_statement, draw]
14
+ [target_number_or_problem_statement.target_number, target_number_or_problem_statement.draw]
15
+ else
16
+ [target_number_or_problem_statement, draw]
16
17
  end
17
18
  DigitsSolver.logger.info "The target is #{target_number}"
18
19
  DigitsSolver.logger.info "The draw is #{draw.inspect}"
@@ -21,6 +22,5 @@ module DigitsSolver
21
22
  def max_operations_number
22
23
  @max_operations_number ||= @draw.size - 1
23
24
  end
24
-
25
25
  end
26
26
  end
@@ -1,31 +1,30 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module DigitsSolver
3
4
 
5
+ # This is the class that represents a solution to the problem.
4
6
  class Solution
5
-
6
7
  include DigitsSolver::Strategies::Base
7
8
 
8
9
  attr_reader :problem_statement, :operands, :operations_to_apply
9
10
 
10
11
  def initialize(problem_statement, operands, operations_to_apply)
11
- raise DigitsSolver::Error, "Invalid problem statement" unless problem_statement.is_a? DigitsSolver::ProblemStatement
12
+ raise DigitsSolver::Error, 'Invalid problem statement' unless problem_statement.is_a? DigitsSolver::ProblemStatement
12
13
  unless operands.size == operations_to_apply.size + 1
13
14
  raise DigitsSolver::Error, "Invalid solution #{operands.inspect} => #{operations_to_apply.inspect}"
14
15
  end
15
16
 
16
- DigitsSolver.logger.info "New solution: #{self.inspect}"
17
-
18
17
  @problem_statement = problem_statement
19
18
  @operands = operands
20
19
  @operations_to_apply = operations_to_apply
21
20
  end
22
21
 
23
- def ==(other_solution)
24
- (operations_to_apply == other_solution.operations_to_apply) && (operands == other_solution.operands)
22
+ def ==(other)
23
+ (operations_to_apply == other.operations_to_apply) && (operands == other.operands)
25
24
  end
26
25
 
27
26
  def to_s
28
- res = ["Solved in #{operations_to_apply.size} operation#{operations_to_apply.size <= 1 ? '' : 's'}:"]
27
+ res = ["Solved in #{operations_to_apply.size} operation#{operations_to_apply.size <= 1 ? "" : "s"}:"]
29
28
  res.concat to_operation_lines
30
29
  res.join "\n"
31
30
  end
@@ -50,23 +49,22 @@ module DigitsSolver
50
49
  pp.text "Solution: '#{to_evaluable_code} = #{problem_statement.target_number}'"
51
50
  pp.text ','
52
51
  pp.breakable
53
- pp.seplist(self.instance_variables) do |v|
52
+ pp.seplist(instance_variables) do |v|
54
53
  pp.text "#{v}="
55
- pp.pp self.instance_variable_get v
54
+ pp.pp instance_variable_get v
56
55
  end
57
56
  end
58
57
  end
59
58
 
60
59
  def to_evaluable_code
61
- res = operations_to_apply.each.with_index.reduce(operands.first) do |res, (operation, idx)|
60
+ # parenthesis management is ... meh, but better than nothing, and at least mathematically correct.
61
+ evaluable_code = operations_to_apply.each.with_index.reduce(operands.first) do |res, (operation, idx)|
62
62
  op1 = res
63
63
  op2 = operands[idx + 1]
64
64
  format_string = operation == :multiply ? '%s %s %u' : '(%s %s %u)'
65
65
  format(format_string, op1, DigitsSolver::Strategies::Base::OPERATIONS[operation], op2)
66
66
  end
67
- res[-1] == ')' ? res[1...-1] : res
67
+ evaluable_code[-1] == ')' ? evaluable_code[1...-1] : evaluable_code
68
68
  end
69
-
70
69
  end
71
-
72
70
  end
@@ -1,20 +1,19 @@
1
- module DigitsSolver
1
+ # frozen_string_literal: true
2
2
 
3
+ module DigitsSolver
3
4
  class SolutionSet
4
-
5
5
  include Enumerable
6
6
 
7
7
  DEFAULT_STRATEGY = DigitsSolver::Strategies::BruteForce
8
- attr_reader :problem_statement, :strategy
8
+ attr_reader :problem_statement, :strategy, :count
9
9
 
10
10
  class << self
11
-
12
11
  def solve_for(problem_statement, strategy: DEFAULT_STRATEGY)
13
12
  extend strategy
14
- solutions = solve(problem_statement)
13
+ solutions, attempts_count = solve(problem_statement)
14
+ DigitsSolver.logger.info "Found #{solutions.count} potentially non unique solutions amongst #{attempts_count} tries."
15
15
  new problem_statement, solutions, strategy
16
16
  end
17
-
18
17
  end
19
18
 
20
19
  def each(&block)
@@ -37,6 +36,7 @@ module DigitsSolver
37
36
  .take(nb)
38
37
  nb == 1 ? res.first : res
39
38
  end
39
+
40
40
  alias best_solutions best_solution
41
41
 
42
42
  def size
@@ -57,7 +57,7 @@ module DigitsSolver
57
57
  end
58
58
 
59
59
  def initialize(problem_statement, solutions, strategy)
60
- raise DigitsSolver::Error, "Invalid problem statement" unless problem_statement.is_a? DigitsSolver::ProblemStatement
60
+ raise DigitsSolver::Error, 'Invalid problem statement' unless problem_statement.is_a? DigitsSolver::ProblemStatement
61
61
 
62
62
  @problem_statement = problem_statement
63
63
  @strategy = strategy
@@ -65,12 +65,20 @@ module DigitsSolver
65
65
  @indexed_solutions = {}
66
66
  @solutions = []
67
67
 
68
- solutions.each do |solution|
69
- self << solution
68
+ DigitsSolver.logger.info "#{solutions.count} candidate solutions"
69
+ discarded_nb = solutions.reduce(0) do |count, solution|
70
+ if self << solution
71
+ DigitsSolver.logger.debug "New solution added to solution set: #{solution.to_evaluable_code}"
72
+ count
73
+ else
74
+ count + 1
75
+ end
70
76
  end
71
-
77
+ DigitsSolver.logger.info "Discarded: #{discarded_nb}"
78
+ msg = "Added #{self.solutions.count} solutions to the set of solutions, "
79
+ msg += discarded_nb.zero? ? 'none' : discarded_nb.to_s
80
+ msg += ' were discarded'
81
+ DigitsSolver.logger.info msg
72
82
  end
73
-
74
83
  end
75
-
76
84
  end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DigitsSolver
2
4
  module Strategies
3
5
 
4
6
  module Base
5
-
6
7
  class OperationError < StandardError; end
7
8
 
8
9
  OPERATIONS = {
@@ -18,12 +19,13 @@ module DigitsSolver
18
19
 
19
20
  protected
20
21
 
22
+ # noinspection RubyInstanceMethodNamingConvention,RubyParameterNamingConvention
21
23
  def possible_operations_for_ordered_draw(max_operations_number)
22
24
  nb_operations = OPERATIONS.size
23
25
  ops_a = OPERATIONS.to_a
24
- number_of_possibilities = nb_operations ** max_operations_number
26
+ number_of_possibilities = nb_operations**max_operations_number
25
27
 
26
- DigitsSolver.logger.info "number of operations permutations: #{number_of_possibilities}, nb op: #{nb_operations}"
28
+ DigitsSolver.logger.info "The number of operations permutations for the #{nb_operations} basic operations and a draw of #{max_operations_number + 1} numbers (ie #{max_operations_number} consecutive operations) is #{number_of_possibilities}."
27
29
 
28
30
  (0...number_of_possibilities).map do |i|
29
31
  i.to_s(nb_operations)
@@ -33,6 +35,7 @@ module DigitsSolver
33
35
  end
34
36
  end
35
37
 
38
+ # noinspection RubyInstanceMethodNamingConvention
36
39
  def apply_operations_chain_to_ordered_draw(operations_chain, ordered_draw, problem_statement)
37
40
  operations_chain.each.with_index.reduce(ordered_draw.first) do |acc, (operation, idx)|
38
41
  cur_op_res = apply_operation_to_operands(operation, acc, ordered_draw[idx + 1])
@@ -40,16 +43,16 @@ module DigitsSolver
40
43
  ops = operations_chain.take(idx + 1)
41
44
  operands = ordered_draw.take(idx + 2)
42
45
  yield DigitsSolver::Solution.new(problem_statement, operands, ops)
43
- break
46
+ return cur_op_res
47
+
44
48
  end
45
49
  cur_op_res
46
50
  end
47
51
  end
48
52
 
49
- def apply_operation_to_operands (operation, operand1, operand2)
50
- res = send(operation, operand1, operand2)
51
- DigitsSolver.logger.debug "#{operand1} #{OPERATIONS[operation]} #{operand2} = #{res}"
52
- res
53
+ def apply_operation_to_operands(operation, operand1, operand2)
54
+ # wow that's a useful one ;-), at least more understandable
55
+ send operation, operand1, operand2
53
56
  end
54
57
 
55
58
  def plus(a, b)
@@ -67,11 +70,13 @@ module DigitsSolver
67
70
  end
68
71
 
69
72
  def divide(a, b)
70
- raise DigitsSolver::Strategies::Base::OperationError, "#{a} / #{b} is not allowed as result would not be an integer" unless a % b == 0
73
+ unless (a % b).zero?
74
+ raise DigitsSolver::Strategies::Base::OperationError,
75
+ "#{a} / #{b} is not allowed as result would not be an integer"
76
+ end
71
77
 
72
78
  a / b
73
79
  end
74
-
75
80
  end
76
81
  end
77
82
  end
@@ -1,8 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DigitsSolver
2
4
  module Strategies
3
-
4
5
  module BruteForce
5
-
6
6
  include DigitsSolver::Strategies::Base
7
7
 
8
8
  def solve(problem_statement)
@@ -10,27 +10,24 @@ module DigitsSolver
10
10
  draw = problem_statement.draw
11
11
  possible_operations = possible_operations_for_ordered_draw problem_statement.max_operations_number
12
12
  # DigitsSolver.logger.debug possible_operations.inspect
13
+ attempts_count = 0
13
14
 
14
15
  draw.permutation.map do |ordered_draw|
15
-
16
- DigitsSolver.logger.debug ordered_draw.inspect
16
+ DigitsSolver.logger.debug "Testing #{ordered_draw.inspect} for all possible chains of operations"
17
17
  possible_operations.each do |operations_chain|
18
- DigitsSolver.logger.debug operations_chain.inspect
18
+ attempts_count += 1
19
19
  begin
20
20
  apply_operations_chain_to_ordered_draw(operations_chain, ordered_draw, problem_statement) do |valid_solution|
21
21
  solutions << valid_solution
22
22
  end
23
- rescue DigitsSolver::Strategies::Base::OperationError => dsboe
24
- DigitsSolver.logger.debug "#{ordered_draw.inspect} => #{operations_chain.inspect} is discarded because #{dsboe.message}"
23
+ rescue DigitsSolver::Strategies::Base::OperationError => e
24
+ DigitsSolver.logger.debug "#{ordered_draw.inspect} => #{operations_chain.inspect} is discarded because #{e.message}"
25
25
  end
26
26
  end
27
-
28
27
  end
29
- DigitsSolver.logger.info "Solutions: #{solutions.inspect}"
30
- solutions
28
+ DigitsSolver.logger.debug "Found #{solutions.count} solutions."
29
+ [solutions, attempts_count]
31
30
  end
32
-
33
31
  end
34
-
35
32
  end
36
- end
33
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DigitsSolver
4
- VERSION = '0.1.1'.freeze
4
+ VERSION = '0.1.3'
5
5
  end
data/lib/digits_solver.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "digits_solver/version"
4
- require_relative "digits_solver/error"
5
- require_relative "digits_solver/problem_statement"
6
- require_relative "digits_solver/strategies/base"
7
- require_relative "digits_solver/strategies/brute_force"
8
- require_relative "digits_solver/solution"
3
+ require_relative 'digits_solver/version'
4
+ require_relative 'digits_solver/error'
5
+ require_relative 'digits_solver/problem_statement'
6
+ require_relative 'digits_solver/strategies/base'
7
+ require_relative 'digits_solver/strategies/brute_force'
8
+ require_relative 'digits_solver/solution'
9
9
  require_relative 'digits_solver/solution_set'
10
10
 
11
11
  module DigitsSolver
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: digits_solver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent B.
@@ -24,8 +24,64 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.21'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.21'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
29
85
  requirement: !ruby/object:Gem::Requirement
30
86
  requirements:
31
87
  - - ">="
@@ -83,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
139
  - !ruby/object:Gem::Version
84
140
  version: '0'
85
141
  requirements: []
86
- rubygems_version: 3.3.26
142
+ rubygems_version: 3.1.6
87
143
  signing_key:
88
144
  specification_version: 4
89
145
  summary: Solves NYTimes Digits puzzle.