pairs 0.1.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/pairs.rb +35 -6
- data/pairs.gemspec +2 -2
- data/spec/lib/pairs_spec.rb +95 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c45b4690d8e587e6f573da694da1e9c2de38765
|
4
|
+
data.tar.gz: 8fb165db6f151c56d7f46cb02db8f7cfef578a74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe982314f97243308c4c5f5084e709c7a840ba66742a2a0450a3eca596e5599522f6954171edd4c591fdac8136c6a17a9292bee13203c489264ef276d4856659
|
7
|
+
data.tar.gz: e9b9181531de3bc6b8960b9f962a97eb093f224621fc9394c2e37de679f5fb7e366fbd583fe5f7d7a7b54e9b1803542c385cb84aceade2ad00551ecd9330e112
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.0
|
4
|
+
|
5
|
+
* Add helper constraints `together`, `separate`, `alone`, and `accompanied`
|
6
|
+
* Change max_attempts to 10,000
|
7
|
+
* Raise an error if unsolvable
|
8
|
+
* Create predicate methods for use in constraints
|
9
|
+
|
3
10
|
## 0.1.0
|
4
11
|
|
5
12
|
* Initial release, basic constraints
|
data/lib/pairs.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
class Pairs
|
2
|
+
class NoSolutionError < StandardError; end
|
3
|
+
|
2
4
|
attr_reader :max_attempts, :block
|
3
5
|
|
4
|
-
|
6
|
+
MAX_ATTEMPTS = 10_000
|
7
|
+
|
8
|
+
def initialize(max_attempts: MAX_ATTEMPTS, &block)
|
5
9
|
@max_attempts = max_attempts
|
6
10
|
@block = block
|
7
11
|
end
|
@@ -16,10 +20,6 @@ class Pairs
|
|
16
20
|
until all.empty?
|
17
21
|
these = all.sample(2)
|
18
22
|
|
19
|
-
next unless clean_room.__constraints__.all? { |constraint|
|
20
|
-
constraint.call(these)
|
21
|
-
}
|
22
|
-
|
23
23
|
result << these
|
24
24
|
|
25
25
|
these.each do |item|
|
@@ -27,8 +27,14 @@ class Pairs
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
return result
|
30
|
+
return result if clean_room.__constraints__.all? { |constraint|
|
31
|
+
result.all? { |pair|
|
32
|
+
constraint.call(pair)
|
33
|
+
}
|
34
|
+
}
|
31
35
|
end
|
36
|
+
|
37
|
+
raise NoSolutionError
|
32
38
|
end
|
33
39
|
|
34
40
|
def solution
|
@@ -54,9 +60,32 @@ class Pairs
|
|
54
60
|
__constraints__ << block
|
55
61
|
end
|
56
62
|
|
63
|
+
def together(a, b)
|
64
|
+
constraint { |both| both.include?(a) ? both.include?(b) : true }
|
65
|
+
end
|
66
|
+
|
67
|
+
def separate(a, b)
|
68
|
+
constraint { |both| both.include?(a) ? !both.include?(b) : true }
|
69
|
+
end
|
70
|
+
|
71
|
+
def alone(a)
|
72
|
+
constraint { |both| both.include?(a) ? both == [a] : true }
|
73
|
+
end
|
74
|
+
|
75
|
+
def accompanied(a)
|
76
|
+
constraint { |both| both.include?(a) ? both.count == 2 : true }
|
77
|
+
end
|
78
|
+
|
57
79
|
def method_missing(method_name, *args, &block)
|
58
80
|
return super unless args.count == 1
|
59
81
|
|
82
|
+
predicate_method_name = "#{method_name}?".intern
|
83
|
+
unless methods.include?(predicate_method_name)
|
84
|
+
define_singleton_method(predicate_method_name) do |item|
|
85
|
+
__items__[method_name].include?(item)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
60
89
|
__items__[method_name] ||= []
|
61
90
|
__items__[method_name] << args.first
|
62
91
|
end
|
data/pairs.gemspec
CHANGED
@@ -4,12 +4,12 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "pairs"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.2.0"
|
8
8
|
spec.authors = ["Justin Campbell"]
|
9
9
|
spec.email = ["justin@justincampbell.me"]
|
10
10
|
spec.summary = "Constraint solver for pairs"
|
11
11
|
spec.description = "Constraint solver for pairs"
|
12
|
-
spec.homepage = ""
|
12
|
+
spec.homepage = "https://github.com/justincampbell/pairs"
|
13
13
|
spec.license = "MIT"
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
data/spec/lib/pairs_spec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Pairs do
|
4
|
-
let(:pairs) { Pairs.new(&block) }
|
4
|
+
let(:pairs) { Pairs.new(max_attempts: max_attempts, &block) }
|
5
|
+
let(:max_attempts) { Pairs::MAX_ATTEMPTS }
|
5
6
|
let(:block) { -> { } }
|
6
7
|
let(:solution) { pairs.solution }
|
7
8
|
|
@@ -60,4 +61,97 @@ describe Pairs do
|
|
60
61
|
end
|
61
62
|
end
|
62
63
|
end
|
64
|
+
|
65
|
+
context "with an unsolvable constraint" do
|
66
|
+
let(:block) {
|
67
|
+
-> {
|
68
|
+
n 1; n 2; n 3
|
69
|
+
constraint { |both| both.reduce(:+) == 100 }
|
70
|
+
}
|
71
|
+
}
|
72
|
+
let(:max_attempts) { 1 }
|
73
|
+
|
74
|
+
generative do
|
75
|
+
it "raises a NoSolutionError" do
|
76
|
+
expect { solution }.to raise_error(Pairs::NoSolutionError)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "with predicate constraints" do
|
82
|
+
let(:block) {
|
83
|
+
-> {
|
84
|
+
good "a"; good "b"; bad "c"; bad "d"
|
85
|
+
constraint { |a, b| !(bad?(a) && bad?(b)) }
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
generative do
|
90
|
+
it "returns a solution" do
|
91
|
+
expect(solution.size).to eq(2)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#together" do
|
97
|
+
let(:block) {
|
98
|
+
-> {
|
99
|
+
item "a"; item "b"; item "c"; item "d"
|
100
|
+
together "a", "b"
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
generative do
|
105
|
+
it "keeps those 2 items together" do
|
106
|
+
expect(solution.any? { |both| both.sort == %w[a b] }).to eq(true)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#separate" do
|
112
|
+
let(:block) {
|
113
|
+
-> {
|
114
|
+
item "a"; item "b"; item "c"; item "d"
|
115
|
+
separate "a", "b"
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
generative do
|
120
|
+
it "keeps those 2 items separate" do
|
121
|
+
expect(solution.any? { |both| both.sort == %w[a b] }).to_not eq(true)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#alone" do
|
127
|
+
context "with an odd number" do
|
128
|
+
let(:block) {
|
129
|
+
-> {
|
130
|
+
item "a"; item "b"; item "c"
|
131
|
+
alone "c"
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
generative do
|
136
|
+
it "keeps that item alone" do
|
137
|
+
expect(solution.last).to eq(["c"])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "#accompanied" do
|
144
|
+
let(:block) {
|
145
|
+
-> {
|
146
|
+
item "a"; item "b"; item "c"
|
147
|
+
accompanied "c"
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
generative do
|
152
|
+
it "ensures that item is accompanied" do
|
153
|
+
expect(solution.first).to include("c")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
63
157
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pairs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Campbell
|
@@ -84,7 +84,7 @@ files:
|
|
84
84
|
- pairs.gemspec
|
85
85
|
- spec/lib/pairs_spec.rb
|
86
86
|
- spec/spec_helper.rb
|
87
|
-
homepage:
|
87
|
+
homepage: https://github.com/justincampbell/pairs
|
88
88
|
licenses:
|
89
89
|
- MIT
|
90
90
|
metadata: {}
|