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/demos.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
Methods in this module are not intended to be used by students. They are
|
4
|
+
implemented here so they can be tested before being included in the book
|
5
|
+
or lecture slides. Instructors can also load this module to use the methods
|
6
|
+
in lectures.
|
7
|
+
|
8
|
+
=end
|
9
|
+
|
10
|
+
module RubyLabs
|
11
|
+
|
12
|
+
module Demos
|
13
|
+
|
14
|
+
=begin rdoc
|
15
|
+
Convert the temperature +f+ (in degrees Fahrenheit) into the equivalent
|
16
|
+
temperature in degrees Celsius.
|
17
|
+
=end
|
18
|
+
|
19
|
+
def celsius(f)
|
20
|
+
(f - 32) * 5 / 9
|
21
|
+
end
|
22
|
+
|
23
|
+
=begin rdoc
|
24
|
+
This version of the Sieve of Eratosthenes iterates until the worklist is
|
25
|
+
empty. Use it as a baseline for counting the number of iterations, to
|
26
|
+
compare it to the actual version that iterates until finding the first
|
27
|
+
prime greater than sqrt(n)
|
28
|
+
=end
|
29
|
+
|
30
|
+
def sieve(n)
|
31
|
+
worklist = Array(2..n)
|
32
|
+
primes = []
|
33
|
+
|
34
|
+
while worklist.length > 0
|
35
|
+
primes << worklist.first
|
36
|
+
worklist.delete_if { |x| x % primes.last == 0 }
|
37
|
+
end
|
38
|
+
|
39
|
+
return primes
|
40
|
+
end
|
41
|
+
|
42
|
+
def sequence(i,j)
|
43
|
+
Array(i..j)
|
44
|
+
end
|
45
|
+
|
46
|
+
=begin rdoc
|
47
|
+
The HashLab module has preliminary versions of insert and lookup methods
|
48
|
+
that don't use buckets; these are the final versions, with buckets.
|
49
|
+
=end
|
50
|
+
|
51
|
+
def insert(s, t)
|
52
|
+
i = h(s, t.length)
|
53
|
+
t[i] = Array.new if t[i].nil?
|
54
|
+
t[i] << s
|
55
|
+
return i
|
56
|
+
end
|
57
|
+
|
58
|
+
def lookup(s, t)
|
59
|
+
i = h(s, t.length)
|
60
|
+
if t[i] && t[i].include?(s)
|
61
|
+
return i
|
62
|
+
else
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
=begin rdoc
|
68
|
+
This is the bare bones version of Eliza.transform, the method that
|
69
|
+
applies transformation rule to make a response to a sentence.
|
70
|
+
=end
|
71
|
+
|
72
|
+
def transform(sentence)
|
73
|
+
queue = PriorityQueue.new
|
74
|
+
Eliza.scan(sentence, queue)
|
75
|
+
response = nil
|
76
|
+
while queue.length > 0
|
77
|
+
rule = queue.shift
|
78
|
+
response = Eliza.apply(sentence, rule)
|
79
|
+
break if response != nil
|
80
|
+
end
|
81
|
+
return response
|
82
|
+
end
|
83
|
+
|
84
|
+
=begin rdoc
|
85
|
+
Compare two ways of writing a loop
|
86
|
+
=end
|
87
|
+
|
88
|
+
def loops(n)
|
89
|
+
i = 1
|
90
|
+
while i <= n
|
91
|
+
puts i ** 2
|
92
|
+
i += 1
|
93
|
+
end
|
94
|
+
|
95
|
+
for i in 1..n
|
96
|
+
puts i**2
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
=begin rdoc
|
101
|
+
Simple demonstration of why nested loops lead to n^2 operations. This
|
102
|
+
version is for a loop structure like the one in isort, but it also works
|
103
|
+
for any algorithm that needs all (i,j) pairs and that is symmetric, i.e.
|
104
|
+
(i,j) = (j,i).
|
105
|
+
=end
|
106
|
+
|
107
|
+
# :begin :nested
|
108
|
+
def nested(n)
|
109
|
+
count = 0
|
110
|
+
i = 0
|
111
|
+
while i < n
|
112
|
+
j = 0
|
113
|
+
while j < i
|
114
|
+
count += 1
|
115
|
+
j += 1
|
116
|
+
end
|
117
|
+
i += 1
|
118
|
+
end
|
119
|
+
return count
|
120
|
+
end
|
121
|
+
# :end :nested
|
122
|
+
|
123
|
+
# code used in figure next to nested
|
124
|
+
|
125
|
+
def isnest(n)
|
126
|
+
i = 1
|
127
|
+
while i < n
|
128
|
+
j = i-1
|
129
|
+
while j >= 0
|
130
|
+
puts "i = #{i}, j = #{j}"
|
131
|
+
j = j-1
|
132
|
+
end
|
133
|
+
i = i+1
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
end # Demos
|
140
|
+
|
141
|
+
end # RubyLabs
|
data/lib/elizalab.rb
CHANGED
@@ -10,6 +10,10 @@ writing their own scripts.
|
|
10
10
|
|
11
11
|
=end
|
12
12
|
|
13
|
+
=begin
|
14
|
+
TODO don't add rule to queue more than once (e.g. word repeated in input sentence)
|
15
|
+
=end
|
16
|
+
|
13
17
|
module RubyLabs
|
14
18
|
|
15
19
|
module ElizaLab
|
@@ -323,7 +327,7 @@ words (a|b|c), and variable names ($x) if they aren't already there.
|
|
323
327
|
|
324
328
|
def Eliza.checkout(script, filename = nil)
|
325
329
|
scriptfilename = script.to_s + ".txt"
|
326
|
-
scriptfilename = File.join(@@
|
330
|
+
scriptfilename = File.join(@@elizaDirectory, scriptfilename)
|
327
331
|
if !File.exists?(scriptfilename)
|
328
332
|
puts "Script not found: #{scriptfilename}"
|
329
333
|
return nil
|
@@ -492,7 +496,7 @@ words (a|b|c), and variable names ($x) if they aren't already there.
|
|
492
496
|
Eliza.clear
|
493
497
|
rule = nil
|
494
498
|
if filename.class == Symbol
|
495
|
-
filename = File.join(@@
|
499
|
+
filename = File.join(@@elizaDirectory, filename.to_s + ".txt")
|
496
500
|
end
|
497
501
|
File.open(filename).each do |line|
|
498
502
|
line.strip!
|
@@ -615,7 +619,7 @@ words (a|b|c), and variable names ($x) if they aren't already there.
|
|
615
619
|
# the ElizaLab module
|
616
620
|
|
617
621
|
@@verbose = false
|
618
|
-
@@
|
622
|
+
@@elizaDirectory = File.join(File.dirname(__FILE__), '..', 'data', 'eliza')
|
619
623
|
@@pre = Dictionary.new
|
620
624
|
@@post = Dictionary.new
|
621
625
|
@@rules = Dictionary.new
|
data/lib/hashlab.rb
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
Methods used in experiments on hash tables.
|
6
6
|
|
7
|
-
<b>NOTE:</b> the +insert+ and +
|
7
|
+
<b>NOTE:</b> the +insert+ and +lookup+ methods defined here are "stubs" used to test the hash
|
8
8
|
functions. Load the file <tt>hashmethods.rb</tt> to overwrite the stubs with the actual
|
9
9
|
methods that create and search buckets.
|
10
10
|
|
@@ -13,45 +13,8 @@ methods that create and search buckets.
|
|
13
13
|
module RubyLabs
|
14
14
|
|
15
15
|
module HashLab
|
16
|
-
|
17
|
-
=begin rdoc
|
18
|
-
|
19
|
-
Ruby version of the ``card catalog box'' number, a trivial hash function that
|
20
|
-
maps two-letter strings to numbers between 0 and 675.
|
21
|
-
|
22
|
-
=end
|
23
|
-
|
24
|
-
# :begin :ccb
|
25
|
-
def ccb(s)
|
26
|
-
return s[0].ord * 26 + s[1].ord
|
27
|
-
end
|
28
|
-
# :end :ccb
|
29
|
-
|
30
|
-
=begin rdoc
|
31
|
-
|
32
|
-
The "small card catalog box" number, a version of ccb that works
|
33
|
-
for a smaller catalog (n = 100 boxes).
|
34
|
-
|
35
|
-
=end
|
36
|
-
|
37
|
-
# :begin :sccb
|
38
|
-
def sccb(s)
|
39
|
-
return ccb(s) % 100
|
40
|
-
end
|
41
|
-
# :end :sccb
|
42
16
|
|
43
|
-
=
|
44
|
-
|
45
|
-
"Randomized" version of sccb that uses prime numbers to do
|
46
|
-
a better job of scattering words more evenly.
|
47
|
-
|
48
|
-
=end
|
49
|
-
|
50
|
-
# :begin :rccb
|
51
|
-
def rccb(s)
|
52
|
-
return (s[0].ord * 31 + s[1].ord * 107) % 100
|
53
|
-
end
|
54
|
-
# :end :rccb
|
17
|
+
TableView = Struct.new(:table, :nrows)
|
55
18
|
|
56
19
|
=begin rdoc
|
57
20
|
|
@@ -98,18 +61,61 @@ RubyLabs module.
|
|
98
61
|
string to hash, +n+ is the size of the hash table.
|
99
62
|
=end
|
100
63
|
|
101
|
-
# :begin :
|
102
|
-
def
|
64
|
+
# :begin :hr
|
65
|
+
def hr(s, n)
|
103
66
|
return radix26(s) % n
|
104
67
|
end
|
105
|
-
# :end :
|
68
|
+
# :end :hr
|
106
69
|
|
107
|
-
|
70
|
+
=begin rdoc
|
71
|
+
Simple hash function used in the first project, to introduce the idea of hashing.
|
72
|
+
Uses a default table size of 10 and the h0 method (which just looks at the first
|
73
|
+
letter in a string).
|
74
|
+
=end
|
75
|
+
|
76
|
+
# :begin :h
|
77
|
+
def h(s, n = 10)
|
78
|
+
return s[0].ord % n
|
79
|
+
end
|
80
|
+
# :end :h
|
81
|
+
|
82
|
+
=begin rdoc
|
83
|
+
Method used in the first project: if +s+ can be added to +t+ (i.e. if no
|
84
|
+
collision) return the location, otherwise return +nil+
|
85
|
+
=end
|
86
|
+
|
87
|
+
# :begin :insert
|
88
|
+
def insert(s, t)
|
89
|
+
i = h(s, t.length)
|
90
|
+
if t[i].nil?
|
91
|
+
t[i] = s
|
92
|
+
return i
|
93
|
+
else
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
# :end :insert
|
98
|
+
|
99
|
+
=begin rdoc
|
100
|
+
Method used in the first project: if +s+ is in array +t+ return the location,
|
101
|
+
otherwise return +nil+
|
102
|
+
=end
|
103
|
+
|
104
|
+
# :begin :lookup
|
105
|
+
def lookup(s, t)
|
106
|
+
i = h(s, t.length)
|
107
|
+
if t[i] == s
|
108
|
+
return i
|
109
|
+
else
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
# :end :lookup
|
108
114
|
|
109
115
|
=begin rdoc
|
110
116
|
|
111
117
|
Make a hash table with +n+ buckets. The optional parameter is a symbol specifying
|
112
|
-
an alternative hash function (<tt>:h0</tt> or <tt>:h1</tt>); the default is the method +
|
118
|
+
an alternative hash function (<tt>:h0</tt> or <tt>:h1</tt>); the default is the method +hr+, which
|
113
119
|
uses the radix26 function.
|
114
120
|
|
115
121
|
The object returned by this method is an array of the designated size. A bit of
|
@@ -120,104 +126,156 @@ Ruby magic defines three new methods just for the new object:
|
|
120
126
|
|
121
127
|
=end
|
122
128
|
|
123
|
-
|
124
|
-
t = Array.new(n)
|
125
|
-
|
126
|
-
class <<t
|
127
|
-
attr_accessor :h
|
129
|
+
class HashTable
|
128
130
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
when :h1 : h1(s, self.size)
|
133
|
-
else hn(s, self.size)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
t.h = f
|
139
|
-
return t
|
140
|
-
end
|
131
|
+
@@hash_functions = [:h0, :h1, :hr]
|
132
|
+
|
133
|
+
attr_reader :table
|
141
134
|
|
135
|
+
def initialize(n, f = :hr)
|
136
|
+
raise "HashTable: hash function must be one of #{@@hash_functions.inspect}" unless @@hash_functions.include?(f)
|
137
|
+
@table = Array.new(n)
|
138
|
+
@hash = f
|
139
|
+
end
|
140
|
+
|
141
|
+
# def hash(s)
|
142
|
+
# return case @h
|
143
|
+
# when :h0 : h0(s, @table.length)
|
144
|
+
# when :h1 : h1(s, @table.length)
|
145
|
+
# else hr(s, @table.length)
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
|
149
|
+
def lookup(s)
|
150
|
+
i = send(@hash, s, @table.length)
|
151
|
+
return ( @table[i] && @table[i].include?(s) ) ? i : nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def insert(s)
|
155
|
+
i = send(@hash, s, @table.length)
|
156
|
+
@table[i] = Array.new if @table[i].nil?
|
157
|
+
@table[i] << s
|
158
|
+
return i
|
159
|
+
end
|
160
|
+
|
161
|
+
def to_s
|
162
|
+
print_table(self)
|
163
|
+
end
|
164
|
+
|
165
|
+
def inspect
|
166
|
+
sprintf '#<RubyLabs::HashLab::HashTable: %d rows, :%s>', @table.size, @hash.to_s
|
167
|
+
end
|
168
|
+
|
142
169
|
=begin rdoc
|
143
|
-
|
144
|
-
|
170
|
+
Print usage statistics for the table. Prints lengths of longest and shortest
|
171
|
+
buckets, number of empty buckets, and mean bucket length.
|
145
172
|
=end
|
146
173
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
174
|
+
def print_stats
|
175
|
+
max = 0
|
176
|
+
min = Float::MAX
|
177
|
+
nzero = 0
|
178
|
+
sum = 0
|
179
|
+
@table.each do |bucket|
|
180
|
+
n = bucket.nil? ? 0 : bucket.length
|
181
|
+
min = n if n < min
|
182
|
+
max = n if n > max
|
183
|
+
sum += n
|
184
|
+
nzero += 1 if n == 0
|
185
|
+
end
|
186
|
+
printf "shortest bucket: %d\n", min
|
187
|
+
printf "longest bucket: %d\n", max
|
188
|
+
printf "empty buckets: %d\n", nzero
|
189
|
+
if max > 0
|
190
|
+
printf "mean bucket length: %.2f\n", sum.to_f / (@table.length - nzero)
|
191
|
+
end
|
192
|
+
return nil
|
193
|
+
end
|
153
194
|
|
154
195
|
=begin rdoc
|
155
|
-
|
156
|
-
table must be an object created by a call to <tt>make_table</tt>.
|
196
|
+
Return a list of indices for buckets that have more than +cutoff+ entries.
|
157
197
|
=end
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
else
|
166
|
-
puts "collision!"
|
167
|
-
return false
|
198
|
+
|
199
|
+
def long_rows(cutoff = 5)
|
200
|
+
rows = Array.new
|
201
|
+
@table.each_with_index do |row, i|
|
202
|
+
rows << i if !row.nil? && row.length > cutoff
|
203
|
+
end
|
204
|
+
return rows
|
168
205
|
end
|
169
|
-
|
170
|
-
#
|
206
|
+
|
207
|
+
end # HashTable
|
171
208
|
|
172
209
|
=begin rdoc
|
173
|
-
Print a nicely formatted representation of hash table +t
|
210
|
+
Print a nicely formatted representation of hash table. The parameter +t+ can be
|
211
|
+
an array or a HashTable object. The optional parameter
|
174
212
|
is the number of rows to print, e.g. to print just the first 10 rows of a large table
|
175
213
|
+t+ call <tt>print_table(t,10)</tt>. Skips rows that have empty buckets.
|
176
214
|
=end
|
177
215
|
|
178
216
|
def print_table(t, max = nil)
|
217
|
+
t = t.table if t.class == HashTable
|
179
218
|
max = t.length unless max
|
180
|
-
max.times { |i| print_row(i, t) unless t[i].nil? }
|
181
|
-
nil
|
219
|
+
max.times { |i| print_row(i, t[i] ) unless t[i].nil? }
|
220
|
+
return nil
|
182
221
|
end
|
183
222
|
|
184
|
-
def print_row(n,
|
185
|
-
printf "%4d: ", n
|
186
|
-
p t[n]
|
223
|
+
def print_row(n, row) # :nodoc:
|
224
|
+
printf "%4d: %s\n", n, row.inspect
|
187
225
|
end
|
188
|
-
|
226
|
+
|
189
227
|
=begin rdoc
|
190
|
-
|
191
|
-
|
228
|
+
Verification of numbers shown in the table for the birthday paradox. Call
|
229
|
+
birthday(n,m) to make a table with n rows and fill it with m random words.
|
230
|
+
Return true if any row has more than one item.
|
192
231
|
=end
|
193
|
-
|
194
|
-
def print_stats(t)
|
195
|
-
max = 0
|
196
|
-
min = Float::MAX
|
197
|
-
nzero = 0
|
198
|
-
sum = 0
|
199
|
-
t.each do |bucket|
|
200
|
-
n = bucket.nil? ? 0 : bucket.length
|
201
|
-
min = n if n < min
|
202
|
-
max = n if n > max
|
203
|
-
sum += n
|
204
|
-
nzero += 1 if n == 0
|
205
|
-
end
|
206
|
-
puts "shortest bucket: #{min} items"
|
207
|
-
puts "longest bucket: #{max} items"
|
208
|
-
puts "empty buckets: #{nzero}"
|
209
|
-
puts "mean bucket length: #{sum.to_f / (t.length - nzero)}" unless nzero == t.length
|
210
|
-
nil
|
211
|
-
end
|
212
232
|
|
233
|
+
def birthday(n, m)
|
234
|
+
t = HashTable.new(n)
|
235
|
+
TestArray.new(m, :words).each { |s| t.insert(s) }
|
236
|
+
# puts t
|
237
|
+
t.table.each { |row| return true if row && row.length > 1 }
|
238
|
+
return false
|
239
|
+
end
|
240
|
+
|
213
241
|
=begin rdoc
|
214
|
-
|
242
|
+
Initialize the canvas with a drawing of an hash table +t+ (a table is
|
243
|
+
just an array augmented with a hash method)
|
215
244
|
=end
|
216
245
|
|
217
|
-
def
|
218
|
-
|
219
|
-
|
246
|
+
def view_table(t, userOptions = {} )
|
247
|
+
options = @@tableOptions.merge(userOptions)
|
248
|
+
Canvas.init(300, 500, "HashLab")
|
249
|
+
tbl = t.table
|
250
|
+
x0 = options[:tableX]
|
251
|
+
x1 = x0 + options[:cellWidth]
|
252
|
+
# if nil, color = gray, else color = white and draw text
|
253
|
+
# todo -- arrow
|
254
|
+
# todo -- save text, update with call to insert
|
255
|
+
nrows = min(tbl.size, options[:maxRows])
|
256
|
+
nrows.times do |i|
|
257
|
+
y0 = options[:tableY] + i * (options[:cellHeight] + options[:cellYSpace])
|
258
|
+
y1 = y0 + options[:cellHeight]
|
259
|
+
Canvas.rectangle(x0, y0, x1, y1, :fill => options[:cellColor])
|
260
|
+
# Canvas.text(tbl[i].inspect, textx, y0)
|
261
|
+
end
|
262
|
+
@@drawing = TableView.new(t, nrows)
|
263
|
+
Canvas.sync
|
264
|
+
return true
|
220
265
|
end
|
266
|
+
|
267
|
+
@@tableOptions = {
|
268
|
+
:tableX => 20,
|
269
|
+
:tableY => 20,
|
270
|
+
:cellHeight => 15,
|
271
|
+
:cellYSpace => 2,
|
272
|
+
:cellWidth => 30,
|
273
|
+
:cellColor => :lightgray,
|
274
|
+
:textX => 70,
|
275
|
+
:maxRows => 25,
|
276
|
+
}
|
277
|
+
|
278
|
+
|
221
279
|
|
222
280
|
end # HashLab
|
223
281
|
|
data/lib/introlab.rb
CHANGED
@@ -1,14 +1,53 @@
|
|
1
1
|
=begin rdoc
|
2
2
|
|
3
|
-
|
3
|
+
Methods used in Chapter 2 (the Ruby Workbench)
|
4
4
|
|
5
5
|
=end
|
6
6
|
|
7
|
+
module RubyLabs
|
8
|
+
|
9
|
+
module IntroLab
|
10
|
+
|
11
|
+
=begin rdoc
|
12
|
+
Compute the area of a 5-sided counter that is a square with a missing
|
13
|
+
triangle shape. The parameter +x+ is the length of one side of the square.
|
14
|
+
=end
|
15
|
+
|
16
|
+
# :begin :countertop
|
17
|
+
def countertop(x)
|
18
|
+
square = x**2
|
19
|
+
triangle = ((x/2)**2) / 2
|
20
|
+
return square - triangle
|
21
|
+
end
|
22
|
+
# :end :countertop
|
23
|
+
|
7
24
|
=begin rdoc
|
8
25
|
Convert the temperature +f+ (in degrees Fahrenheit) into the equivalent
|
9
26
|
temperature in degrees Celsius.
|
10
27
|
=end
|
11
28
|
|
12
|
-
def celsius(f)
|
13
|
-
|
14
|
-
end
|
29
|
+
def celsius(f)
|
30
|
+
(f - 32) * 5 / 9
|
31
|
+
end
|
32
|
+
|
33
|
+
# :begin :fahrenheit
|
34
|
+
def fahrenheit(c)
|
35
|
+
# your expression goes here
|
36
|
+
end
|
37
|
+
# :end :fahrenheit
|
38
|
+
|
39
|
+
# :begin :payment
|
40
|
+
def payment(c)
|
41
|
+
# your expression goes here
|
42
|
+
end
|
43
|
+
# :end :payment
|
44
|
+
|
45
|
+
# :begin :payment
|
46
|
+
def era(runs, ip)
|
47
|
+
return (9.0 / ip) * runs
|
48
|
+
end
|
49
|
+
# :end :payment
|
50
|
+
|
51
|
+
end # IntroLab
|
52
|
+
|
53
|
+
end # RubyLabs
|
data/lib/iterationlab.rb
CHANGED
@@ -51,20 +51,20 @@ array, find a location for it to the left of its original position,
|
|
51
51
|
and insert it back into the array at the new location.
|
52
52
|
=end
|
53
53
|
|
54
|
-
# :begin :isort :
|
54
|
+
# :begin :isort :move_left :less
|
55
55
|
def isort(array)
|
56
56
|
a = array.clone # don't modify the input array....
|
57
57
|
i = 1
|
58
58
|
while i < a.length
|
59
|
-
|
59
|
+
move_left(a, i) # find a place for a[i] somewhere to the left
|
60
60
|
i += 1
|
61
61
|
end
|
62
62
|
return a
|
63
63
|
end
|
64
64
|
# :end :isort
|
65
65
|
|
66
|
-
# :begin :
|
67
|
-
def
|
66
|
+
# :begin :move_left
|
67
|
+
def move_left(a, i)
|
68
68
|
x = a.slice!(i) # remove the item at location i
|
69
69
|
j = i-1 # start scanning from the left of i
|
70
70
|
while j >= 0 && less(x, a[j])
|
@@ -72,7 +72,7 @@ and insert it back into the array at the new location.
|
|
72
72
|
end
|
73
73
|
a.insert(j+1, x) # insert x back into a at location j
|
74
74
|
end
|
75
|
-
# :end :
|
75
|
+
# :end :move_left
|
76
76
|
|
77
77
|
# :begin :less
|
78
78
|
def less(x, y)
|
@@ -80,34 +80,6 @@ and insert it back into the array at the new location.
|
|
80
80
|
end
|
81
81
|
# :end :less
|
82
82
|
|
83
|
-
=begin rdoc
|
84
|
-
Simple demonstration of why nested loops lead to n^2 operations
|
85
|
-
=end
|
86
|
-
|
87
|
-
# :begin :nested
|
88
|
-
def nested(n)
|
89
|
-
n.times do |i|
|
90
|
-
n.times do |j|
|
91
|
-
puts "i = #{i}, j = #{j}"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
# :end :nested
|
96
|
-
|
97
|
-
# code used in figure next to nested
|
98
|
-
|
99
|
-
def isnest(n)
|
100
|
-
i = 1
|
101
|
-
while i < n
|
102
|
-
j = i-1
|
103
|
-
while j >= 0
|
104
|
-
puts "i = #{i}, j = #{j}"
|
105
|
-
j = j-1
|
106
|
-
end
|
107
|
-
i = i+1
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
83
|
=begin rdoc
|
112
84
|
A helper method that can be called from a probe to display the contents
|
113
85
|
of an array during a search or sort.
|
data/lib/marslab.rb
CHANGED
@@ -289,7 +289,7 @@ module MARSLab
|
|
289
289
|
|
290
290
|
def initialize(filename)
|
291
291
|
if filename.class == Symbol
|
292
|
-
filename = File.join(@@
|
292
|
+
filename = File.join(@@marsDirectory, filename.to_s + ".txt")
|
293
293
|
end
|
294
294
|
|
295
295
|
if ! File.exists?(filename)
|
@@ -1062,7 +1062,7 @@ module MARSLab
|
|
1062
1062
|
def MARS.listing(prog, dest = nil)
|
1063
1063
|
filename = prog.to_s
|
1064
1064
|
filename += ".txt" unless filename =~ /\.txt$/
|
1065
|
-
filename = File.join(@@
|
1065
|
+
filename = File.join(@@marsDirectory, filename)
|
1066
1066
|
dest = STDOUT if dest.nil?
|
1067
1067
|
if !File.exists?(filename)
|
1068
1068
|
puts "File not found: #{filename}"
|
@@ -1092,8 +1092,8 @@ module MARSLab
|
|
1092
1092
|
=end
|
1093
1093
|
|
1094
1094
|
def MARS.dir
|
1095
|
-
puts "Redcode programs in #{@@
|
1096
|
-
Dir.open(@@
|
1095
|
+
puts "Redcode programs in #{@@marsDirectory}:"
|
1096
|
+
Dir.open(@@marsDirectory).each do |file|
|
1097
1097
|
next if file[0] == ?.
|
1098
1098
|
file.slice!(/\.txt/)
|
1099
1099
|
puts " " + file
|
@@ -1120,7 +1120,7 @@ module MARSLab
|
|
1120
1120
|
# -- Initializations -- These are "global" vars in the outer MARSLab scope that are
|
1121
1121
|
# accessible to all the classes and modules defined inside MARSLab
|
1122
1122
|
|
1123
|
-
@@
|
1123
|
+
@@marsDirectory = File.join(File.dirname(__FILE__), '..', 'data', 'mars')
|
1124
1124
|
|
1125
1125
|
@@opcodes = ["DAT", "MOV", "ADD", "SUB", "JMP", "JMZ", "JMN", "DJN", "CMP", "SPL", "END", "SLT", "EQU"]
|
1126
1126
|
@@modes = "@<#"
|