rubylabs 0.5.4
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 +20 -0
- data/README.rdoc +9 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/bb.rb +12 -0
- data/bin/statistics2-0.53/ext/extconf.rb +11 -0
- data/bin/statistics2-0.53/ext/show.rb +11 -0
- data/bin/statistics2-0.53/ext/t.rb +46 -0
- data/bin/statistics2-0.53/mklist.rb +26 -0
- data/bin/statistics2-0.53/sample-tbl.rb +129 -0
- data/bin/statistics2-0.53/statistics2.rb +532 -0
- data/bin/statistics2-0.53/t-inv.rb +54 -0
- data/bin/statistics2.rb +532 -0
- data/data/aafreq.txt +20 -0
- data/data/cars.txt +50 -0
- data/data/century.txt +1 -0
- data/data/colors.txt +64 -0
- data/data/earth.yaml +15 -0
- data/data/fruit.txt +45 -0
- data/data/hacodes.txt +35 -0
- data/data/hafreq.txt +16 -0
- data/data/hvfreq.txt +5 -0
- data/data/nbody.R +23 -0
- data/data/nbody.out +731 -0
- data/data/nbody.pdf +3111 -0
- data/data/nbody.png +0 -0
- data/data/nbody3d.pdf +3201 -0
- data/data/outer.pdf +182785 -0
- data/data/solar.dat +36501 -0
- data/data/solarsystem.txt +17 -0
- data/data/suits.txt +1 -0
- data/data/wordlist.txt +210653 -0
- data/lib/bitlab.rb +624 -0
- data/lib/elizalab.rb +523 -0
- data/lib/encryptionlab.rb +42 -0
- data/lib/hashlab.rb +224 -0
- data/lib/introlab.rb +14 -0
- data/lib/iterationlab.rb +130 -0
- data/lib/randomlab.rb +294 -0
- data/lib/recursionlab.rb +228 -0
- data/lib/rubylabs.rb +507 -0
- data/lib/sievelab.rb +58 -0
- data/lib/sortlab.rb +213 -0
- data/lib/spherelab.rb +352 -0
- data/lib/temps.rb +41 -0
- data/lib/tsplab.rb +416 -0
- data/lib/viewer.rb +65 -0
- data/test/bit_test.rb +175 -0
- data/test/encryption_test.rb +20 -0
- data/test/iteration_test.rb +40 -0
- data/test/random_test.rb +64 -0
- data/test/recursion_test.rb +47 -0
- data/test/rubylabs_test.rb +18 -0
- data/test/sieve_test.rb +28 -0
- data/test/sphere_test.rb +130 -0
- data/test/temps_test.rb +24 -0
- data/test/test_helper.rb +18 -0
- metadata +112 -0
data/lib/sortlab.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== SortLab
|
5
|
+
|
6
|
+
Instrumented versions of the sorting algorithms described in the chapters
|
7
|
+
on iterative algorithms and recursive algorithms. The versions here are
|
8
|
+
not intended to be viewed by students -- those implementations are in the
|
9
|
+
modules named IterationLab and RecursionLab.
|
10
|
+
|
11
|
+
The three public methods implemented here are +isort+ (insertion sort),
|
12
|
+
+msort+ (mergesort), and +qsort+ (quicksort). The only required parameter
|
13
|
+
is an array to sort. A method will make a copy of the parameter and return
|
14
|
+
a sorted version of the copy.
|
15
|
+
|
16
|
+
An optional second parameter can be used when running experiments:
|
17
|
+
:trace print the state of the array after each iteration of the outer loop
|
18
|
+
:count return a count of the number of comparisons made instead of the sorted array
|
19
|
+
:timer return the execution time in seconds instead of the sorted array
|
20
|
+
|
21
|
+
=end
|
22
|
+
|
23
|
+
module RubyLabs
|
24
|
+
|
25
|
+
module SortLab
|
26
|
+
|
27
|
+
=begin rdoc
|
28
|
+
|
29
|
+
The Timer class implements a simpler timer. Call +Timer.start+ to start
|
30
|
+
the timer, and +Timer.stop+ to get the elapsed time since the call to
|
31
|
+
+Timer.start+.
|
32
|
+
=end
|
33
|
+
|
34
|
+
class Timer
|
35
|
+
|
36
|
+
def Timer.start
|
37
|
+
@@tstart = Time.now
|
38
|
+
end
|
39
|
+
|
40
|
+
def Timer.stop
|
41
|
+
return Time.now - @@tstart
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
=begin rdoc
|
47
|
+
Insertion sort.
|
48
|
+
=end
|
49
|
+
|
50
|
+
def isort(a, mode = nil)
|
51
|
+
a = a.clone
|
52
|
+
Timer.start if mode == :timer
|
53
|
+
count = 0
|
54
|
+
for i in 1..a.length - 1
|
55
|
+
puts isort_brackets(a,i) if mode == :trace
|
56
|
+
x = a.slice!(i)
|
57
|
+
j = i - 1
|
58
|
+
while j >= 0 && (count += 1) > 0 && a[j] > x
|
59
|
+
j = j - 1
|
60
|
+
end
|
61
|
+
a.insert(j + 1, x)
|
62
|
+
end
|
63
|
+
return case mode
|
64
|
+
when :count : count
|
65
|
+
when :timer : Timer.stop
|
66
|
+
else a
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
=begin rdoc
|
71
|
+
Helper method for printing the state of the array during insertion sort.
|
72
|
+
=end
|
73
|
+
|
74
|
+
def isort_brackets(a, i)
|
75
|
+
pre = (i == 0) ? [] : a.slice(0..(i-1))
|
76
|
+
post = (i <= a.length) ? a.slice(i..-1) : []
|
77
|
+
return "[" + pre.join(", ") + "] [" + post.join(", ") + "]"
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Merge sort. Makes a copy of the input Array, returns a sorted
|
82
|
+
# version of the copy. Uses a "helper function" named merge to
|
83
|
+
# combine successively bigger pieces of the input array.
|
84
|
+
|
85
|
+
def msort(a, mode = nil)
|
86
|
+
a = a.clone # don't modify the input array!
|
87
|
+
Timer.start
|
88
|
+
n = 1 # size of "pile" at each step
|
89
|
+
count = 0
|
90
|
+
while n < a.length
|
91
|
+
i = 0 # first pile starts here
|
92
|
+
while i < a.length
|
93
|
+
count += merge(a,i,n) # merge piles at a[i] and i+n, put at a[i]
|
94
|
+
print " [" + a[i..i+2*n-1].join(" ") + "] " if mode == :trace
|
95
|
+
i += 2*n # next pile starts at i+2n
|
96
|
+
end
|
97
|
+
puts if mode == :trace
|
98
|
+
n *= 2 # double the pile size
|
99
|
+
end
|
100
|
+
if mode == :timer
|
101
|
+
return Timer.stop
|
102
|
+
elsif mode == :count
|
103
|
+
return count
|
104
|
+
else
|
105
|
+
return a
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# "Helper function" to merge two "piles" in place. A call to this method
|
110
|
+
# merges n-element lists at a[i] and a[i+n] and stores the merged result
|
111
|
+
# in the array starting at a[i]. Uses an auxiliary list to hold items moved
|
112
|
+
# from a[i..i+n-1], then merges those into place at a[i+n].
|
113
|
+
|
114
|
+
def merge(a, i, n)
|
115
|
+
aux = []
|
116
|
+
j = k = i + n
|
117
|
+
kmax = i + 2*n
|
118
|
+
kmax = a.length if kmax > a.length
|
119
|
+
count = 0
|
120
|
+
# phase 1 -- copy items from a[i..i+n-1] to aux
|
121
|
+
while i < k
|
122
|
+
if a[j] && a[j] < a[i] && (aux.empty? || a[j] < aux[0])
|
123
|
+
aux << a[i]
|
124
|
+
a[i] = a[j]
|
125
|
+
j += 1
|
126
|
+
count += 1
|
127
|
+
elsif !aux.empty? && aux[0] < a[i]
|
128
|
+
aux << a[i]
|
129
|
+
a[i] = aux.shift
|
130
|
+
count += 1
|
131
|
+
end
|
132
|
+
i += 1
|
133
|
+
end
|
134
|
+
# phase 2 -- merge aux into empty slots in a[i+n..i+2n]
|
135
|
+
while k < kmax && ! aux.empty?
|
136
|
+
if j == kmax || a[j] > aux[0]
|
137
|
+
a[k] = aux.shift
|
138
|
+
else
|
139
|
+
a[k] = a[j]
|
140
|
+
j += 1
|
141
|
+
end
|
142
|
+
k += 1
|
143
|
+
count += 1
|
144
|
+
end
|
145
|
+
return count
|
146
|
+
end
|
147
|
+
|
148
|
+
# QuickSort, based on the description from Cormen et al. The interface is
|
149
|
+
# a method qsort, called with the array to sort and an optional mode parameter
|
150
|
+
# that specifies whether to count comparisons or measure execution time.
|
151
|
+
|
152
|
+
# The actual sorting is done by qs. The parameters (using notation from
|
153
|
+
# Cormen et al): p is the left boundary of the region to sort, and r is
|
154
|
+
# right boundary. The call to partition sets q, the new boundary between
|
155
|
+
# two sub-regions.
|
156
|
+
|
157
|
+
def qsort(a, mode = nil)
|
158
|
+
dup = a.clone
|
159
|
+
Timer.start
|
160
|
+
if mode == :timer
|
161
|
+
return Timer.stop
|
162
|
+
else
|
163
|
+
count = qs(dup, 0, a.length-1, mode)
|
164
|
+
return mode == :count ? count : dup
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def qs(a, p, r, mode)
|
169
|
+
puts bracketed(a,p,r) if mode == :trace
|
170
|
+
if p < r
|
171
|
+
q, count = partition(a, p, r)
|
172
|
+
count += qs(a, p, q, mode)
|
173
|
+
count += qs(a, q+1, r, mode)
|
174
|
+
else
|
175
|
+
count = 0
|
176
|
+
end
|
177
|
+
return count
|
178
|
+
end
|
179
|
+
|
180
|
+
# Set the pivot (called x here) to the item on the left edge of the
|
181
|
+
# region, then extend the regions until they meet in the middle
|
182
|
+
|
183
|
+
def partition(a, p, r)
|
184
|
+
x = a[p]
|
185
|
+
i = p - 1
|
186
|
+
j = r + 1
|
187
|
+
count = 0
|
188
|
+
while true
|
189
|
+
loop { j = j - 1; count += 1; break if a[j] <= x }
|
190
|
+
loop { i = i + 1; count += 1; break if a[i] >= x }
|
191
|
+
if i < j
|
192
|
+
a[i], a[j] = a[j], a[i]
|
193
|
+
else
|
194
|
+
return j, count
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def bracketed(a, left, right)
|
200
|
+
# puts "#{left}..#{right}"
|
201
|
+
tmp = []
|
202
|
+
tmp += a[ 0 .. (left-1) ] if left > 0
|
203
|
+
tmp << "["
|
204
|
+
tmp += a[ left .. right ] if right >= 0
|
205
|
+
tmp << "]"
|
206
|
+
tmp += a[ (right+1) .. (a.length-1) ] if right < a.length
|
207
|
+
return tmp.join(" ")
|
208
|
+
end
|
209
|
+
|
210
|
+
end # RecursionLab
|
211
|
+
|
212
|
+
end # RubyLabs
|
213
|
+
|
data/lib/spherelab.rb
ADDED
@@ -0,0 +1,352 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== SphereLab
|
5
|
+
|
6
|
+
Definition of Vector and Body objects used for n-body simulations.
|
7
|
+
|
8
|
+
=end
|
9
|
+
|
10
|
+
module RubyLabs
|
11
|
+
|
12
|
+
module SphereLab
|
13
|
+
|
14
|
+
=begin rdoc
|
15
|
+
The constant G is the universal gravitational constant, assuming mass is
|
16
|
+
in units of kilograms, distances are in meters, and time is in seconds.
|
17
|
+
=end
|
18
|
+
|
19
|
+
G = 6.67E-11
|
20
|
+
|
21
|
+
|
22
|
+
class Vector
|
23
|
+
attr_accessor :x, :y, :z
|
24
|
+
|
25
|
+
=begin rdoc
|
26
|
+
Make a new vector with the specified x, y, and z components.
|
27
|
+
=end
|
28
|
+
|
29
|
+
def initialize(*args)
|
30
|
+
@x, @y, @z = args
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
sprintf "<%s, %s, %s>", @x.to_s, @y.to_s, @z.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
=begin rdoc
|
38
|
+
v1 == v2 if the three components are the same
|
39
|
+
=end
|
40
|
+
|
41
|
+
def ==(v)
|
42
|
+
return (@x == v.x) && (@y == v.y) && (@z == v.z)
|
43
|
+
end
|
44
|
+
|
45
|
+
=begin rdoc
|
46
|
+
Arithmetic methods are invoked for a vector v1 when Ruby evaluates an expression of the
|
47
|
+
form v1 <op> v2 where <op> is +, -, or *. They create a a new vector containing the
|
48
|
+
result of the operation. + and - do element-wise addition or and subtraction, *
|
49
|
+
is a vector-scalar multiplication.
|
50
|
+
=end
|
51
|
+
|
52
|
+
def +(v)
|
53
|
+
Vector.new(@x + v.x, @y + v.y, @z + v.z)
|
54
|
+
end
|
55
|
+
|
56
|
+
def -(v)
|
57
|
+
Vector.new(@x - v.x, @y - v.y, @z - v.z)
|
58
|
+
end
|
59
|
+
|
60
|
+
def *(a)
|
61
|
+
Vector.new(@x * a, @y * a, @z * a)
|
62
|
+
end
|
63
|
+
|
64
|
+
=begin rdoc
|
65
|
+
v1.add(v2) adds the components of v2 to v1 -- would be v1 += v2 if Ruby
|
66
|
+
allowed us to overload +=
|
67
|
+
=end
|
68
|
+
|
69
|
+
def add(v)
|
70
|
+
@x += v.x
|
71
|
+
@y += v.y
|
72
|
+
@z += v.z
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
=begin rdoc
|
77
|
+
v1.sub(v2) subtracts the components of v2 from v1 -- would be v1 -= v2 if Ruby
|
78
|
+
allowed us to overload -=
|
79
|
+
=end
|
80
|
+
|
81
|
+
def sub(v)
|
82
|
+
@x -= v.x
|
83
|
+
@y -= v.y
|
84
|
+
@z -= v.z
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
=begin rdoc
|
89
|
+
The magnitude of a vector is the Euclidean norm: sqrt(x**2 + y**2 + z**2)
|
90
|
+
=end
|
91
|
+
|
92
|
+
def norm
|
93
|
+
Math.sqrt(@x*@x + @y*@y + @z*@z)
|
94
|
+
end
|
95
|
+
|
96
|
+
end # Vector
|
97
|
+
|
98
|
+
|
99
|
+
=begin rdoc
|
100
|
+
A Body object represents the state of a celestial body. A body has mass (a scalar),
|
101
|
+
position (a vector), and velocity (a vector). A third vector, named force, is used
|
102
|
+
when calculating forces acting on a body. The size and color attributes are used by
|
103
|
+
the visualization methods.
|
104
|
+
=end
|
105
|
+
|
106
|
+
class Body
|
107
|
+
attr_accessor :mass, :position, :velocity, :force, :name, :size, :color
|
108
|
+
|
109
|
+
=begin rdoc
|
110
|
+
The constructor can be called with a variety of different arguments:
|
111
|
+
* for the main n-body simulation, initial conditions are read from a data file,
|
112
|
+
and the constructor is passed three parameters: mass, position vector, and
|
113
|
+
velocity vector; an optional 4th parameter is a name string
|
114
|
+
* for interactive experiments, pass two floats, which become the mass and the
|
115
|
+
x component of the velocity; an optional 3rd parameter is the name
|
116
|
+
* also for interactive experiments pass :rand to make a body with random
|
117
|
+
mass, position, and velocity
|
118
|
+
* pass no parameters to get a body with all attributes set to 0
|
119
|
+
=end
|
120
|
+
|
121
|
+
def initialize(*args)
|
122
|
+
if args[1].class == Vector
|
123
|
+
@mass, @position, @velocity, @name = args
|
124
|
+
elsif args[0] == :random
|
125
|
+
@mass = rand(10000) * 1e6
|
126
|
+
@position = Vector.new(rand(300)-150, rand(300)-150, 0)
|
127
|
+
@velocity = Vector.new(rand(20)-10, rand(10)-5, 0)
|
128
|
+
@name = "b" + self.object_id.to_s
|
129
|
+
elsif args[0].is_a?(Numeric) && args[1].is_a?(Numeric)
|
130
|
+
@mass = args[0]
|
131
|
+
@position = Vector.new(args[1], 0.0, 0.0)
|
132
|
+
@velocity = Vector.new(0.0, 0.0, 0.0)
|
133
|
+
@name = args[2]
|
134
|
+
@linear = true
|
135
|
+
else
|
136
|
+
@mass = 0.0
|
137
|
+
@position = Vector.new(0.0, 0.0, 0.0)
|
138
|
+
@velocity = Vector.new(0.0, 0.0, 0.0)
|
139
|
+
@name = nil
|
140
|
+
end
|
141
|
+
@force = Vector.new(0.0, 0.0, 0.0)
|
142
|
+
end
|
143
|
+
|
144
|
+
def inspect
|
145
|
+
s = ""
|
146
|
+
s << @name + ": " if @name
|
147
|
+
s << @mass.to_s + "g "
|
148
|
+
if @linear
|
149
|
+
s << "x: " + @position.x.to_s
|
150
|
+
else
|
151
|
+
s << @position.inspect + " " + @velocity.inspect
|
152
|
+
end
|
153
|
+
return s
|
154
|
+
end
|
155
|
+
|
156
|
+
=begin rdoc
|
157
|
+
Reset the force vector to 0 (to get ready for a new round of interaction calculations).
|
158
|
+
=end
|
159
|
+
|
160
|
+
def clear_force
|
161
|
+
@force.x = 0.0
|
162
|
+
@force.y = 0.0
|
163
|
+
@force.z = 0.0
|
164
|
+
end
|
165
|
+
|
166
|
+
=begin rdoc
|
167
|
+
Compute force acting on this body wrt body b
|
168
|
+
=end
|
169
|
+
|
170
|
+
def add_force(b)
|
171
|
+
r = @position - b.position
|
172
|
+
nr = r.norm ** 3
|
173
|
+
mr = b.mass / nr
|
174
|
+
@force.add(r * mr)
|
175
|
+
end
|
176
|
+
|
177
|
+
=begin rdoc
|
178
|
+
Move this body by applying current force vector for dt seconds
|
179
|
+
=end
|
180
|
+
|
181
|
+
def move(dt)
|
182
|
+
acc = @force * G * -1.0
|
183
|
+
@velocity.add( acc * dt )
|
184
|
+
@position.add( @velocity * dt )
|
185
|
+
end
|
186
|
+
|
187
|
+
=begin rdoc
|
188
|
+
Class method to compute the interaction between bodies b1 and b2 and update
|
189
|
+
their force vectors.
|
190
|
+
=end
|
191
|
+
|
192
|
+
def Body.interaction(b1, b2)
|
193
|
+
r = b1.position - b2.position
|
194
|
+
a = r.norm ** 3
|
195
|
+
b1.force.add(r * (b2.mass / a))
|
196
|
+
b2.force.add(r * (-b1.mass / a))
|
197
|
+
end
|
198
|
+
|
199
|
+
end # Body
|
200
|
+
|
201
|
+
=begin rdoc
|
202
|
+
Make a list of Body objects using data in the file +fn+
|
203
|
+
=end
|
204
|
+
|
205
|
+
def read_bodies(fn)
|
206
|
+
bodies = []
|
207
|
+
File.open(fn).each do |line|
|
208
|
+
line.strip!
|
209
|
+
next if line.length == 0
|
210
|
+
next if line[0] == ?#
|
211
|
+
a = line.chomp.split
|
212
|
+
for i in 1..7
|
213
|
+
a[i] = a[i].to_f
|
214
|
+
end
|
215
|
+
b = Body.new( a[1], Vector.new(a[2],a[3],a[4]), Vector.new(a[5],a[6],a[7]), a[0] )
|
216
|
+
b.size = a[-2].to_i
|
217
|
+
b.color = a[-1]
|
218
|
+
bodies << b
|
219
|
+
end
|
220
|
+
return bodies
|
221
|
+
end
|
222
|
+
|
223
|
+
=begin rdoc
|
224
|
+
Call SphereLab::step(bodies, time) to calculate the pairwise interactions between all
|
225
|
+
Body objects in the array +bodies+ and then compute their new positions after +time+ seconds.
|
226
|
+
=end
|
227
|
+
|
228
|
+
# :begin :step
|
229
|
+
def step(bodies, time)
|
230
|
+
nb = bodies.length
|
231
|
+
|
232
|
+
for i in 0...nb # compute all pairwise interactions
|
233
|
+
for j in (i+1)...nb
|
234
|
+
Body.interaction( bodies[i], bodies[j] )
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
bodies.each do |b|
|
239
|
+
b.move(time) # apply the accumulated forces
|
240
|
+
b.clear_force # reset force to 0 for next round
|
241
|
+
end
|
242
|
+
end
|
243
|
+
# :end :step
|
244
|
+
|
245
|
+
def random_vectors(r, i, n)
|
246
|
+
theta = (2 * Math::PI / n) * i + (Math::PI * rand / n)
|
247
|
+
radius = r + (r/3)*(rand-0.5)
|
248
|
+
x = radius * Math.cos(theta)
|
249
|
+
y = radius * Math.sin(theta)
|
250
|
+
vtheta = (Math::PI - theta) * -1 + Math::PI * (rand-0.5)
|
251
|
+
vx = radius/20 * Math.cos(vtheta)
|
252
|
+
vy = radius/20 * Math.sin(vtheta)
|
253
|
+
return Vector.new(x, y, 0), Vector.new(vx, vy, 0)
|
254
|
+
end
|
255
|
+
|
256
|
+
def random_velocity(v, r)
|
257
|
+
res = Vector.new(-r * Math.cos)
|
258
|
+
end
|
259
|
+
|
260
|
+
def random_bodies(n, big = 1)
|
261
|
+
res = []
|
262
|
+
mm = 1e12 # average mass
|
263
|
+
mr = 150 # average distance from origin
|
264
|
+
write_tuple( :scale, [ 1.0 ] )
|
265
|
+
big.times do |i|
|
266
|
+
r0, v0 = random_vectors(mr/2, i, big)
|
267
|
+
res << Body.new(mm*100/big, r0, v0)
|
268
|
+
write_tuple( :view, [i, 10, "#0080ff"] )
|
269
|
+
end
|
270
|
+
(n-big).times do |i|
|
271
|
+
r, v = random_vectors(mr, i, n-big)
|
272
|
+
b = Body.new(mm, r, v)
|
273
|
+
b.name = "b" + (i+1).to_s
|
274
|
+
write_tuple( :view, [i+big, 5, "#0080ff"] )
|
275
|
+
res << b
|
276
|
+
end
|
277
|
+
return res
|
278
|
+
end
|
279
|
+
|
280
|
+
def urey_hall
|
281
|
+
write_tuple( :scale, [ 1e-7 ] )
|
282
|
+
# a 6.6 lb watermelon 7 stories (84 feet) above the surface of the earth:
|
283
|
+
w = Body.new(3000, 6.37101e6 + 25)
|
284
|
+
w.name = "watermelon"
|
285
|
+
w.size = 2
|
286
|
+
w.color = "#ff6666"
|
287
|
+
write_tuple( :view, [1, w.size, w.color] )
|
288
|
+
# the earth:
|
289
|
+
e = Body.new(5.9736E+24, 0)
|
290
|
+
e.name = "earth"
|
291
|
+
e.size = 100
|
292
|
+
e.color = "#004080"
|
293
|
+
write_tuple( :view, [0, e.size, e.color] )
|
294
|
+
return [e, w]
|
295
|
+
end
|
296
|
+
|
297
|
+
def four_body
|
298
|
+
write_tuple( :scale, [ 0.5 ] )
|
299
|
+
a = Body.new(1.4e18, Vector.new(50, 70, 0), Vector.new(0, 1, 0))
|
300
|
+
write_tuple( :view, [0, 10, "#ff6666"] )
|
301
|
+
b = Body.new(1.2e16, Vector.new(50, 225, 0), Vector.new(-1000, 2, 0))
|
302
|
+
write_tuple( :view, [1, 3, "#ff6666"] )
|
303
|
+
c = Body.new(2.1e16, Vector.new(175, -75, 0), Vector.new(-1, -5, 0))
|
304
|
+
write_tuple( :view, [2, 5, "#ff6666"] )
|
305
|
+
d = Body.new(4.5e16, Vector.new(300, -75, 0), Vector.new(-5, 2, 0))
|
306
|
+
write_tuple( :view, [3, 6, "#ff6666"] )
|
307
|
+
return [a,b,c,d]
|
308
|
+
end
|
309
|
+
|
310
|
+
=begin rdoc
|
311
|
+
Attach a probe to the step method, have it call this method to show the
|
312
|
+
current state of the simulation.
|
313
|
+
=end
|
314
|
+
|
315
|
+
def display(bodies)
|
316
|
+
for i in 0...bodies.length
|
317
|
+
write_tuple( :body, [i, bodies[i].position.x, bodies[i].position.y] )
|
318
|
+
end
|
319
|
+
write_tuple( :timestep, [] )
|
320
|
+
return true
|
321
|
+
end
|
322
|
+
|
323
|
+
=begin rdoc
|
324
|
+
Call this method to create a "scope" for viewing the state of an n-body simulation.
|
325
|
+
Also creates a proc that will be executed when IRB exits to shut down the tuple
|
326
|
+
space and viewer.
|
327
|
+
=end
|
328
|
+
|
329
|
+
def make_viewer
|
330
|
+
include Viewer
|
331
|
+
launch_viewer("nbview.rb")
|
332
|
+
end
|
333
|
+
|
334
|
+
=begin rdoc
|
335
|
+
Methods used in IRB sessions.
|
336
|
+
=end
|
337
|
+
|
338
|
+
# :begin :dist
|
339
|
+
def dist(r, t)
|
340
|
+
return r * t
|
341
|
+
end
|
342
|
+
# :end :dist
|
343
|
+
|
344
|
+
# :begin :falling
|
345
|
+
def falling(t)
|
346
|
+
return 0.5 * 9.8 * t**2
|
347
|
+
end
|
348
|
+
# :end :falling
|
349
|
+
|
350
|
+
end # SphereLab
|
351
|
+
|
352
|
+
end # RubyLabs
|
data/lib/temps.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== Ruby Workbench
|
5
|
+
|
6
|
+
Chapter 2, <em>The Ruby Workbench</em>, is an introduction to Ruby and IRB. There
|
7
|
+
are no "experiments," but the chapter does describe two methods. The code here is
|
8
|
+
available so students can make a copy by calling the +checkout+ method.
|
9
|
+
|
10
|
+
=end
|
11
|
+
|
12
|
+
module RubyLabs
|
13
|
+
|
14
|
+
module Temps
|
15
|
+
|
16
|
+
=begin rdoc
|
17
|
+
Convert the temperature +f+ (in degrees Fahrenheit) into the equivalent
|
18
|
+
temperature in degrees Celsius.
|
19
|
+
=end
|
20
|
+
|
21
|
+
# :begin :celsius
|
22
|
+
def celsius(f)
|
23
|
+
(f - 32) * 5 / 9
|
24
|
+
end
|
25
|
+
# :end :celsius
|
26
|
+
|
27
|
+
=begin rdoc
|
28
|
+
Fill in the body of this method with an equation that converts a number of
|
29
|
+
degrees on the Celsius scale to the equivalent on the Fahrenheit scale.
|
30
|
+
=end
|
31
|
+
|
32
|
+
# :begin :fahrenheit
|
33
|
+
def fahrenheit(c)
|
34
|
+
|
35
|
+
end
|
36
|
+
# :end :fahrenheit
|
37
|
+
|
38
|
+
|
39
|
+
end # Temp
|
40
|
+
|
41
|
+
end # RubyLabs
|