winston 0.0.1 → 0.0.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 +4 -4
- data/.travis.yml +3 -0
- data/CHANGELOG.md +13 -0
- data/README.md +2 -0
- data/Rakefile +6 -0
- data/lib/winston.rb +1 -0
- data/lib/winston/backtrack.rb +1 -1
- data/lib/winston/constraint.rb +18 -5
- data/lib/winston/constraints/all_different.rb +2 -1
- data/lib/winston/constraints/not_in_list.rb +18 -0
- data/lib/winston/csp.rb +9 -2
- data/spec/examples/sudoku_spec.rb +120 -0
- data/spec/winston/constraint_spec.rb +46 -1
- data/spec/winston/constraints/all_different_spec.rb +12 -7
- data/spec/winston/constraints/not_in_list_spec.rb +35 -0
- data/spec/winston/csp_spec.rb +20 -1
- data/winston.gemspec +1 -1
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86cee2ee3ce5ed70188c907b9889a640f7ea6458
|
4
|
+
data.tar.gz: 6b9601b07bdf710141e1b9894c6b8e7b8389b694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24362a9745841f0f85b255309412ee32a815ff8da790f5028c74285381908203ed11fc1231b4f1eca5185fce2f3d3d8d7aeeffbe428c0f927aabc5b68a661cf8
|
7
|
+
data.tar.gz: 90f64cc3d08170211a819d379162f029874010cf7a660d21b21f8fb6113be8dbccadb6b77f9231704328c5c149b24aa115b4f9bf6000731e3a88903b0506b158
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Winston
|
2
|
+
===============
|
3
|
+
|
4
|
+
http://github.com/dmnelson/winston
|
5
|
+
|
6
|
+
CHANGELOG
|
7
|
+
---------
|
8
|
+
|
9
|
+
### 0.0.2
|
10
|
+
* Added NotInList constraint.
|
11
|
+
* Added Sudoku example spec.
|
12
|
+
* Added 'allow_nil' option for constraints, so not all variables are necessarily required.
|
13
|
+
* Changed AllDifferent constraint to be restricted to given variables when not global
|
data/README.md
CHANGED
@@ -5,6 +5,8 @@ It provides a useful way to solve problems like resource allocation or planning
|
|
5
5
|
|
6
6
|
The most common example of usage for CSPs is probably the game [Sudoku](http://en.wikipedia.org/wiki/Sudoku).
|
7
7
|
|
8
|
+
[](http://badge.fury.io/rb/winston) [](https://travis-ci.org/dmnelson/winston) [](https://codeclimate.com/github/dmnelson/winston)
|
9
|
+
|
8
10
|
## Installation
|
9
11
|
|
10
12
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
data/lib/winston.rb
CHANGED
data/lib/winston/backtrack.rb
CHANGED
data/lib/winston/constraint.rb
CHANGED
@@ -1,19 +1,32 @@
|
|
1
1
|
module Winston
|
2
2
|
class Constraint
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
attr_reader :variables, :predicate, :allow_nil, :global
|
5
|
+
|
6
|
+
def initialize(variables: nil, predicate: nil, allow_nil: false)
|
7
|
+
@variables = [variables].flatten.compact
|
6
8
|
@predicate = predicate
|
9
|
+
@allow_nil = allow_nil
|
7
10
|
@global = @variables.empty?
|
8
11
|
end
|
9
12
|
|
10
13
|
def elegible_for?(changed_var, assignments)
|
11
|
-
|
14
|
+
global || (variables.include?(changed_var) && has_required_values?(assignments))
|
12
15
|
end
|
13
16
|
|
14
17
|
def validate(assignments)
|
15
|
-
return false unless
|
16
|
-
|
18
|
+
return false unless predicate
|
19
|
+
predicate.call(*values_at(assignments), assignments)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def values_at(assignments)
|
25
|
+
assignments.values_at(*variables)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_required_values?(assignments)
|
29
|
+
allow_nil || variables.all? { |v| assignments.key?(v) }
|
17
30
|
end
|
18
31
|
end
|
19
32
|
end
|
@@ -2,7 +2,8 @@ module Winston
|
|
2
2
|
module Constraints
|
3
3
|
class AllDifferent < Winston::Constraint
|
4
4
|
def validate(assignments)
|
5
|
-
assignments.values
|
5
|
+
values = global ? assignments.values : values_at(assignments).compact
|
6
|
+
values.uniq.size == values.size
|
6
7
|
end
|
7
8
|
end
|
8
9
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Winston
|
2
|
+
module Constraints
|
3
|
+
class NotInList < Winston::Constraint
|
4
|
+
|
5
|
+
attr_reader :list
|
6
|
+
|
7
|
+
def initialize(variables: nil, allow_nil: false, list: [])
|
8
|
+
super(variables: variables, allow_nil: allow_nil)
|
9
|
+
@list = list
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate(assignments)
|
13
|
+
values = global ? assignments.values : values_at(assignments)
|
14
|
+
!values.any? { |v| list.include?(v) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/winston/csp.rb
CHANGED
@@ -17,8 +17,8 @@ module Winston
|
|
17
17
|
variables[name] = Variable.new(name, value: value, domain: domain)
|
18
18
|
end
|
19
19
|
|
20
|
-
def add_constraint(*variables, constraint: nil, &block)
|
21
|
-
constraint ||= Constraint.new(variables, block)
|
20
|
+
def add_constraint(*variables, constraint: nil, allow_nil: false, &block)
|
21
|
+
constraint ||= Constraint.new(variables: variables, allow_nil: allow_nil, predicate: block)
|
22
22
|
constraints << constraint
|
23
23
|
end
|
24
24
|
|
@@ -29,6 +29,13 @@ module Winston
|
|
29
29
|
true
|
30
30
|
end
|
31
31
|
|
32
|
+
def domain_for(variable_name)
|
33
|
+
variable = variables[variable_name]
|
34
|
+
return [] if variable.nil? || variable.domain.nil?
|
35
|
+
|
36
|
+
variable.domain.values
|
37
|
+
end
|
38
|
+
|
32
39
|
private
|
33
40
|
|
34
41
|
def var_assignments
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require "winston"
|
2
|
+
|
3
|
+
describe "Sudoku Example" do
|
4
|
+
let(:csp) { Winston::CSP.new }
|
5
|
+
|
6
|
+
describe "Unique values for every row, column and quadrant" do
|
7
|
+
before do
|
8
|
+
domain = [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
9
|
+
|
10
|
+
# Adding variables
|
11
|
+
1.upto(9).each do |x|
|
12
|
+
1.upto(9).each do |j|
|
13
|
+
csp.add_variable({ x: x, y: j }, domain: domain)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
variables = csp.variables.keys
|
18
|
+
|
19
|
+
# add columns and rows constraints
|
20
|
+
1.upto(9).each do |i|
|
21
|
+
column = variables.select { |name| name[:x] == i }
|
22
|
+
row = variables.select { |name| name[:y] == i }
|
23
|
+
|
24
|
+
csp.add_constraint constraint: Winston::Constraints::AllDifferent.new(variables: row, allow_nil: true)
|
25
|
+
csp.add_constraint constraint: Winston::Constraints::AllDifferent.new(variables: column, allow_nil: true)
|
26
|
+
end
|
27
|
+
|
28
|
+
# blocks
|
29
|
+
variables.each_slice(3).group_by { |i| (i[0][:y] -1) % 9 }.values.flatten.each_slice(9).each do |vars|
|
30
|
+
csp.add_constraint constraint: Winston::Constraints::AllDifferent.new(variables: vars, allow_nil: true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return a valid solution" do
|
35
|
+
expect(csp.solve).to eq({
|
36
|
+
{:x=>1, :y=>1}=>1,
|
37
|
+
{:x=>1, :y=>2}=>2,
|
38
|
+
{:x=>1, :y=>3}=>3,
|
39
|
+
{:x=>1, :y=>4}=>4,
|
40
|
+
{:x=>1, :y=>5}=>5,
|
41
|
+
{:x=>1, :y=>6}=>6,
|
42
|
+
{:x=>1, :y=>7}=>7,
|
43
|
+
{:x=>1, :y=>8}=>8,
|
44
|
+
{:x=>1, :y=>9}=>9,
|
45
|
+
{:x=>2, :y=>1}=>4,
|
46
|
+
{:x=>2, :y=>2}=>5,
|
47
|
+
{:x=>2, :y=>3}=>6,
|
48
|
+
{:x=>2, :y=>4}=>7,
|
49
|
+
{:x=>2, :y=>5}=>8,
|
50
|
+
{:x=>2, :y=>6}=>9,
|
51
|
+
{:x=>2, :y=>7}=>1,
|
52
|
+
{:x=>2, :y=>8}=>2,
|
53
|
+
{:x=>2, :y=>9}=>3,
|
54
|
+
{:x=>3, :y=>1}=>7,
|
55
|
+
{:x=>3, :y=>2}=>8,
|
56
|
+
{:x=>3, :y=>3}=>9,
|
57
|
+
{:x=>3, :y=>4}=>1,
|
58
|
+
{:x=>3, :y=>5}=>2,
|
59
|
+
{:x=>3, :y=>6}=>3,
|
60
|
+
{:x=>3, :y=>7}=>4,
|
61
|
+
{:x=>3, :y=>8}=>5,
|
62
|
+
{:x=>3, :y=>9}=>6,
|
63
|
+
{:x=>4, :y=>1}=>2,
|
64
|
+
{:x=>4, :y=>2}=>1,
|
65
|
+
{:x=>4, :y=>3}=>4,
|
66
|
+
{:x=>4, :y=>4}=>3,
|
67
|
+
{:x=>4, :y=>5}=>6,
|
68
|
+
{:x=>4, :y=>6}=>5,
|
69
|
+
{:x=>4, :y=>7}=>8,
|
70
|
+
{:x=>4, :y=>8}=>9,
|
71
|
+
{:x=>4, :y=>9}=>7,
|
72
|
+
{:x=>5, :y=>1}=>3,
|
73
|
+
{:x=>5, :y=>2}=>6,
|
74
|
+
{:x=>5, :y=>3}=>5,
|
75
|
+
{:x=>5, :y=>4}=>8,
|
76
|
+
{:x=>5, :y=>5}=>9,
|
77
|
+
{:x=>5, :y=>6}=>7,
|
78
|
+
{:x=>5, :y=>7}=>2,
|
79
|
+
{:x=>5, :y=>8}=>1,
|
80
|
+
{:x=>5, :y=>9}=>4,
|
81
|
+
{:x=>6, :y=>1}=>8,
|
82
|
+
{:x=>6, :y=>2}=>9,
|
83
|
+
{:x=>6, :y=>3}=>7,
|
84
|
+
{:x=>6, :y=>4}=>2,
|
85
|
+
{:x=>6, :y=>5}=>1,
|
86
|
+
{:x=>6, :y=>6}=>4,
|
87
|
+
{:x=>6, :y=>7}=>3,
|
88
|
+
{:x=>6, :y=>8}=>6,
|
89
|
+
{:x=>6, :y=>9}=>5,
|
90
|
+
{:x=>7, :y=>1}=>5,
|
91
|
+
{:x=>7, :y=>2}=>3,
|
92
|
+
{:x=>7, :y=>3}=>1,
|
93
|
+
{:x=>7, :y=>4}=>6,
|
94
|
+
{:x=>7, :y=>5}=>4,
|
95
|
+
{:x=>7, :y=>6}=>2,
|
96
|
+
{:x=>7, :y=>7}=>9,
|
97
|
+
{:x=>7, :y=>8}=>7,
|
98
|
+
{:x=>7, :y=>9}=>8,
|
99
|
+
{:x=>8, :y=>1}=>6,
|
100
|
+
{:x=>8, :y=>2}=>4,
|
101
|
+
{:x=>8, :y=>3}=>2,
|
102
|
+
{:x=>8, :y=>4}=>9,
|
103
|
+
{:x=>8, :y=>5}=>7,
|
104
|
+
{:x=>8, :y=>6}=>8,
|
105
|
+
{:x=>8, :y=>7}=>5,
|
106
|
+
{:x=>8, :y=>8}=>3,
|
107
|
+
{:x=>8, :y=>9}=>1,
|
108
|
+
{:x=>9, :y=>1}=>9,
|
109
|
+
{:x=>9, :y=>2}=>7,
|
110
|
+
{:x=>9, :y=>3}=>8,
|
111
|
+
{:x=>9, :y=>4}=>5,
|
112
|
+
{:x=>9, :y=>5}=>3,
|
113
|
+
{:x=>9, :y=>6}=>1,
|
114
|
+
{:x=>9, :y=>7}=>6,
|
115
|
+
{:x=>9, :y=>8}=>4,
|
116
|
+
{:x=>9, :y=>9}=>2
|
117
|
+
})
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -4,7 +4,8 @@ describe Winston::Constraint do
|
|
4
4
|
|
5
5
|
let(:variables) { nil }
|
6
6
|
let(:predicate) { nil }
|
7
|
-
|
7
|
+
let(:allow_nil) { false }
|
8
|
+
subject { described_class.new(variables: variables, predicate: predicate, allow_nil: allow_nil) }
|
8
9
|
|
9
10
|
describe "#elegible_for?" do
|
10
11
|
context "global" do
|
@@ -49,6 +50,50 @@ describe Winston::Constraint do
|
|
49
50
|
expect(subject.elegible_for?(:a, { b: 2 })).to be(false)
|
50
51
|
end
|
51
52
|
end
|
53
|
+
|
54
|
+
context "allowing nil" do
|
55
|
+
let(:allow_nil) { true }
|
56
|
+
|
57
|
+
context "for specific variable" do
|
58
|
+
let(:variables) { [:a] }
|
59
|
+
|
60
|
+
it "should return true when that variable is changed" do
|
61
|
+
expect(subject.elegible_for?(:a, { a: nil })).to be(true)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return false when that variable isn't the one changed" do
|
65
|
+
expect(subject.elegible_for?(:b, { a: 1, b: 2 })).to be(false)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return true when that variable is changed but doesn't have a value" do
|
69
|
+
expect(subject.elegible_for?(:a, { b: 2 })).to be(true)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "for multiple variables" do
|
74
|
+
let(:variables) { [:a, :b] }
|
75
|
+
|
76
|
+
it "should return true when one of those variables is changed" do
|
77
|
+
expect(subject.elegible_for?(:a, { a: 1, b: nil })).to be(true)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return false when one of those variables isn't the one changed" do
|
81
|
+
expect(subject.elegible_for?(:c, { a: 1, b: 2 })).to be(false)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return true when one of those variables is changed but doesn't have a value for every one of them" do
|
85
|
+
expect(subject.elegible_for?(:b, { b: 2 })).to be(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return true when one of those variables is changed but doesn't have a value for every one of them" do
|
89
|
+
expect(subject.elegible_for?(:a, { b: 2 })).to be(true)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return true when one of those variables is changed but doesn't have a value for any of them" do
|
93
|
+
expect(subject.elegible_for?(:a, {})).to be(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
52
97
|
end
|
53
98
|
|
54
99
|
describe "#validate" do
|
@@ -3,13 +3,6 @@ require "winston"
|
|
3
3
|
describe Winston::Constraints::AllDifferent do
|
4
4
|
subject { described_class.new }
|
5
5
|
|
6
|
-
describe "#elegible_for?" do
|
7
|
-
it "should be elegible for everything" do
|
8
|
-
expect(subject.elegible_for?(:a, {})).to be(true)
|
9
|
-
expect(subject.elegible_for?(:b, { a: 1 })).to be(true)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
6
|
describe "#validate" do
|
14
7
|
it "should return 'true' when all values are unique" do
|
15
8
|
expect(subject.validate(a: 1, b: 2, c: 3, d: 4)).to be(true)
|
@@ -18,5 +11,17 @@ describe Winston::Constraints::AllDifferent do
|
|
18
11
|
it "should return 'false' when not all values are unique" do
|
19
12
|
expect(subject.validate(a: 1, b: 2, c: 2, d: 4)).to be(false)
|
20
13
|
end
|
14
|
+
|
15
|
+
context "for specific variables" do
|
16
|
+
subject { described_class.new(variables: [:a, :b, :c]) }
|
17
|
+
|
18
|
+
it "should return 'true' when all values are unique" do
|
19
|
+
expect(subject.validate(a: 1, b: 2, c: 3, d: 3)).to be(true)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return 'false' when not all values are unique" do
|
23
|
+
expect(subject.validate(a: 1, b: 2, c: 2, d: 4)).to be(false)
|
24
|
+
end
|
25
|
+
end
|
21
26
|
end
|
22
27
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "winston"
|
2
|
+
|
3
|
+
describe Winston::Constraints::NotInList do
|
4
|
+
subject { described_class.new(list: [ 4, 5, 6 ]) }
|
5
|
+
|
6
|
+
describe "#validate" do
|
7
|
+
it "should return 'true' none of the values are on the list" do
|
8
|
+
expect(subject.validate(a: 1, b: 2, c: 3, d: 3)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return 'false' when any of the values are on the list" do
|
12
|
+
expect(subject.validate(a: 1, b: 2, c: 2, d: 4)).to be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return 'false' when all the values are on the list" do
|
16
|
+
expect(subject.validate(a: 4, b: 6, c: 5, d: 4)).to be(false)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "for specific variables" do
|
20
|
+
subject { described_class.new(variables: [:a, :b, :c], list: [ 4, 5, 6 ]) }
|
21
|
+
|
22
|
+
it "should return 'true' when none of the values are on the list" do
|
23
|
+
expect(subject.validate(a: 1, b: 2, c: 3, d: 6)).to be(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return 'false' when any of the values are on the list" do
|
27
|
+
expect(subject.validate(a: 1, b: 2, c: 5, d: 3)).to be(false)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return 'false' when all the values are on the list" do
|
31
|
+
expect(subject.validate(a: 4, b: 6, c: 5, d: 3)).to be(false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/winston/csp_spec.rb
CHANGED
@@ -28,7 +28,7 @@ describe Winston::CSP do
|
|
28
28
|
describe "#add_constraint" do
|
29
29
|
let(:constraint) { double("Constraint") }
|
30
30
|
it "should build a constraint for the given block" do
|
31
|
-
expect(Winston::Constraint).to receive(:new).with([:a, :b], an_instance_of(Proc)).once.and_return(constraint)
|
31
|
+
expect(Winston::Constraint).to receive(:new).with(variables: [:a, :b], allow_nil: false, predicate: an_instance_of(Proc)).once.and_return(constraint)
|
32
32
|
subject.add_constraint(:a, :b) { true }
|
33
33
|
expect(subject.constraints).to include(constraint)
|
34
34
|
end
|
@@ -60,6 +60,25 @@ describe Winston::CSP do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
describe "#domain_for" do
|
64
|
+
before do
|
65
|
+
subject.add_variable :a, value: 1
|
66
|
+
subject.add_variable :b, domain: [1, 2]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns domain values for a given variable" do
|
70
|
+
expect(subject.domain_for(:b)).to eq([1, 2])
|
71
|
+
end
|
72
|
+
|
73
|
+
it "returns an empty list when a variable doesn't exist in the problem" do
|
74
|
+
expect(subject.domain_for(:c)).to be_empty
|
75
|
+
end
|
76
|
+
|
77
|
+
it "return an empty list when a variable doesn't have a domain" do
|
78
|
+
expect(subject.domain_for(:a)).to be_empty
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
63
82
|
describe "#solve" do
|
64
83
|
let(:solver) { double("Solver") }
|
65
84
|
before do
|
data/winston.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: winston
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Michael Nelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -59,6 +59,8 @@ extensions: []
|
|
59
59
|
extra_rdoc_files: []
|
60
60
|
files:
|
61
61
|
- ".gitignore"
|
62
|
+
- ".travis.yml"
|
63
|
+
- CHANGELOG.md
|
62
64
|
- Gemfile
|
63
65
|
- LICENSE
|
64
66
|
- README.md
|
@@ -67,13 +69,16 @@ files:
|
|
67
69
|
- lib/winston/backtrack.rb
|
68
70
|
- lib/winston/constraint.rb
|
69
71
|
- lib/winston/constraints/all_different.rb
|
72
|
+
- lib/winston/constraints/not_in_list.rb
|
70
73
|
- lib/winston/csp.rb
|
71
74
|
- lib/winston/domain.rb
|
72
75
|
- lib/winston/variable.rb
|
73
76
|
- spec/examples/numbers_spec.rb
|
77
|
+
- spec/examples/sudoku_spec.rb
|
74
78
|
- spec/winston/backtrack_spec.rb
|
75
79
|
- spec/winston/constraint_spec.rb
|
76
80
|
- spec/winston/constraints/all_different_spec.rb
|
81
|
+
- spec/winston/constraints/not_in_list_spec.rb
|
77
82
|
- spec/winston/csp_spec.rb
|
78
83
|
- spec/winston/domain_spec.rb
|
79
84
|
- spec/winston/variable_spec.rb
|
@@ -104,9 +109,11 @@ specification_version: 4
|
|
104
109
|
summary: Constraint Satisfaction Problem (CSP) implementation for Ruby
|
105
110
|
test_files:
|
106
111
|
- spec/examples/numbers_spec.rb
|
112
|
+
- spec/examples/sudoku_spec.rb
|
107
113
|
- spec/winston/backtrack_spec.rb
|
108
114
|
- spec/winston/constraint_spec.rb
|
109
115
|
- spec/winston/constraints/all_different_spec.rb
|
116
|
+
- spec/winston/constraints/not_in_list_spec.rb
|
110
117
|
- spec/winston/csp_spec.rb
|
111
118
|
- spec/winston/domain_spec.rb
|
112
119
|
- spec/winston/variable_spec.rb
|