digits_solver 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/Gemfile +1 -7
- data/README.md +97 -8
- data/Rakefile +4 -4
- data/digits_solver.gemspec +19 -15
- data/exe/find_nydigits_solutions +11 -11
- data/lib/digits_solver/error.rb +2 -1
- data/lib/digits_solver/problem_statement.rb +5 -5
- data/lib/digits_solver/solution.rb +11 -13
- data/lib/digits_solver/solution_set.rb +6 -10
- data/lib/digits_solver/strategies/base.rb +10 -5
- data/lib/digits_solver/strategies/brute_force.rb +9 -11
- data/lib/digits_solver/version.rb +1 -1
- data/lib/digits_solver.rb +6 -6
- metadata +58 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4525006e958912fda9a02dcae3bd4f9d1a08003ad4d28c54c8f439cc74407b77
|
4
|
+
data.tar.gz: b7351af8932b86749718e26030be4fc678f9f9637de861aefcf6a51bb6eb82f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1cc800b59af1a3264946bffa754868c6a7e805b614105443be97a0b4c881db0b0f577136db00477b61a7dd794b4c94b28a23a58d763f60d8b9e05f101d7830d
|
7
|
+
data.tar.gz: 6ec3f7bbc27edf3830caf952428266d0136fed2cf66143d9d190b68c31a16c99d260a5940e7033f8df5ff9a7f5d226c0bb4e238b8bc74aaa6cad68693249b599
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,24 +1,35 @@
|
|
1
1
|
# DigitsSolver
|
2
2
|
|
3
|
-
This is basically a coding
|
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
|
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
|
-
|
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 in an integer.
|
10
10
|
|
11
|
+
This gem implements a brute-force approach to solve the problem but is ready to host alternative strategies.
|
12
|
+
Basically this strategy won't work beyond 7 numbers in the draw (it is limited in the command line at 6 but not within
|
13
|
+
the code), as for 7 numbers within the 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
|
-
|
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
|
-
|
27
|
+
### Command line
|
19
28
|
|
20
|
-
|
21
|
-
|
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
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec)
|
7
7
|
|
8
|
-
require
|
8
|
+
require 'rubocop/rake_task'
|
9
9
|
|
10
10
|
RuboCop::RakeTask.new
|
11
11
|
|
12
|
-
task default: %i[spec
|
12
|
+
task default: %i[spec]
|
data/digits_solver.gemspec
CHANGED
@@ -1,39 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'lib/digits_solver/version'
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
6
|
+
spec.name = 'digits_solver'
|
7
7
|
spec.version = DigitsSolver::VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
8
|
+
spec.authors = ['Laurent B.']
|
9
|
+
spec.email = ['lbnetid+rb@gmail.com']
|
10
10
|
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.required_ruby_version =
|
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[
|
16
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
17
17
|
|
18
|
-
spec.metadata[
|
19
|
-
spec.metadata[
|
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 =
|
29
|
+
spec.bindir = 'exe'
|
29
30
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
-
spec.require_paths = [
|
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 '
|
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
|
data/exe/find_nydigits_solutions
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
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 =
|
9
|
-
out.puts
|
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,
|
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
|
-
|
35
|
-
help
|
33
|
+
rescue StandardError => e
|
34
|
+
warn e.message
|
35
|
+
help $stderr
|
36
36
|
end
|
data/lib/digits_solver/error.rb
CHANGED
@@ -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
|
-
|
14
|
-
|
15
|
-
|
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,31 @@
|
|
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,
|
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
|
20
|
+
DigitsSolver.logger.debug "New solution: #{inspect}"
|
21
21
|
end
|
22
22
|
|
23
|
-
def ==(
|
24
|
-
(operations_to_apply ==
|
23
|
+
def ==(other)
|
24
|
+
(operations_to_apply == other.operations_to_apply) && (operands == other.operands)
|
25
25
|
end
|
26
26
|
|
27
27
|
def to_s
|
28
|
-
res = ["Solved in #{operations_to_apply.size} operation#{operations_to_apply.size <= 1 ?
|
28
|
+
res = ["Solved in #{operations_to_apply.size} operation#{operations_to_apply.size <= 1 ? "" : "s"}:"]
|
29
29
|
res.concat to_operation_lines
|
30
30
|
res.join "\n"
|
31
31
|
end
|
@@ -50,23 +50,21 @@ module DigitsSolver
|
|
50
50
|
pp.text "Solution: '#{to_evaluable_code} = #{problem_statement.target_number}'"
|
51
51
|
pp.text ','
|
52
52
|
pp.breakable
|
53
|
-
pp.seplist(
|
53
|
+
pp.seplist(instance_variables) do |v|
|
54
54
|
pp.text "#{v}="
|
55
|
-
pp.pp
|
55
|
+
pp.pp instance_variable_get v
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
def to_evaluable_code
|
61
|
-
|
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
|
-
|
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
|
-
|
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} 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)
|
@@ -57,7 +56,7 @@ module DigitsSolver
|
|
57
56
|
end
|
58
57
|
|
59
58
|
def initialize(problem_statement, solutions, strategy)
|
60
|
-
raise DigitsSolver::Error,
|
59
|
+
raise DigitsSolver::Error, 'Invalid problem statement' unless problem_statement.is_a? DigitsSolver::ProblemStatement
|
61
60
|
|
62
61
|
@problem_statement = problem_statement
|
63
62
|
@strategy = strategy
|
@@ -68,9 +67,6 @@ module DigitsSolver
|
|
68
67
|
solutions.each do |solution|
|
69
68
|
self << solution
|
70
69
|
end
|
71
|
-
|
72
70
|
end
|
73
|
-
|
74
71
|
end
|
75
|
-
|
76
72
|
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,10 +19,11 @@ 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
|
26
|
+
number_of_possibilities = nb_operations**max_operations_number
|
25
27
|
|
26
28
|
DigitsSolver.logger.info "number of operations permutations: #{number_of_possibilities}, nb op: #{nb_operations}"
|
27
29
|
|
@@ -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])
|
@@ -46,7 +49,7 @@ module DigitsSolver
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
def apply_operation_to_operands
|
52
|
+
def apply_operation_to_operands(operation, operand1, operand2)
|
50
53
|
res = send(operation, operand1, operand2)
|
51
54
|
DigitsSolver.logger.debug "#{operand1} #{OPERATIONS[operation]} #{operand2} = #{res}"
|
52
55
|
res
|
@@ -67,11 +70,13 @@ module DigitsSolver
|
|
67
70
|
end
|
68
71
|
|
69
72
|
def divide(a, b)
|
70
|
-
|
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,25 @@ 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
16
|
DigitsSolver.logger.debug ordered_draw.inspect
|
17
17
|
possible_operations.each do |operations_chain|
|
18
|
+
attempts_count += 1
|
18
19
|
DigitsSolver.logger.debug operations_chain.inspect
|
19
20
|
begin
|
20
21
|
apply_operations_chain_to_ordered_draw(operations_chain, ordered_draw, problem_statement) do |valid_solution|
|
21
22
|
solutions << valid_solution
|
22
23
|
end
|
23
|
-
rescue DigitsSolver::Strategies::Base::OperationError =>
|
24
|
-
DigitsSolver.logger.debug "#{ordered_draw.inspect} => #{operations_chain.inspect} is discarded because #{
|
24
|
+
rescue DigitsSolver::Strategies::Base::OperationError => e
|
25
|
+
DigitsSolver.logger.debug "#{ordered_draw.inspect} => #{operations_chain.inspect} is discarded because #{e.message}"
|
25
26
|
end
|
26
27
|
end
|
27
|
-
|
28
28
|
end
|
29
|
-
DigitsSolver.logger.
|
30
|
-
solutions
|
29
|
+
DigitsSolver.logger.debug "Solutions: #{solutions.inspect}"
|
30
|
+
[solutions, attempts_count]
|
31
31
|
end
|
32
|
-
|
33
32
|
end
|
34
|
-
|
35
33
|
end
|
36
|
-
end
|
34
|
+
end
|
data/lib/digits_solver.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
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.
|
4
|
+
version: 0.1.2
|
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.
|
142
|
+
rubygems_version: 3.1.6
|
87
143
|
signing_key:
|
88
144
|
specification_version: 4
|
89
145
|
summary: Solves NYTimes Digits puzzle.
|