mendel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ require "priority_queue" # gem
2
+ require 'json'
3
+
4
+ # Wrapper to allow swapping implementations
5
+ module Mendel
6
+ class MinPriorityQueue
7
+
8
+ def initialize
9
+ self.wrapped_queue = PriorityQueue.new
10
+ end
11
+
12
+ def push(item, priority)
13
+ wrapped_queue.push(item, priority)
14
+ end
15
+
16
+ def pop
17
+ wrapped_queue.delete_min
18
+ end
19
+
20
+ def length
21
+ wrapped_queue.length
22
+ end
23
+
24
+ def dump
25
+ [].tap {|items|
26
+ items << pop while length > 0
27
+ }
28
+ end
29
+
30
+ def dump_json
31
+ JSON.dump(dump)
32
+ end
33
+
34
+ # TODO - make the load methods class methods
35
+ def load(items)
36
+ items.each do |item|
37
+ push(*item)
38
+ end
39
+ end
40
+
41
+ def load_json(json)
42
+ load(JSON.parse(json))
43
+ end
44
+
45
+ private
46
+ attr_accessor :wrapped_queue
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ require "mendel/combiner"
2
+
3
+ module Mendel
4
+ class ObservableCombiner
5
+ include Mendel::Combiner
6
+ include Observable
7
+
8
+ def queueable_item_for(coordinates)
9
+ super.tap {|combo| notify(:scored, combo) }
10
+ end
11
+
12
+ def pop_queue
13
+ super.tap { |pair|
14
+ return if pair.nil?
15
+ coords = pair[0].fetch('coordinates')
16
+ notify(:returned, {'coordinates' => coords, 'score' => pair[1]}) unless pair.nil?
17
+ }
18
+ end
19
+
20
+ def notify(*args)
21
+ changed && notify_observers(*args)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Mendel
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'base'
2
+ require 'colorize'
3
+
4
+ module Mendel
5
+ module Visualizers
6
+ class ASCII < Base
7
+
8
+ def initialize(*args)
9
+ super
10
+ @point_width = 8
11
+ end
12
+
13
+ def output
14
+ horizontal_space = ' '
15
+ output_lines = []
16
+ grid.each_with_index do |line, y|
17
+ x_label = axis_label_for(list1[y])
18
+ line_string = x_label
19
+ points_on_line = line.each_with_index.map { |column, x|
20
+ grid_point_for(*grid[y][x])
21
+ }
22
+ line_string.concat(points_on_line.join(horizontal_space))
23
+ output_lines.unshift(line_string)
24
+ end
25
+ y_labels = list2.map {|item| axis_label_for(item) }
26
+
27
+ footer_line = "#{fix_point_width('')}#{y_labels.join(horizontal_space)}"
28
+ output_lines = output_lines.join("\n\n\n")
29
+ output_lines.concat("\n#{footer_line}\n")
30
+ end
31
+
32
+ def axis_label_for(list_item)
33
+ fix_point_width(list_item.to_s)
34
+ end
35
+
36
+ def grid_point_for(status, score=nil)
37
+ case status
38
+ when :unscored then fix_point_width('')
39
+ when :scored then fix_point_width(score.to_s).green
40
+ when :returned then fix_point_width(score.to_s).blue
41
+ else raise UnknownPointType, status.inspect
42
+ end
43
+ end
44
+
45
+ def fix_point_width(string)
46
+ string[0...point_width].rjust(point_width, ' ')
47
+ end
48
+
49
+ private
50
+
51
+ attr_reader :point_width
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ module Mendel
2
+ module Visualizers
3
+ class Base
4
+ attr_accessor :combiner, :list1, :list2
5
+ attr_reader :grid
6
+
7
+ def self.max_list_length
8
+ 10 # To be decided
9
+ end
10
+
11
+ def initialize(combiner)
12
+ self.combiner = combiner
13
+ combiner.add_observer(self)
14
+ lists = combiner.lists
15
+ check_list_validity(lists)
16
+ self.list1, self.list2 = lists
17
+ self.grid = Array.new(list1.size) { Array.new(list2.size, [:unscored]) }
18
+ end
19
+
20
+ def update(status, combo)
21
+ y, x = combo.fetch('coordinates')
22
+ score = combo.fetch('score')
23
+ grid[y][x] = [status, score]
24
+ end
25
+
26
+ private
27
+
28
+ attr_writer :grid
29
+
30
+ def check_list_validity(lists)
31
+ raise InvalidListCount, "Can only graph in 2 dimensions" unless lists.length == 2
32
+ raise ListsTooLarge, "Need to fit on screen" if lists.any? {|l| l.length > self.class.max_list_length }
33
+ end
34
+
35
+ InvalidListCount = Class.new(StandardError)
36
+ ListsTooLarge = Class.new(StandardError)
37
+
38
+ UnknownPointType = Class.new(StandardError)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mendel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mendel"
8
+ spec.version = Mendel::VERSION
9
+ spec.authors = ["Nathan Long"]
10
+ spec.email = ["nathanmlong@gmail.com"]
11
+ spec.summary = %q{Mendel breeds the best combinations of lists that you provide.}
12
+ spec.description = %q{Mendel breeds the best combinations of N lists without building all possible combinations.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "PriorityQueue", "~> 0.1.2"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 3.4"
26
+ spec.add_development_dependency "pry", "~> 0.10"
27
+ spec.add_development_dependency "colorize", "~> 0.7.7"
28
+ end
@@ -0,0 +1,13 @@
1
+ EXAMPLE_INPUT = {
2
+ incrementing_integers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100],
3
+
4
+ incrementing_decimals: [1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 8.1, 9.1, 10.1, 11.1, 12.1, 13.1, 14.1, 15.1, 16.1, 17.1, 18.1, 19.1, 20.1, 21.1, 22.1, 23.1, 24.1, 25.1, 26.1, 27.1, 28.1, 29.1, 30.1, 31.1, 32.1, 33.1, 34.1, 35.1, 36.1, 37.1, 38.1, 39.1, 40.1, 41.1, 42.1, 43.1, 44.1, 45.1, 46.1, 47.1, 48.1, 49.1, 50.1, 51.1, 52.1, 53.1, 54.1, 55.1, 56.1, 57.1, 58.1, 59.1, 60.1, 61.1, 62.1, 63.1, 64.1, 65.1, 66.1, 67.1, 68.1, 69.1, 70.1, 71.1, 72.1, 73.1, 74.1, 75.1, 76.1, 77.1, 78.1, 79.1, 80.1, 81.1, 82.1, 83.1, 84.1, 85.1, 86.1, 87.1, 88.1, 89.1, 90.1, 91.1, 92.1, 93.1, 94.1, 95.1, 96.1, 97.1, 98.1, 99.1, 100.1],
5
+
6
+ repeats: [1, 2, 3, 3, 4, 5, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 38, 39, 40, 41, 41, 42, 43, 44, 44, 45, 46, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 70, 71, 72, 73, 74, 75, 76, 77, 78, 78, 79, 80, 80, 81, 82, 83],
7
+
8
+ skips: [0, 2, 3, 4, 5, 7, 9, 10, 11, 12, 13, 15, 16, 17, 19, 20, 23, 24, 25, 26, 27, 29, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 49, 50, 51, 53, 54, 55, 56, 58, 59, 60, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 78, 83, 87, 88, 90, 92, 94, 95, 99, 101, 102, 104, 105, 106, 107, 110, 111, 112, 114, 115, 116, 117, 119, 120, 121, 122, 125, 126, 127, 128, 130, 131, 133, 134, 135, 136, 137, 138, 139, 140, 145],
9
+
10
+ repeats_and_skips: [1, 2, 2, 9, 11, 11, 13, 14, 15, 16, 17, 17, 18, 20, 20, 22, 23, 24, 24, 25, 26, 26, 26, 30, 30, 32, 33, 34, 34, 35, 35, 35, 35, 37, 38, 39, 39, 39, 40, 40, 41, 42, 42, 44, 44, 45, 46, 46, 46, 48, 49, 50, 50, 51, 52, 53, 54, 55, 57, 57, 61, 61, 62, 66, 66, 69, 72, 73, 73, 74, 76, 76, 77, 79, 82, 82, 82, 83, 83, 85, 87, 88, 88, 91, 91, 92, 92, 92, 93, 93, 93, 94, 95, 95, 95, 97, 97, 98, 98, 98],
11
+
12
+ short_list: [1, 2, 3],
13
+ }
@@ -0,0 +1,303 @@
1
+ $different_lengths =
2
+ [
3
+ [[1, 1], 2],
4
+ [[1, 2], 3],
5
+ [[2, 1], 3],
6
+ [[1, 3], 4],
7
+ [[3, 1], 4],
8
+ [[2, 2], 4],
9
+ [[2, 3], 5],
10
+ [[4, 1], 5],
11
+ [[3, 2], 5],
12
+ [[3, 3], 6],
13
+ [[4, 2], 6],
14
+ [[5, 1], 6],
15
+ [[6, 1], 7],
16
+ [[5, 2], 7],
17
+ [[4, 3], 7],
18
+ [[5, 3], 8],
19
+ [[6, 2], 8],
20
+ [[7, 1], 8],
21
+ [[6, 3], 9],
22
+ [[8, 1], 9],
23
+ [[7, 2], 9],
24
+ [[9, 1], 10],
25
+ [[8, 2], 10],
26
+ [[7, 3], 10],
27
+ [[8, 3], 11],
28
+ [[9, 2], 11],
29
+ [[10, 1], 11],
30
+ [[9, 3], 12],
31
+ [[11, 1], 12],
32
+ [[10, 2], 12],
33
+ [[12, 1], 13],
34
+ [[11, 2], 13],
35
+ [[10, 3], 13],
36
+ [[13, 1], 14],
37
+ [[12, 2], 14],
38
+ [[11, 3], 14],
39
+ [[12, 3], 15],
40
+ [[13, 2], 15],
41
+ [[14, 1], 15],
42
+ [[15, 1], 16],
43
+ [[14, 2], 16],
44
+ [[13, 3], 16],
45
+ [[14, 3], 17],
46
+ [[15, 2], 17],
47
+ [[16, 1], 17],
48
+ [[15, 3], 18],
49
+ [[17, 1], 18],
50
+ [[16, 2], 18],
51
+ [[18, 1], 19],
52
+ [[17, 2], 19],
53
+ [[16, 3], 19],
54
+ [[17, 3], 20],
55
+ [[19, 1], 20],
56
+ [[18, 2], 20],
57
+ [[18, 3], 21],
58
+ [[19, 2], 21],
59
+ [[20, 1], 21],
60
+ [[19, 3], 22],
61
+ [[21, 1], 22],
62
+ [[20, 2], 22],
63
+ [[22, 1], 23],
64
+ [[21, 2], 23],
65
+ [[20, 3], 23],
66
+ [[21, 3], 24],
67
+ [[22, 2], 24],
68
+ [[23, 1], 24],
69
+ [[22, 3], 25],
70
+ [[24, 1], 25],
71
+ [[23, 2], 25],
72
+ [[23, 3], 26],
73
+ [[25, 1], 26],
74
+ [[24, 2], 26],
75
+ [[24, 3], 27],
76
+ [[25, 2], 27],
77
+ [[26, 1], 27],
78
+ [[27, 1], 28],
79
+ [[26, 2], 28],
80
+ [[25, 3], 28],
81
+ [[26, 3], 29],
82
+ [[27, 2], 29],
83
+ [[28, 1], 29],
84
+ [[27, 3], 30],
85
+ [[29, 1], 30],
86
+ [[28, 2], 30],
87
+ [[30, 1], 31],
88
+ [[29, 2], 31],
89
+ [[28, 3], 31],
90
+ [[29, 3], 32],
91
+ [[31, 1], 32],
92
+ [[30, 2], 32],
93
+ [[30, 3], 33],
94
+ [[31, 2], 33],
95
+ [[32, 1], 33],
96
+ [[31, 3], 34],
97
+ [[33, 1], 34],
98
+ [[32, 2], 34],
99
+ [[32, 3], 35],
100
+ [[34, 1], 35],
101
+ [[33, 2], 35],
102
+ [[33, 3], 36],
103
+ [[34, 2], 36],
104
+ [[35, 1], 36],
105
+ [[34, 3], 37],
106
+ [[36, 1], 37],
107
+ [[35, 2], 37],
108
+ [[37, 1], 38],
109
+ [[36, 2], 38],
110
+ [[35, 3], 38],
111
+ [[38, 1], 39],
112
+ [[37, 2], 39],
113
+ [[36, 3], 39],
114
+ [[37, 3], 40],
115
+ [[38, 2], 40],
116
+ [[39, 1], 40],
117
+ [[40, 1], 41],
118
+ [[39, 2], 41],
119
+ [[38, 3], 41],
120
+ [[39, 3], 42],
121
+ [[40, 2], 42],
122
+ [[41, 1], 42],
123
+ [[40, 3], 43],
124
+ [[42, 1], 43],
125
+ [[41, 2], 43],
126
+ [[43, 1], 44],
127
+ [[42, 2], 44],
128
+ [[41, 3], 44],
129
+ [[44, 1], 45],
130
+ [[43, 2], 45],
131
+ [[42, 3], 45],
132
+ [[43, 3], 46],
133
+ [[44, 2], 46],
134
+ [[45, 1], 46],
135
+ [[44, 3], 47],
136
+ [[46, 1], 47],
137
+ [[45, 2], 47],
138
+ [[45, 3], 48],
139
+ [[46, 2], 48],
140
+ [[47, 1], 48],
141
+ [[46, 3], 49],
142
+ [[48, 1], 49],
143
+ [[47, 2], 49],
144
+ [[47, 3], 50],
145
+ [[49, 1], 50],
146
+ [[48, 2], 50],
147
+ [[48, 3], 51],
148
+ [[49, 2], 51],
149
+ [[50, 1], 51],
150
+ [[49, 3], 52],
151
+ [[50, 2], 52],
152
+ [[51, 1], 52],
153
+ [[50, 3], 53],
154
+ [[51, 2], 53],
155
+ [[52, 1], 53],
156
+ [[51, 3], 54],
157
+ [[53, 1], 54],
158
+ [[52, 2], 54],
159
+ [[54, 1], 55],
160
+ [[53, 2], 55],
161
+ [[52, 3], 55],
162
+ [[53, 3], 56],
163
+ [[55, 1], 56],
164
+ [[54, 2], 56],
165
+ [[54, 3], 57],
166
+ [[55, 2], 57],
167
+ [[56, 1], 57],
168
+ [[55, 3], 58],
169
+ [[57, 1], 58],
170
+ [[56, 2], 58],
171
+ [[56, 3], 59],
172
+ [[58, 1], 59],
173
+ [[57, 2], 59],
174
+ [[57, 3], 60],
175
+ [[58, 2], 60],
176
+ [[59, 1], 60],
177
+ [[58, 3], 61],
178
+ [[60, 1], 61],
179
+ [[59, 2], 61],
180
+ [[61, 1], 62],
181
+ [[60, 2], 62],
182
+ [[59, 3], 62],
183
+ [[62, 1], 63],
184
+ [[61, 2], 63],
185
+ [[60, 3], 63],
186
+ [[61, 3], 64],
187
+ [[62, 2], 64],
188
+ [[63, 1], 64],
189
+ [[62, 3], 65],
190
+ [[64, 1], 65],
191
+ [[63, 2], 65],
192
+ [[63, 3], 66],
193
+ [[64, 2], 66],
194
+ [[65, 1], 66],
195
+ [[64, 3], 67],
196
+ [[66, 1], 67],
197
+ [[65, 2], 67],
198
+ [[67, 1], 68],
199
+ [[66, 2], 68],
200
+ [[65, 3], 68],
201
+ [[66, 3], 69],
202
+ [[68, 1], 69],
203
+ [[67, 2], 69],
204
+ [[67, 3], 70],
205
+ [[68, 2], 70],
206
+ [[69, 1], 70],
207
+ [[68, 3], 71],
208
+ [[70, 1], 71],
209
+ [[69, 2], 71],
210
+ [[71, 1], 72],
211
+ [[70, 2], 72],
212
+ [[69, 3], 72],
213
+ [[70, 3], 73],
214
+ [[71, 2], 73],
215
+ [[72, 1], 73],
216
+ [[71, 3], 74],
217
+ [[73, 1], 74],
218
+ [[72, 2], 74],
219
+ [[72, 3], 75],
220
+ [[74, 1], 75],
221
+ [[73, 2], 75],
222
+ [[73, 3], 76],
223
+ [[74, 2], 76],
224
+ [[75, 1], 76],
225
+ [[74, 3], 77],
226
+ [[75, 2], 77],
227
+ [[76, 1], 77],
228
+ [[75, 3], 78],
229
+ [[76, 2], 78],
230
+ [[77, 1], 78],
231
+ [[76, 3], 79],
232
+ [[78, 1], 79],
233
+ [[77, 2], 79],
234
+ [[79, 1], 80],
235
+ [[78, 2], 80],
236
+ [[77, 3], 80],
237
+ [[78, 3], 81],
238
+ [[80, 1], 81],
239
+ [[79, 2], 81],
240
+ [[79, 3], 82],
241
+ [[80, 2], 82],
242
+ [[81, 1], 82],
243
+ [[80, 3], 83],
244
+ [[82, 1], 83],
245
+ [[81, 2], 83],
246
+ [[81, 3], 84],
247
+ [[83, 1], 84],
248
+ [[82, 2], 84],
249
+ [[82, 3], 85],
250
+ [[83, 2], 85],
251
+ [[84, 1], 85],
252
+ [[83, 3], 86],
253
+ [[85, 1], 86],
254
+ [[84, 2], 86],
255
+ [[86, 1], 87],
256
+ [[85, 2], 87],
257
+ [[84, 3], 87],
258
+ [[87, 1], 88],
259
+ [[86, 2], 88],
260
+ [[85, 3], 88],
261
+ [[86, 3], 89],
262
+ [[87, 2], 89],
263
+ [[88, 1], 89],
264
+ [[87, 3], 90],
265
+ [[89, 1], 90],
266
+ [[88, 2], 90],
267
+ [[88, 3], 91],
268
+ [[89, 2], 91],
269
+ [[90, 1], 91],
270
+ [[89, 3], 92],
271
+ [[91, 1], 92],
272
+ [[90, 2], 92],
273
+ [[92, 1], 93],
274
+ [[91, 2], 93],
275
+ [[90, 3], 93],
276
+ [[93, 1], 94],
277
+ [[92, 2], 94],
278
+ [[91, 3], 94],
279
+ [[92, 3], 95],
280
+ [[93, 2], 95],
281
+ [[94, 1], 95],
282
+ [[93, 3], 96],
283
+ [[94, 2], 96],
284
+ [[95, 1], 96],
285
+ [[94, 3], 97],
286
+ [[95, 2], 97],
287
+ [[96, 1], 97],
288
+ [[95, 3], 98],
289
+ [[97, 1], 98],
290
+ [[96, 2], 98],
291
+ [[96, 3], 99],
292
+ [[97, 2], 99],
293
+ [[98, 1], 99],
294
+ [[97, 3], 100],
295
+ [[98, 2], 100],
296
+ [[99, 1], 100],
297
+ [[98, 3], 101],
298
+ [[100, 1], 101],
299
+ [[99, 2], 101],
300
+ [[99, 3], 102],
301
+ [[100, 2], 102],
302
+ [[100, 3], 103],
303
+ ]