rubylabs 0.7.5 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/permute.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Permute the order of items in x. Does not copy x -- shuffles the
|
3
|
+
items in place. Works for strings, arrays, any container that responds to
|
4
|
+
length, [], and []=
|
5
|
+
=end
|
6
|
+
|
7
|
+
# :begin :permute! :random
|
8
|
+
def permute!(x)
|
9
|
+
for i in 0..x.length-2
|
10
|
+
r = random(i, x.length-1)
|
11
|
+
x[i], x[r] = x[r], x[i]
|
12
|
+
end
|
13
|
+
return x
|
14
|
+
end
|
15
|
+
# :end :permute!
|
16
|
+
|
17
|
+
=begin rdoc
|
18
|
+
A "helper method" for permute! that makes it easier to see which two
|
19
|
+
locations are being swapped. A call to random(i,j) returns a random
|
20
|
+
integer in the range i..j. See also PRNG::random
|
21
|
+
=end
|
22
|
+
|
23
|
+
# :begin :random
|
24
|
+
def random(min, max)
|
25
|
+
return nil if max < min
|
26
|
+
range = max - min + 1
|
27
|
+
return rand(range) + min
|
28
|
+
end
|
29
|
+
# :end :random
|
30
|
+
|
data/lib/randomlab.rb
CHANGED
@@ -7,10 +7,17 @@ Random number generators and associated methods.
|
|
7
7
|
|
8
8
|
=end
|
9
9
|
|
10
|
+
=begin
|
11
|
+
TODO number line -- mini-histogram, e.g. second tick drawn above first? else explain in lab manual / reference why two values per tickmark
|
12
|
+
TODO another thing for documentation: diff between p.random(x,y) and random(x,y) [latter uses Ruby's PRNG]
|
13
|
+
=end
|
14
|
+
|
10
15
|
module RubyLabs
|
11
16
|
|
12
17
|
module RandomLab
|
13
18
|
|
19
|
+
require "permute.rb"
|
20
|
+
|
14
21
|
=begin rdoc
|
15
22
|
Pseudo-random number generator. Constraints on a, c, and m:
|
16
23
|
* c and m must be relatively prime
|
@@ -80,39 +87,13 @@ module RandomLab
|
|
80
87
|
(0..51).map { |i| Card.new(i) }
|
81
88
|
end
|
82
89
|
|
83
|
-
=begin rdoc
|
84
|
-
Permute the order of items in x. Does not copy x -- shuffles the
|
85
|
-
items in place. Works for strings, arrays, any container that responds to
|
86
|
-
length, [], and []=
|
87
|
-
=end
|
88
|
-
|
89
|
-
# :begin :permute
|
90
|
-
def permute(x)
|
91
|
-
for i in 0..x.length-2
|
92
|
-
r = random(i, x.length-1)
|
93
|
-
x[i], x[r] = x[r], x[i]
|
94
|
-
end
|
95
|
-
return x
|
96
|
-
end
|
97
|
-
# :end :permute
|
98
|
-
|
99
|
-
=begin rdoc
|
100
|
-
A "helper method" for permute, that makes it easier to see which two
|
101
|
-
locations are being swapped. A call to random(i,j) returns a random
|
102
|
-
integer in the range i..j. See also PRNG::random
|
103
|
-
=end
|
104
|
-
|
105
|
-
def random(min, max)
|
106
|
-
return nil if max < min
|
107
|
-
range = max - min + 1
|
108
|
-
return rand(range) + min
|
109
|
-
end
|
110
|
-
|
111
90
|
=begin rdoc
|
112
91
|
A "helper method" that can be called via a probe, to print the contents
|
113
|
-
of an array during the execution of the permute method
|
92
|
+
of an array during the execution of the permute! method
|
114
93
|
=end
|
115
94
|
|
95
|
+
# Note: permute! moved to own source file, permute.rb
|
96
|
+
|
116
97
|
def brackets(a, i, r)
|
117
98
|
res = "#{r}: "
|
118
99
|
if i <= 0
|
data/lib/recursionlab.rb
CHANGED
@@ -64,18 +64,18 @@ Recursive implementation of binary search.
|
|
64
64
|
|
65
65
|
=end
|
66
66
|
|
67
|
-
# :begin :
|
68
|
-
def
|
67
|
+
# :begin :rbsearch
|
68
|
+
def rbsearch(a, k, lower = -1, upper = a.length)
|
69
69
|
mid = (lower + upper) / 2
|
70
70
|
return nil if upper == lower + 1 # search fails if the region is empty
|
71
71
|
return mid if k == a[mid] # search succeeds if k is at the midpoint
|
72
72
|
if k < a[mid]
|
73
|
-
return
|
73
|
+
return rbsearch(a, k, lower, mid)
|
74
74
|
else
|
75
|
-
return
|
75
|
+
return rbsearch(a, k, mid, upper)
|
76
76
|
end
|
77
77
|
end
|
78
|
-
# :end :
|
78
|
+
# :end :rbsearch
|
79
79
|
|
80
80
|
=begin rdoc
|
81
81
|
A helper method that can be called from a probe to display the contents
|
@@ -116,30 +116,38 @@ combine successively bigger pieces of the input array.
|
|
116
116
|
|
117
117
|
=end
|
118
118
|
|
119
|
-
# :begin :msort :merge :less
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
g *= 2 # double the group size
|
130
|
-
a = tmp # a now refers to array just built
|
131
|
-
end
|
132
|
-
return a
|
133
|
-
end
|
119
|
+
# :begin :msort :merge :merge_groups :less
|
120
|
+
def msort(array)
|
121
|
+
a = array.clone
|
122
|
+
size = 1
|
123
|
+
while size < a.length
|
124
|
+
merge_groups(a, size)
|
125
|
+
size = size * 2
|
126
|
+
end
|
127
|
+
return a
|
128
|
+
end
|
134
129
|
# :end :msort
|
135
130
|
|
136
|
-
# "Helper
|
137
|
-
|
131
|
+
# "Helper method" to merge all groups of size g
|
132
|
+
|
133
|
+
# :begin :merge_groups
|
134
|
+
def merge_groups(a, gs)
|
135
|
+
i = 0 # first group starts here
|
136
|
+
while i < a.length
|
137
|
+
j = i + 2*gs - 1 # end of second group
|
138
|
+
a[i..j] = merge(a, i, gs) # merge groups at a[i] and a[i+g]
|
139
|
+
i += 2*gs # next groups starts 2*g places to the right
|
140
|
+
end
|
141
|
+
end
|
142
|
+
# :end :merge_groups
|
143
|
+
|
144
|
+
# "Helper method" to merge two blocks. A call of the form merge(a, i, n) creates
|
145
|
+
# a new list by merging n-element lists starting at a[i] and a[i+n].
|
138
146
|
|
139
147
|
# :begin :merge
|
140
|
-
def merge(a, i,
|
141
|
-
ix = j = min(i +
|
142
|
-
jx = min(j +
|
148
|
+
def merge(a, i, gs) # :nodoc:
|
149
|
+
ix = j = min(i + gs, a.length)
|
150
|
+
jx = min(j + gs, a.length)
|
143
151
|
res = []
|
144
152
|
while i < ix || j < jx
|
145
153
|
if j == jx || i < ix && less( a[i], a[j] )
|
data/lib/rubylabs.rb
CHANGED
@@ -10,8 +10,7 @@ Methods used to monitor execution of programs during experiments.
|
|
10
10
|
|
11
11
|
SCRIPT_LINES__ = Hash.new unless defined? SCRIPT_LINES__
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
autoload :IntroLab, "introlab.rb"
|
15
14
|
autoload :SieveLab, "sievelab.rb"
|
16
15
|
autoload :IterationLab, "iterationlab.rb"
|
17
16
|
autoload :RecursionLab, "recursionlab.rb"
|
@@ -24,6 +23,10 @@ autoload :ElizaLab, "elizalab.rb"
|
|
24
23
|
autoload :SphereLab, "spherelab.rb"
|
25
24
|
autoload :TSPLab, "tsplab.rb"
|
26
25
|
|
26
|
+
autoload :Demos, "demos.rb"
|
27
|
+
|
28
|
+
include Math
|
29
|
+
|
27
30
|
module RubyLabs
|
28
31
|
|
29
32
|
=begin rdoc
|
@@ -43,7 +46,7 @@ Log base 2.
|
|
43
46
|
=end
|
44
47
|
|
45
48
|
def log2(x)
|
46
|
-
|
49
|
+
log(x) / log(2.0)
|
47
50
|
end
|
48
51
|
|
49
52
|
=begin rdoc
|
@@ -55,31 +58,17 @@ Log base 2.
|
|
55
58
|
end
|
56
59
|
|
57
60
|
=begin rdoc
|
58
|
-
Return the smaller of a and b
|
61
|
+
Return the smaller of +a+ and +b+
|
59
62
|
=end
|
60
63
|
|
61
64
|
def min(a,b)
|
62
65
|
a < b ? a : b
|
63
66
|
end
|
64
|
-
|
65
|
-
# =begin rdoc
|
66
|
-
# Return a copy of object x with the elements in a new, scrambled order. The
|
67
|
-
# parameter x can be any object that has an index operator (e.g. strings or
|
68
|
-
# arrays).
|
69
|
-
# =end
|
70
|
-
#
|
71
|
-
# def permutation(x)
|
72
|
-
# res = x.clone
|
73
|
-
# for i in 0..res.length-2
|
74
|
-
# r = rand(res.length-i) + i
|
75
|
-
# res[i], res[r] = res[r], res[i]
|
76
|
-
# end
|
77
|
-
# return res
|
78
|
-
# end
|
67
|
+
|
79
68
|
|
80
69
|
=begin rdoc
|
81
70
|
|
82
|
-
Call time { foo(...) } to measure the execution time of a call to foo
|
71
|
+
Call +time { foo(...) }+ to measure the execution time of a call to +foo+. This
|
83
72
|
method will time any arbitrary Ruby expression.
|
84
73
|
|
85
74
|
=end
|
@@ -157,9 +146,6 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
|
|
157
146
|
# to keep around for very few calls, but it's efficient enough -- making an array
|
158
147
|
# of 100K items takes less than a second.
|
159
148
|
|
160
|
-
# The @spread variable controls the average spacing between items. The 6.667 for
|
161
|
-
# small arrays means an array of 15 will have numbers between 0 and 99.
|
162
|
-
|
163
149
|
# An earlier version used a method named test_array to make a regular Array object
|
164
150
|
# and augment it with the location method, but the singleton's methods were not passed
|
165
151
|
# on to copies made by a call to sort:
|
@@ -169,72 +155,93 @@ Call +a.random(:success)+ to get a value that is in the array +a+, or call
|
|
169
155
|
# NoMethodError: undefined method `random' for [4, 13, 16]:Array
|
170
156
|
|
171
157
|
class TestArray < Array
|
172
|
-
|
173
|
-
def initialize(size)
|
174
|
-
@spread = (size > 50) ? 10 : 6.667
|
175
|
-
@h = Hash.new
|
176
158
|
|
177
|
-
|
178
|
-
|
179
|
-
|
159
|
+
data = File.join(File.dirname(__FILE__), '..', 'data', 'arrays')
|
160
|
+
|
161
|
+
@@sources = {
|
162
|
+
:cars => "#{data}/cars.txt",
|
163
|
+
:colors => "#{data}/colors.txt",
|
164
|
+
:fruits => "#{data}/fruit.txt",
|
165
|
+
:words => "#{data}/wordlist.txt",
|
166
|
+
}
|
180
167
|
|
181
|
-
|
182
|
-
|
183
|
-
|
168
|
+
def initialize(size, src = nil)
|
169
|
+
|
170
|
+
if src.nil? || src.class == Fixnum
|
171
|
+
raise "TestArray: array size must be an integer" unless size.class == Fixnum
|
172
|
+
if src.nil?
|
173
|
+
@max = (size < 50) ? 100 : (10 * size)
|
174
|
+
else
|
175
|
+
@max = src
|
176
|
+
raise "TestArray: max must be at least 2x larger than size" unless @max >= 2 * size
|
177
|
+
end
|
178
|
+
else
|
179
|
+
raise "TestArray: array size must be an integer or :all" unless size.class == Fixnum || size == :all
|
180
|
+
end
|
181
|
+
|
182
|
+
@h = Hash.new
|
183
|
+
|
184
|
+
# if @max is defined make an array of integers, otherwise src defines the type of data;
|
185
|
+
# size might be :all, in which case return the whole file, and set @all to true so random
|
186
|
+
# doesn't try to make a random value not in the array.
|
187
|
+
|
188
|
+
if @max
|
189
|
+
while @h.size < size
|
190
|
+
@h[ rand( @max ) ] = 1
|
191
|
+
end
|
192
|
+
else
|
193
|
+
fn = @@sources[src] or raise "TestArray: undefined source: #{src}"
|
194
|
+
@words = File.open(fn).readlines
|
195
|
+
if size != :all
|
196
|
+
max = @words.length
|
197
|
+
raise "TestArray: size must be less than #{max} for an array of #{src}" unless size < max
|
198
|
+
while @h.size < size
|
199
|
+
@h[ @words[ rand(max) ].chomp ] = 1
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
if size == :all
|
205
|
+
self.concat @words.map { |s| s.chomp! }
|
206
|
+
@all = true
|
207
|
+
else
|
208
|
+
self.concat @h.keys
|
209
|
+
for i in 0..length-2
|
210
|
+
r = rand(length-i) + i # i <= r < length
|
211
|
+
self[i],self[r] = self[r],self[i]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
184
215
|
end
|
185
216
|
|
186
217
|
def random(outcome)
|
187
218
|
if outcome == :success
|
188
219
|
return self[ rand(self.length) ]
|
189
220
|
elsif outcome == :fail
|
221
|
+
raise "TestArray#random: array is universal set" if @all
|
190
222
|
loop do
|
191
|
-
|
192
|
-
|
223
|
+
if @max
|
224
|
+
x = rand( @max )
|
225
|
+
else
|
226
|
+
x = @words[ rand( @words.length ) ].chomp
|
227
|
+
end
|
228
|
+
return x if @h[x] == nil
|
193
229
|
end
|
194
230
|
else
|
195
231
|
return nil
|
196
232
|
end
|
197
233
|
end
|
198
|
-
|
199
|
-
end # class TestArray
|
200
|
-
|
201
|
-
=begin rdoc
|
202
|
-
|
203
|
-
=== RandomArray
|
204
|
-
|
205
|
-
Similar to TestArray, but draws random words from a file.
|
206
|
-
|
207
|
-
=end
|
208
|
-
|
209
|
-
class RandomArray < Array
|
210
|
-
|
211
|
-
data = File.join(File.dirname(__FILE__), '..', 'data', 'arrays')
|
212
|
-
|
213
|
-
@@sources = {
|
214
|
-
:cars => "#{data}/cars.txt",
|
215
|
-
:colors => "#{data}/colors.txt",
|
216
|
-
:fruit => "#{data}/fruit.txt",
|
217
|
-
:words => "#{data}/wordlist.txt",
|
218
|
-
}
|
219
234
|
|
220
|
-
def
|
221
|
-
fn = @@sources[src] or raise "RandomArray: undefined array type: #{src}"
|
222
|
-
words = File.open(fn).readlines
|
223
|
-
a = Hash.new
|
224
|
-
while a.size < n
|
225
|
-
w = words[rand(words.length)].chomp
|
226
|
-
a[w] = 1
|
227
|
-
end
|
228
|
-
a.keys.each do |w|
|
229
|
-
self << w
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def RandomArray.sources
|
235
|
+
def TestArray.sources
|
234
236
|
return @@sources.keys.sort { |a,b| a.to_s <=> b.to_s }
|
235
237
|
end
|
236
|
-
|
237
|
-
|
238
|
+
|
239
|
+
end # class TestArray
|
240
|
+
|
241
|
+
|
242
|
+
def TestArray(n, type = nil)
|
243
|
+
TestArray.new(n, type)
|
244
|
+
end
|
238
245
|
|
239
246
|
|
240
247
|
=begin
|
@@ -406,7 +413,8 @@ Similar to TestArray, but draws random words from a file.
|
|
406
413
|
next
|
407
414
|
end
|
408
415
|
end
|
409
|
-
|
416
|
+
# if s =~ /:end\s+:#{id.to_s}\b/
|
417
|
+
if s =~ /:end\s+:#{id.to_s}\s/
|
410
418
|
size = line_num - base
|
411
419
|
throw :found
|
412
420
|
end
|
@@ -565,11 +573,25 @@ Similar to TestArray, but draws random words from a file.
|
|
565
573
|
# synch the drawing thread....
|
566
574
|
|
567
575
|
def Canvas.sync
|
568
|
-
if RUBY_VERSION =~ %r{^1\.8} && RUBY_PLATFORM =~ %r{darwin} && caller[
|
576
|
+
if RUBY_VERSION =~ %r{^1\.8} && RUBY_PLATFORM =~ %r{darwin} && caller[1].index("(irb)") == 0
|
569
577
|
sleep(0.1)
|
570
578
|
end
|
571
579
|
end
|
572
580
|
|
581
|
+
=begin rdoc
|
582
|
+
Add text at (x, y). Note -- looks like :anchor is required, otherwise runtime error
|
583
|
+
from Tk (something about illegal coords).
|
584
|
+
=end
|
585
|
+
|
586
|
+
def Canvas.text(s, x, y, opts = {})
|
587
|
+
return nil unless @@canvas
|
588
|
+
opts[:anchor] = :nw
|
589
|
+
opts[:text] = s
|
590
|
+
text = TkcText.new( @@canvas, x, y, opts)
|
591
|
+
@@objects << text
|
592
|
+
return text
|
593
|
+
end
|
594
|
+
|
573
595
|
=begin rdoc
|
574
596
|
Draw a line from (x0,y0) to (x1,y1)
|
575
597
|
=end
|
@@ -666,8 +688,8 @@ Similar to TestArray, but draws random words from a file.
|
|
666
688
|
(0...a.length).step(2) do |i|
|
667
689
|
x = a[i] - x0
|
668
690
|
y = a[i+1] - y0
|
669
|
-
a[i] = x0 + x *
|
670
|
-
a[i+1] = y0 + x *
|
691
|
+
a[i] = x0 + x * cos(theta) - y * sin(theta)
|
692
|
+
a[i+1] = y0 + x * sin(theta) + y * cos(theta)
|
671
693
|
end
|
672
694
|
obj.coords = a
|
673
695
|
return a
|
data/lib/sievelab.rb
CHANGED
@@ -10,19 +10,18 @@ filtering step until no more composite numbers are left in the worklist.
|
|
10
10
|
|
11
11
|
=end
|
12
12
|
|
13
|
-
include Math
|
14
|
-
|
15
13
|
module RubyLabs
|
16
14
|
|
17
15
|
module SieveLab
|
18
|
-
|
19
|
-
|
16
|
+
|
17
|
+
=begin rdoc
|
18
|
+
Call +sieve(n)+ to create an array of prime numbers between +2+ and +n+
|
19
|
+
=end
|
20
20
|
|
21
21
|
# :begin :sieve
|
22
22
|
def sieve(n)
|
23
|
-
|
24
|
-
worklist =
|
25
|
-
(n-1).times { |i| worklist << i+2 }
|
23
|
+
return [] if n < 2
|
24
|
+
worklist = Array(2..n)
|
26
25
|
primes = []
|
27
26
|
|
28
27
|
while worklist.first < sqrt(n)
|
@@ -34,25 +33,6 @@ module SieveLab
|
|
34
33
|
end
|
35
34
|
# :end :sieve
|
36
35
|
|
37
|
-
|
38
|
-
# A first version of the sieve, iterates until the worklist is empty
|
39
|
-
|
40
|
-
# :begin :proto_sieve
|
41
|
-
def proto_sieve(n)
|
42
|
-
return [] if n < 2
|
43
|
-
worklist = []
|
44
|
-
(n-1).times { |i| worklist << i+2 }
|
45
|
-
primes = []
|
46
|
-
|
47
|
-
while worklist.length > 0
|
48
|
-
primes << worklist.first
|
49
|
-
worklist.delete_if { |x| x % primes.last == 0 }
|
50
|
-
end
|
51
|
-
|
52
|
-
return primes
|
53
|
-
end
|
54
|
-
# :end :proto_sieve
|
55
|
-
|
56
36
|
end # SieveLab
|
57
37
|
|
58
38
|
end # RubyLabs
|
data/lib/spherelab.rb
CHANGED
@@ -7,8 +7,6 @@ Definition of Vector and Body objects used for n-body simulations.
|
|
7
7
|
|
8
8
|
=end
|
9
9
|
|
10
|
-
include Math
|
11
|
-
|
12
10
|
module RubyLabs
|
13
11
|
|
14
12
|
module SphereLab
|
@@ -18,7 +16,7 @@ module SphereLab
|
|
18
16
|
global values.
|
19
17
|
=end
|
20
18
|
|
21
|
-
@@
|
19
|
+
@@sphereDirectory = File.join(File.dirname(__FILE__), '..', 'data', 'spheres')
|
22
20
|
|
23
21
|
@@viewerOptions = {
|
24
22
|
:dotColor => '#000080',
|
@@ -210,6 +208,17 @@ module SphereLab
|
|
210
208
|
end
|
211
209
|
@force = Vector.new(0.0, 0.0, 0.0)
|
212
210
|
end
|
211
|
+
|
212
|
+
def clone
|
213
|
+
copy = super
|
214
|
+
if graphic
|
215
|
+
copy.position = position.clone
|
216
|
+
copy.velocity = velocity.clone
|
217
|
+
copy.force = force.clone
|
218
|
+
copy.graphic = Canvas.circle(prevx, prevy, size, :fill => color)
|
219
|
+
end
|
220
|
+
return copy
|
221
|
+
end
|
213
222
|
|
214
223
|
def inspect
|
215
224
|
name = @name ? @name : ""
|
@@ -398,7 +407,8 @@ module SphereLab
|
|
398
407
|
end
|
399
408
|
|
400
409
|
def set_flag(fx, fy)
|
401
|
-
|
410
|
+
r = 3.0
|
411
|
+
Canvas.circle( fx + r/2, fy + r/2, r, :fill => 'darkblue' )
|
402
412
|
@reference = [ fx, fy ]
|
403
413
|
end
|
404
414
|
|
@@ -475,8 +485,8 @@ module SphereLab
|
|
475
485
|
def falling_bodies(n)
|
476
486
|
raise "n must be 5 or more" unless n >= 5
|
477
487
|
a = random_bodies(n-1, n-1)
|
478
|
-
|
479
|
-
b = Body.new(1e13, (a[0].position + a[1].position)*0.85, Vector.new(0,0,0))
|
488
|
+
b = Body.new(1e13, (a[0].position + a[1].position), Vector.new(0,0,0))
|
489
|
+
# b = Body.new(1e13, (a[0].position + a[1].position)*0.85, Vector.new(0,0,0))
|
480
490
|
# pos = a[0].position
|
481
491
|
# (1..(n-2)).each { |i| pos.add( a[i].position ) }
|
482
492
|
# b = Body.new(1e14, pos * (1.0 / n), Vector.new(0,0,0))
|
@@ -506,7 +516,7 @@ module SphereLab
|
|
506
516
|
end
|
507
517
|
filename = args[0]
|
508
518
|
if filename.class == Symbol
|
509
|
-
filename = File.join(@@
|
519
|
+
filename = File.join(@@sphereDirectory, filename.to_s + ".txt")
|
510
520
|
end
|
511
521
|
File.open(filename).each do |line|
|
512
522
|
line.strip!
|
@@ -521,7 +531,7 @@ module SphereLab
|
|
521
531
|
b.color = a[-1]
|
522
532
|
bodies << b
|
523
533
|
end
|
524
|
-
if args[0] == :
|
534
|
+
if args[0] == :melon
|
525
535
|
class <<bodies[0]
|
526
536
|
def height
|
527
537
|
return 0 if prevy.nil?
|
@@ -538,6 +548,27 @@ module SphereLab
|
|
538
548
|
return bodies
|
539
549
|
end
|
540
550
|
|
551
|
+
=begin rdoc
|
552
|
+
Write the mass, position, and velocity for each body to a file. Not intended to
|
553
|
+
be used by students, but used to save interesting data sets they can load and use.
|
554
|
+
=end
|
555
|
+
|
556
|
+
# d 4.5e16 300 -75 0 -5 2 0 6 #ff6666
|
557
|
+
|
558
|
+
|
559
|
+
def save_system(b, fn)
|
560
|
+
raise "file exists" if File.exists?(fn)
|
561
|
+
File.open(fn, "w") do |f|
|
562
|
+
b.each do |x|
|
563
|
+
f.printf "%s %g %g %g %g %g %g %g %d %s\n",
|
564
|
+
x.name, x.mass,
|
565
|
+
x.position.x, x.position.y, x.position.z,
|
566
|
+
x.velocity.x, x.velocity.y, x.velocity.z,
|
567
|
+
x.size, x.color
|
568
|
+
end
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
541
572
|
=begin rdoc
|
542
573
|
Initialize the drawing canvas by drawing a circle for each body in list b.
|
543
574
|
=end
|
@@ -571,31 +602,26 @@ module SphereLab
|
|
571
602
|
Demonstrate adding force vectors by moving only one body
|
572
603
|
=end
|
573
604
|
|
574
|
-
def update_one(
|
575
|
-
|
576
|
-
if b.graphic.nil?
|
605
|
+
def update_one(falling, stationary, time)
|
606
|
+
if falling.graphic.nil?
|
577
607
|
puts "display the system with view_system"
|
578
608
|
return nil
|
579
609
|
end
|
580
|
-
|
581
|
-
Body.interaction(
|
610
|
+
stationary.each do |x|
|
611
|
+
Body.interaction( falling, x )
|
582
612
|
end
|
583
|
-
|
613
|
+
falling.move(time)
|
584
614
|
if @@drawing.options.has_key?(:dash)
|
585
615
|
@@drawing.options[:dashcount] = (@@drawing.options[:dashcount] + 1) % @@drawing.options[:dash]
|
586
616
|
if @@drawing.options[:dashcount] == 0
|
587
617
|
@@drawing.options[:pendown] = @@drawing.options[:pendown].nil? ? :track : nil
|
588
618
|
end
|
589
619
|
end
|
590
|
-
newx, newy = scale(
|
591
|
-
Canvas.move(
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
# puts b.velocity.norm
|
596
|
-
# if (speed = b.velocity.norm) > 7.5
|
597
|
-
# b.velocity.scale(7.5 / speed)
|
598
|
-
# end
|
620
|
+
newx, newy = scale(falling.position, @@drawing.origin, @@drawing.scale)
|
621
|
+
Canvas.move(falling.graphic, newx-falling.prevx, newy-falling.prevy, @@drawing.options[:pendown])
|
622
|
+
falling.prevx = newx
|
623
|
+
falling.prevy = newy
|
624
|
+
falling.clear_force
|
599
625
|
Canvas.sync
|
600
626
|
return true
|
601
627
|
end
|