rubylabs 0.7.5 → 0.8.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.
- data/LICENSE +1 -1
- data/VERSION +1 -1
- data/data/huffman/testcodes.txt +30 -0
- data/data/huffman/testwords.txt +30 -0
- data/data/mars/dwarf.txt +1 -1
- data/data/spheres/fdemo.txt +6 -0
- data/data/spheres/fdemo2.txt +6 -0
- data/data/spheres/{urey.txt → melon.txt} +1 -1
- data/data/tsp/ireland.txt +23 -0
- data/data/tsp/test.txt +8 -8
- data/data/tsp/test10.txt +80 -0
- data/data/tsp/test7.txt +42 -0
- data/lib/bitlab.rb +381 -316
- data/lib/demos.rb +141 -0
- data/lib/elizalab.rb +7 -3
- data/lib/hashlab.rb +173 -115
- data/lib/introlab.rb +43 -4
- data/lib/iterationlab.rb +5 -33
- data/lib/marslab.rb +5 -5
- data/lib/permute.rb +30 -0
- data/lib/randomlab.rb +10 -29
- data/lib/recursionlab.rb +33 -25
- data/lib/rubylabs.rb +98 -76
- data/lib/sievelab.rb +6 -26
- data/lib/spherelab.rb +49 -23
- data/lib/tsplab.rb +717 -425
- data/test/bit_test.rb +5 -6
- data/test/eliza_test.rb +29 -24
- data/test/hash_test.rb +96 -0
- data/test/iteration_test.rb +20 -1
- data/test/random_test.rb +1 -1
- data/test/rubylabs_test.rb +93 -0
- data/test/sieve_test.rb +0 -1
- data/test/tsp_test.rb +140 -0
- metadata +14 -4
- data/data/huffman/hacodes.txt +0 -35
data/lib/bitlab.rb
CHANGED
@@ -10,19 +10,21 @@ module RubyLabs
|
|
10
10
|
|
11
11
|
module BitLab
|
12
12
|
|
13
|
+
QueueView = Struct.new(:queue)
|
14
|
+
|
13
15
|
=begin rdoc
|
14
16
|
Make a unique binary code for each item in array +a+, returning a Hash that
|
15
17
|
associates each item with its code.
|
16
18
|
=end
|
17
19
|
|
18
|
-
def make_codes(a)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def make_codes(a)
|
21
|
+
n = log2(a.length).ceil
|
22
|
+
res = Hash.new
|
23
|
+
a.each_with_index do |x,i|
|
24
|
+
res[x] = i.code(n)
|
25
|
+
end
|
26
|
+
return res
|
23
27
|
end
|
24
|
-
return res
|
25
|
-
end
|
26
28
|
|
27
29
|
=begin rdoc
|
28
30
|
Print the codes in +a+ (an associative array made by +make_codes+ or the
|
@@ -30,21 +32,21 @@ end
|
|
30
32
|
output, either +:by_code+ or +:by_name+.
|
31
33
|
=end
|
32
34
|
|
33
|
-
def print_codes(a, mode = :by_code)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
35
|
+
def print_codes(a, mode = :by_code)
|
36
|
+
if mode == :by_code
|
37
|
+
a.sort { |x,y| x[1] <=> y[1] }.each do |sym, code|
|
38
|
+
printf "%s %s\n", code, sym
|
39
|
+
end
|
40
|
+
elsif mode == :by_name
|
41
|
+
width = a.keys.map{ |x| x.length }.max
|
42
|
+
a.keys.sort.each do |x|
|
43
|
+
printf "%-#{width}s %s\n", x, a[x]
|
44
|
+
end
|
45
|
+
else
|
46
|
+
raise "print_codes: mode must be :by_code or :by_name"
|
42
47
|
end
|
43
|
-
|
44
|
-
raise "print_codes: mode must be :by_code or :by_name"
|
48
|
+
return true
|
45
49
|
end
|
46
|
-
return true
|
47
|
-
end
|
48
50
|
|
49
51
|
=begin rdoc
|
50
52
|
Make a Message object for the characters in string s. The second
|
@@ -55,26 +57,26 @@ end
|
|
55
57
|
documentation of +decode+).
|
56
58
|
=end
|
57
59
|
|
58
|
-
def encode(s, type, opt = nil)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
60
|
+
def encode(s, type, opt = nil)
|
61
|
+
if (type.class == Hash || type.class == Node)
|
62
|
+
code = (type.class == Node) ? assign_codes(type) : type
|
63
|
+
msg = Message.new(:packed)
|
64
|
+
s.each_byte do |ch|
|
65
|
+
msg << code[ch.chr]
|
66
|
+
printf("%s: %s\n", ch.chr, code[ch.chr]) if opt == :trace
|
67
|
+
end
|
68
|
+
else
|
69
|
+
msg = Message.new(:unpacked)
|
70
|
+
s.each_byte do |ch|
|
71
|
+
code = ch.code(8)
|
72
|
+
code.add_parity_bit if type == :parity
|
73
|
+
msg << code
|
74
|
+
printf("%s: %s\n", ch.chr, code) if opt == :trace
|
75
|
+
end
|
73
76
|
end
|
77
|
+
msg.encoding = type
|
78
|
+
return msg
|
74
79
|
end
|
75
|
-
msg.encoding = type
|
76
|
-
return msg
|
77
|
-
end
|
78
80
|
|
79
81
|
=begin rdoc
|
80
82
|
Decode a message using the specified decoding scheme.
|
@@ -87,44 +89,46 @@ end
|
|
87
89
|
encoding scheme.
|
88
90
|
=end
|
89
91
|
|
90
|
-
def decode(m, type)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
92
|
+
def decode(m, type)
|
93
|
+
raise "not a message" unless m.class == Message
|
94
|
+
res = ""
|
95
|
+
if type.class == Node # weird -- it appears case labels can't be class names...
|
96
|
+
res = huffman_decode(m, type)
|
97
|
+
elsif type.class == Code
|
98
|
+
raise "packed decode not implemented"
|
99
|
+
elsif type == :ascii
|
100
|
+
m.array.each do |x|
|
101
|
+
res << x.value.chr
|
102
|
+
end
|
103
|
+
elsif type == :parity
|
104
|
+
m.array.each do |x|
|
105
|
+
if x.even_parity?
|
106
|
+
res << (x.value >> 1).chr
|
107
|
+
elsif $KCODE[0] == ?U
|
108
|
+
res << "\xe2\x80\xa2"
|
109
|
+
else
|
110
|
+
res << "?"
|
111
|
+
end
|
107
112
|
end
|
113
|
+
else
|
114
|
+
raise "unknown option: #{type}"
|
108
115
|
end
|
109
|
-
|
110
|
-
raise "unknown option: #{type}"
|
116
|
+
return res
|
111
117
|
end
|
112
|
-
return res
|
113
|
-
end
|
114
118
|
|
115
119
|
=begin rdoc
|
116
120
|
Simulate transmission of message +m+, adding +n+ random errors. Returns a
|
117
121
|
copy of the Message object after making +n+ calls to the +flip+ method.
|
118
122
|
=end
|
119
123
|
|
120
|
-
def garbled(m, n)
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
def garbled(m, n)
|
125
|
+
res = m.copy
|
126
|
+
n.times do
|
127
|
+
c = res.array[ rand(res.array.length) ]
|
128
|
+
c.flip( rand(c.length) )
|
129
|
+
end
|
130
|
+
return res
|
125
131
|
end
|
126
|
-
return res
|
127
|
-
end
|
128
132
|
|
129
133
|
|
130
134
|
=begin rdoc
|
@@ -132,35 +136,38 @@ end
|
|
132
136
|
by letter name
|
133
137
|
=end
|
134
138
|
|
135
|
-
def read_frequencies(fn)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
139
|
+
def read_frequencies(fn)
|
140
|
+
a = Hash.new
|
141
|
+
if fn.class == Symbol
|
142
|
+
fn = File.join(@@bitsDirectory, fn.to_s + ".txt")
|
143
|
+
end
|
144
|
+
File.open(fn).each do |line|
|
145
|
+
line.chomp!
|
146
|
+
next if line.length == 0
|
147
|
+
next if line[0] == ?#
|
148
|
+
x = line[/^./]
|
149
|
+
f = line[/\d+\.\d+/].to_f
|
150
|
+
a[x] = f
|
151
|
+
end
|
152
|
+
return a
|
144
153
|
end
|
145
|
-
return a
|
146
|
-
end
|
147
154
|
|
148
155
|
=begin rdoc
|
149
156
|
Huffman tree interface: Build a tree using frequencies in Hash +f+.
|
150
157
|
=end
|
151
158
|
|
152
159
|
# :begin :build_tree
|
153
|
-
def build_tree(f)
|
154
|
-
|
160
|
+
def build_tree(f)
|
161
|
+
pq = init_queue(f)
|
155
162
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
163
|
+
while pq.length > 1
|
164
|
+
n1 = pq.shift
|
165
|
+
n2 = pq.shift
|
166
|
+
pq << Node.combine( n1, n2)
|
167
|
+
end
|
161
168
|
|
162
|
-
|
163
|
-
end
|
169
|
+
return pq[0]
|
170
|
+
end
|
164
171
|
# :end :build_tree
|
165
172
|
|
166
173
|
=begin rdoc
|
@@ -173,15 +180,15 @@ end
|
|
173
180
|
=end
|
174
181
|
|
175
182
|
# :begin :assign_codes
|
176
|
-
def assign_codes(tree, code = {}, prefix = Code.new(0,0))
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
183
|
+
def assign_codes(tree, code = {}, prefix = Code.new(0,0))
|
184
|
+
if tree.char != nil
|
185
|
+
code[tree.char] = prefix
|
186
|
+
else
|
187
|
+
assign_codes(tree.left, code, prefix + 0)
|
188
|
+
assign_codes(tree.right, code, prefix + 1)
|
189
|
+
end
|
190
|
+
return code
|
182
191
|
end
|
183
|
-
return code
|
184
|
-
end
|
185
192
|
# :end :assign_codes
|
186
193
|
|
187
194
|
=begin rdoc
|
@@ -190,13 +197,13 @@ end
|
|
190
197
|
=end
|
191
198
|
|
192
199
|
# :begin :init_queue
|
193
|
-
def init_queue(a)
|
194
|
-
|
195
|
-
|
196
|
-
|
200
|
+
def init_queue(a)
|
201
|
+
q = PriorityQueue.new
|
202
|
+
a.each do |x,f|
|
203
|
+
q << Node.new(x,f)
|
204
|
+
end
|
205
|
+
return q
|
197
206
|
end
|
198
|
-
return q
|
199
|
-
end
|
200
207
|
# :end :init_queue
|
201
208
|
|
202
209
|
=begin rdoc
|
@@ -205,66 +212,72 @@ end
|
|
205
212
|
or the +decode+ method defined in the Message class.
|
206
213
|
=end
|
207
214
|
|
208
|
-
def huffman_decode(m, tree)
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
+
def huffman_decode(m, tree)
|
216
|
+
res = ""
|
217
|
+
path = tree
|
218
|
+
m.each do |bit|
|
219
|
+
if path.leaf?
|
220
|
+
res << path.char
|
221
|
+
path = tree
|
222
|
+
end
|
223
|
+
path = (bit == 0) ? path.left : path.right
|
215
224
|
end
|
216
|
-
|
225
|
+
res << path.char if path.leaf?
|
226
|
+
return res
|
217
227
|
end
|
218
|
-
res << path.char if path.leaf?
|
219
|
-
return res
|
220
|
-
end
|
221
228
|
|
222
229
|
=begin rdoc
|
223
|
-
|
224
|
-
|
225
|
-
from the binary sequences and the other a parallel list of words. Since the input is sorted
|
226
|
-
by code length (shortest codes first) returning them in order allows student to choose a
|
227
|
-
word to decode based on length.
|
230
|
+
Return an array of binary codes (so students
|
231
|
+
can text decoding skills)
|
228
232
|
=end
|
229
233
|
|
230
|
-
def read_codes
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
codes
|
244
|
-
words << line[/[a-z]+/]
|
234
|
+
def read_codes
|
235
|
+
codes = Array.new
|
236
|
+
fn = File.join(@@bitsDirectory, "testcodes.txt")
|
237
|
+
File.open(fn).each do |line|
|
238
|
+
line.chomp!
|
239
|
+
code = Code.new(0,0)
|
240
|
+
line.each_byte do |byte|
|
241
|
+
code << byte[0] # add least significant digit of ASCII "0" or "1"
|
242
|
+
end
|
243
|
+
msg = Message.new(:packed)
|
244
|
+
msg << code
|
245
|
+
codes << msg
|
246
|
+
end
|
247
|
+
return codes
|
245
248
|
end
|
246
|
-
|
247
|
-
|
249
|
+
|
250
|
+
=begin rdoc
|
251
|
+
Return an array of binary codes (so students
|
252
|
+
can text decoding skills)
|
253
|
+
=end
|
254
|
+
|
255
|
+
def read_words
|
256
|
+
fn = File.join(@@bitsDirectory, "testwords.txt")
|
257
|
+
words = File.open(fn).readlines
|
258
|
+
return words.map { |x| x.chomp }
|
259
|
+
end
|
260
|
+
|
248
261
|
|
249
262
|
=begin rdoc
|
250
263
|
Huffman tree utility: generate a random string of length +n+ using the letter frequencies +f+.
|
251
264
|
=end
|
252
265
|
|
253
|
-
def generate_string(n, f)
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
266
|
+
def generate_string(n, f)
|
267
|
+
s = ""
|
268
|
+
n.times do
|
269
|
+
r = rand
|
270
|
+
sum = 0
|
271
|
+
f.each do |ch,x|
|
272
|
+
sum += x
|
273
|
+
if r < sum
|
274
|
+
s += ch
|
275
|
+
break
|
276
|
+
end
|
263
277
|
end
|
264
278
|
end
|
279
|
+
return s
|
265
280
|
end
|
266
|
-
return s
|
267
|
-
end
|
268
281
|
|
269
282
|
=begin rdoc
|
270
283
|
Class for nodes of a Huffman tree. All nodes have a frequency (+freq+) used to
|
@@ -279,42 +292,42 @@ end
|
|
279
292
|
queue.
|
280
293
|
=end
|
281
294
|
|
282
|
-
class Node
|
283
|
-
|
284
|
-
attr_accessor :freq, :char, :left, :right
|
295
|
+
class Node
|
285
296
|
|
286
|
-
|
287
|
-
@char = char
|
288
|
-
@freq = freq
|
289
|
-
@left = @right = nil
|
290
|
-
end
|
297
|
+
attr_accessor :freq, :char, :left, :right
|
291
298
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
end
|
299
|
+
def initialize(char,freq)
|
300
|
+
@char = char
|
301
|
+
@freq = freq
|
302
|
+
@left = @right = nil
|
303
|
+
end
|
298
304
|
|
299
|
-
|
300
|
-
|
301
|
-
|
305
|
+
def Node.combine(n1,n2)
|
306
|
+
node = Node.new(nil, n1.freq + n2.freq)
|
307
|
+
node.left = n1
|
308
|
+
node.right = n2
|
309
|
+
return node
|
310
|
+
end
|
311
|
+
|
312
|
+
def <(x)
|
313
|
+
x.class == Node && @freq < x.freq
|
314
|
+
end
|
302
315
|
|
303
|
-
|
304
|
-
|
305
|
-
|
316
|
+
def leaf?
|
317
|
+
return @char != nil
|
318
|
+
end
|
306
319
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
320
|
+
def inspect
|
321
|
+
if leaf?
|
322
|
+
sprintf "( %s: %.3f )", @char, @freq
|
323
|
+
else
|
324
|
+
sprintf "( %.3f %s %s )", @freq, @left.to_s, @right.to_s
|
325
|
+
end
|
326
|
+
end
|
314
327
|
|
315
|
-
|
328
|
+
alias to_s inspect
|
316
329
|
|
317
|
-
end # Node
|
330
|
+
end # Node
|
318
331
|
|
319
332
|
=begin rdoc
|
320
333
|
Code objects are variable-length binary numbers representing individual letters or members
|
@@ -349,101 +362,101 @@ end # Node
|
|
349
362
|
# >> c1.flip(0)
|
350
363
|
# => 10000000000000000000000000000000000000000000000000000000000000000000000001101000
|
351
364
|
|
352
|
-
class Code
|
353
|
-
|
365
|
+
class Code
|
366
|
+
attr_accessor :value, :length, :base
|
354
367
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
368
|
+
def initialize(value, length = 0, base = :binary)
|
369
|
+
raise "Code: unknown base: #{base}" unless [:binary, :hex].include?(base)
|
370
|
+
@value = value
|
371
|
+
@length = length
|
372
|
+
@base = base
|
373
|
+
@has_parity_bit = false
|
374
|
+
end
|
362
375
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
376
|
+
def +(bit)
|
377
|
+
raise "operation not defined for hex codes" unless @base == :binary
|
378
|
+
val = (@value << 1) | bit[0]
|
379
|
+
return Code.new(val, @length+1)
|
380
|
+
end
|
368
381
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
382
|
+
def <<(x)
|
383
|
+
raise "operation not defined for hex codes" unless @base == :binary
|
384
|
+
if x.class == Code
|
385
|
+
val = x.value # val known to fit in x.length bits
|
386
|
+
n = x.length
|
387
|
+
else
|
388
|
+
val = x[0] # val is a single bit
|
389
|
+
n = 1
|
390
|
+
end
|
391
|
+
@value <<= n
|
392
|
+
@value |= val # val can't have any higher order bits set -- see above
|
393
|
+
@length += n
|
394
|
+
return self
|
377
395
|
end
|
378
|
-
@value <<= n
|
379
|
-
@value |= val # val can't have any higher order bits set -- see above
|
380
|
-
@length += n
|
381
|
-
return self
|
382
|
-
end
|
383
396
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
397
|
+
def [](i)
|
398
|
+
if i.class == Range
|
399
|
+
res = 0
|
400
|
+
n = 0
|
401
|
+
i.each { |j| res <<= 1; res |= @value[@length-j-1]; n += 1 }
|
402
|
+
return Code.new(res, n)
|
403
|
+
else
|
404
|
+
return @value[@length-i-1]
|
405
|
+
end
|
392
406
|
end
|
393
|
-
end
|
394
407
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
408
|
+
def parity_bit
|
409
|
+
bit = 0
|
410
|
+
for i in 0...@length
|
411
|
+
bit ^= @value[i]
|
412
|
+
end
|
413
|
+
return bit
|
399
414
|
end
|
400
|
-
return bit
|
401
|
-
end
|
402
415
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
416
|
+
def add_parity_bit
|
417
|
+
@has_parity_bit = true
|
418
|
+
return self << parity_bit
|
419
|
+
end
|
407
420
|
|
408
|
-
|
409
|
-
|
410
|
-
|
421
|
+
def even_parity?
|
422
|
+
return parity_bit() == 0
|
423
|
+
end
|
411
424
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
425
|
+
def flip(i)
|
426
|
+
raise "bit index out of range" unless i < @length
|
427
|
+
@value ^= (1 << (@length - i - 1))
|
428
|
+
return self
|
429
|
+
end
|
417
430
|
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
431
|
+
def chr
|
432
|
+
if @has_parity_bit
|
433
|
+
if even_parity?
|
434
|
+
return (@value >> 1).chr
|
435
|
+
else
|
436
|
+
return "?"
|
437
|
+
end
|
438
|
+
else
|
439
|
+
return @value.chr
|
424
440
|
end
|
425
|
-
else
|
426
|
-
return @value.chr
|
427
441
|
end
|
428
|
-
end
|
429
442
|
|
430
|
-
|
431
|
-
|
432
|
-
|
443
|
+
def <=>(x)
|
444
|
+
return @value <=> x.value
|
445
|
+
end
|
433
446
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
447
|
+
def inspect
|
448
|
+
return "" if @length == 0
|
449
|
+
case @base
|
450
|
+
when :binary
|
451
|
+
return sprintf "%0#{@length}b", @value
|
452
|
+
when :hex
|
453
|
+
return sprintf "%0#{@length/4}X", @value
|
454
|
+
end
|
441
455
|
end
|
442
|
-
end
|
443
456
|
|
444
|
-
|
457
|
+
alias to_s inspect
|
445
458
|
|
446
|
-
end # Code
|
459
|
+
end # Code
|
447
460
|
|
448
461
|
=begin rdoc
|
449
462
|
Message objects are arrays of Codes. New codes are added by a call to <<.
|
@@ -458,98 +471,150 @@ end # Code
|
|
458
471
|
|
459
472
|
# TODO: allow for the possibility that a code word being added to a packed code can be longer than 8 bits
|
460
473
|
|
461
|
-
class Message
|
474
|
+
class Message
|
462
475
|
|
463
|
-
|
476
|
+
attr_accessor :packed, :array, :encoding
|
464
477
|
|
465
|
-
|
478
|
+
@@packsize = 8 # number of bits to pack into single code
|
466
479
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
480
|
+
def initialize(type)
|
481
|
+
raise "Message: unknown type" unless [:packed, :unpacked].include? type
|
482
|
+
if type == :packed
|
483
|
+
@packed = true
|
484
|
+
@array = [ Code.new(0,0) ]
|
485
|
+
else
|
486
|
+
@packed = false
|
487
|
+
@array = [ ]
|
488
|
+
end
|
475
489
|
end
|
476
|
-
end
|
477
490
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
491
|
+
def copy
|
492
|
+
dup = self.clone # copies @packed, @encoding
|
493
|
+
dup.array = Array.new
|
494
|
+
@array.each { |x| dup.array << x.clone } # deep copy of @array
|
495
|
+
return dup
|
496
|
+
end
|
484
497
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
498
|
+
def each
|
499
|
+
@array.each do |byte|
|
500
|
+
for i in 0...byte.length
|
501
|
+
yield(byte[i])
|
502
|
+
end
|
489
503
|
end
|
504
|
+
return self
|
490
505
|
end
|
491
|
-
return self
|
492
|
-
end
|
493
506
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
507
|
+
def <<(x)
|
508
|
+
raise "Message#<<: not a code" unless x.class == Code
|
509
|
+
if @packed
|
510
|
+
if @array[-1].length + x.length <= @@packsize
|
511
|
+
@array[-1] << x
|
512
|
+
else
|
513
|
+
n = @@packsize - @array[-1].length
|
514
|
+
m = x.length - n
|
515
|
+
@array[-1] << x[0...n]
|
516
|
+
@array << x[n...x.length]
|
517
|
+
end
|
499
518
|
else
|
500
|
-
|
501
|
-
m = x.length - n
|
502
|
-
@array[-1] << x[0...n]
|
503
|
-
@array << x[n...x.length]
|
519
|
+
@array << x
|
504
520
|
end
|
505
|
-
|
506
|
-
@array << x
|
521
|
+
return self
|
507
522
|
end
|
508
|
-
return self
|
509
|
-
end
|
510
523
|
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
524
|
+
def decode
|
525
|
+
res = ""
|
526
|
+
if @encoding.class == Symbol
|
527
|
+
@array.each do |code|
|
528
|
+
res << code.chr
|
529
|
+
end
|
530
|
+
elsif @encoding.class == Node
|
531
|
+
res = huffman_decode(self, @encoding)
|
532
|
+
else
|
533
|
+
res = unpack
|
516
534
|
end
|
517
|
-
|
518
|
-
res = huffman_decode(self, @encoding)
|
519
|
-
else
|
520
|
-
res = unpack
|
535
|
+
return res
|
521
536
|
end
|
522
|
-
return res
|
523
|
-
end
|
524
537
|
|
525
|
-
|
526
|
-
|
527
|
-
|
538
|
+
def unpack
|
539
|
+
"unpack: not implemented"
|
540
|
+
end
|
528
541
|
|
529
|
-
|
530
|
-
|
531
|
-
|
542
|
+
def length
|
543
|
+
@array.inject(0) { |sum, code| sum += code.length }
|
544
|
+
end
|
532
545
|
|
533
|
-
|
534
|
-
|
535
|
-
|
546
|
+
def print(option)
|
547
|
+
"a message"
|
548
|
+
end
|
536
549
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
550
|
+
def inspect
|
551
|
+
if @packed
|
552
|
+
return @array.join("")
|
553
|
+
else
|
554
|
+
return @array.join(" ")
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
alias to_s inspect
|
544
559
|
|
545
|
-
|
560
|
+
end # Message
|
546
561
|
|
547
|
-
|
562
|
+
=begin rdoc
|
563
|
+
Initialize the canvas with a drawing of a priority queue.
|
564
|
+
=end
|
565
|
+
|
566
|
+
=begin
|
567
|
+
TODO fill in this stub...
|
568
|
+
=end
|
569
|
+
|
570
|
+
def view_queue(pq, userOptions = {} )
|
571
|
+
options = @@queueOptions.merge(userOptions)
|
572
|
+
Canvas.init(300, 500, "BitLab")
|
573
|
+
@@drawing = QueueView.new(pq)
|
574
|
+
pq.on_canvas = true
|
575
|
+
Canvas.sync
|
576
|
+
return true
|
577
|
+
end
|
578
|
+
|
579
|
+
def redraw_queue(pq)
|
580
|
+
puts "redraw: #{pq.inspect}"
|
581
|
+
end
|
582
|
+
|
583
|
+
@@queueOptions = {
|
584
|
+
}
|
585
|
+
|
586
|
+
@@bitsDirectory = File.join(File.dirname(__FILE__), '..', 'data', 'huffman')
|
548
587
|
|
549
588
|
end # BitLab
|
550
589
|
|
551
590
|
end # RubyLabs
|
552
591
|
|
592
|
+
=begin rdoc
|
593
|
+
Add hooks to the PriorityQueue's shift and << methods so they check to see if the
|
594
|
+
queue is on the canvas, and if so, update the drawing when an item is removed or added.
|
595
|
+
=end
|
596
|
+
|
597
|
+
class PriorityQueue
|
598
|
+
|
599
|
+
attr_accessor :on_canvas
|
600
|
+
|
601
|
+
alias_method :pqappend, :<<
|
602
|
+
|
603
|
+
def <<(obj)
|
604
|
+
res = pqappend(obj)
|
605
|
+
redraw_queue(self) if on_canvas
|
606
|
+
return res
|
607
|
+
end
|
608
|
+
|
609
|
+
alias_method :pqshift, :shift
|
610
|
+
|
611
|
+
def shift
|
612
|
+
res = pqshift
|
613
|
+
redraw_queue(self) if on_canvas
|
614
|
+
return res
|
615
|
+
end
|
616
|
+
|
617
|
+
end
|
553
618
|
|
554
619
|
class Fixnum
|
555
620
|
|