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/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
|