redshift 1.3.15
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/README +5 -0
- data/RELEASE-NOTES +455 -0
- data/TODO +431 -0
- data/bench/alg-state.rb +61 -0
- data/bench/bench +26 -0
- data/bench/bench.rb +10 -0
- data/bench/continuous.rb +76 -0
- data/bench/diff-bench +86 -0
- data/bench/discrete.rb +101 -0
- data/bench/euler.rb +50 -0
- data/bench/formula.rb +78 -0
- data/bench/half-strict.rb +103 -0
- data/bench/inertness.rb +116 -0
- data/bench/queue.rb +92 -0
- data/bench/run +66 -0
- data/bench/simple.rb +74 -0
- data/bench/strictness.rb +86 -0
- data/examples/ball-tkar.rb +72 -0
- data/examples/ball.rb +123 -0
- data/examples/collide.rb +70 -0
- data/examples/connect-parallel.rb +48 -0
- data/examples/connect.rb +109 -0
- data/examples/constants.rb +27 -0
- data/examples/delay.rb +80 -0
- data/examples/derivative.rb +77 -0
- data/examples/euler.rb +46 -0
- data/examples/external-lib.rb +33 -0
- data/examples/guard-debugger.rb +77 -0
- data/examples/lotka-volterra.rb +33 -0
- data/examples/persist-ball.rb +68 -0
- data/examples/pid.rb +87 -0
- data/examples/ports.rb +60 -0
- data/examples/queue.rb +56 -0
- data/examples/queue2.rb +98 -0
- data/examples/reset-with-event-val.rb +28 -0
- data/examples/scheduler.rb +104 -0
- data/examples/set-dest.rb +23 -0
- data/examples/simulink/README +1 -0
- data/examples/simulink/delay.mdl +827 -0
- data/examples/simulink/derivative.mdl +655 -0
- data/examples/step-discrete-profiler.rb +103 -0
- data/examples/subsystem.rb +109 -0
- data/examples/sync-deadlock.rb +32 -0
- data/examples/sync-queue.rb +91 -0
- data/examples/sync-retry.rb +20 -0
- data/examples/sync.rb +51 -0
- data/examples/thermostat.rb +53 -0
- data/examples/zeno.rb +53 -0
- data/lib/accessible-index.rb +47 -0
- data/lib/redshift.rb +1 -0
- data/lib/redshift/component.rb +412 -0
- data/lib/redshift/meta.rb +183 -0
- data/lib/redshift/mixins/zeno-debugger.rb +69 -0
- data/lib/redshift/port.rb +57 -0
- data/lib/redshift/queue.rb +104 -0
- data/lib/redshift/redshift.rb +111 -0
- data/lib/redshift/state.rb +31 -0
- data/lib/redshift/syntax.rb +558 -0
- data/lib/redshift/target/c.rb +37 -0
- data/lib/redshift/target/c/component-gen.rb +1303 -0
- data/lib/redshift/target/c/flow-gen.rb +325 -0
- data/lib/redshift/target/c/flow/algebraic.rb +85 -0
- data/lib/redshift/target/c/flow/buffer.rb +74 -0
- data/lib/redshift/target/c/flow/delay.rb +203 -0
- data/lib/redshift/target/c/flow/derivative.rb +101 -0
- data/lib/redshift/target/c/flow/euler.rb +67 -0
- data/lib/redshift/target/c/flow/expr.rb +113 -0
- data/lib/redshift/target/c/flow/rk4.rb +80 -0
- data/lib/redshift/target/c/library.rb +85 -0
- data/lib/redshift/target/c/world-gen.rb +1370 -0
- data/lib/redshift/target/spec.rb +34 -0
- data/lib/redshift/world.rb +300 -0
- data/rakefile +37 -0
- data/test/test.rb +52 -0
- data/test/test_buffer.rb +58 -0
- data/test/test_connect.rb +242 -0
- data/test/test_connect_parallel.rb +47 -0
- data/test/test_connect_strict.rb +135 -0
- data/test/test_constant.rb +74 -0
- data/test/test_delay.rb +145 -0
- data/test/test_derivative.rb +48 -0
- data/test/test_discrete.rb +592 -0
- data/test/test_discrete_isolated.rb +92 -0
- data/test/test_exit.rb +59 -0
- data/test/test_flow.rb +200 -0
- data/test/test_flow_link.rb +288 -0
- data/test/test_flow_sub.rb +100 -0
- data/test/test_flow_trans.rb +292 -0
- data/test/test_inherit.rb +127 -0
- data/test/test_inherit_event.rb +74 -0
- data/test/test_inherit_flow.rb +139 -0
- data/test/test_inherit_link.rb +65 -0
- data/test/test_inherit_setup.rb +56 -0
- data/test/test_inherit_state.rb +66 -0
- data/test/test_inherit_transition.rb +168 -0
- data/test/test_numerics.rb +34 -0
- data/test/test_queue.rb +90 -0
- data/test/test_queue_alone.rb +115 -0
- data/test/test_reset.rb +209 -0
- data/test/test_setup.rb +119 -0
- data/test/test_strict_continuity.rb +410 -0
- data/test/test_strict_reset_error.rb +30 -0
- data/test/test_strictness_error.rb +32 -0
- data/test/test_sync.rb +185 -0
- data/test/test_world.rb +328 -0
- metadata +204 -0
data/bench/inertness.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'redshift'
|
2
|
+
require 'enumerator'
|
3
|
+
|
4
|
+
include RedShift
|
5
|
+
|
6
|
+
module Inertness
|
7
|
+
class Inert < Component
|
8
|
+
# An inert component is one that has no transitions out of its
|
9
|
+
# current state. However, flows are allowed. But for a sharper
|
10
|
+
# comparison, we don't define any.
|
11
|
+
#
|
12
|
+
# flow do
|
13
|
+
# diff " t' = 1 "
|
14
|
+
# end
|
15
|
+
|
16
|
+
# Adding just one trivial transition prevents the inert optimization,
|
17
|
+
# with dramatic effects (increase of 60% cpu time in first case).
|
18
|
+
#
|
19
|
+
# 1000 comps X 10000 steps X 0 non-inert: +0.60
|
20
|
+
# 1000 comps X 10000 steps X 1 non-inert: +0.59
|
21
|
+
#
|
22
|
+
# transition Enter => Exit do
|
23
|
+
# guard "0"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Turning off the inert optimization in the world source, without adding
|
27
|
+
# a transition, is a bit less dramatic, but a more realistic indicator
|
28
|
+
# of the value of the optimization:
|
29
|
+
#
|
30
|
+
# 1000 comps X 10000 steps X 0 non-inert: +0.39
|
31
|
+
# 1000 comps X 10000 steps X 1 non-inert: +0.36
|
32
|
+
end
|
33
|
+
|
34
|
+
class NonInert < Component
|
35
|
+
n_states = 10
|
36
|
+
# increasing this doesn't make the difference (w/ and w/o the inert
|
37
|
+
# optimization) larger because the inerts go on strict sleep anyway.
|
38
|
+
my_states = state((0...n_states).map {|i| "S#{i}"})
|
39
|
+
start S0
|
40
|
+
flow S0 do
|
41
|
+
diff " t' = 1 "
|
42
|
+
end
|
43
|
+
transition S0 => S1 do
|
44
|
+
guard " t >= 0.1 "
|
45
|
+
reset :t => 0
|
46
|
+
end
|
47
|
+
my_states[1..-1].each_cons(2) do |s, t|
|
48
|
+
transition s => t
|
49
|
+
end
|
50
|
+
transition my_states.last => my_states.first
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.make_world n_inert, n_non_inert=0
|
54
|
+
w = World.new
|
55
|
+
n_inert.times {w.create(Inert)}
|
56
|
+
n_non_inert.times {w.create(NonInert)}
|
57
|
+
w
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.do_bench
|
61
|
+
[0, 1].each do |n_non_inert|
|
62
|
+
[ [ 0, 10_000],
|
63
|
+
[ 1000, 10_000] ].each do
|
64
|
+
| n_inert, n_s|
|
65
|
+
|
66
|
+
w = make_world(n_inert, n_non_inert)
|
67
|
+
w.run 1 # warm up
|
68
|
+
r = bench do
|
69
|
+
w.run(n_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
yield " - %10d comps X %10d steps X %10d non-inert: %8.2f" %
|
73
|
+
[n_inert, n_s, n_non_inert, r]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
if __FILE__ == $0
|
80
|
+
|
81
|
+
require File.join(File.dirname(__FILE__), 'bench')
|
82
|
+
puts "inert:"
|
83
|
+
Inertness.do_bench {|l| puts l}
|
84
|
+
|
85
|
+
exit
|
86
|
+
|
87
|
+
n_inert = 10000
|
88
|
+
n_non_inert = 0
|
89
|
+
n_steps = 1000
|
90
|
+
|
91
|
+
|
92
|
+
times = Process.times
|
93
|
+
t0 = Time.now
|
94
|
+
pt0 = times.utime #+ times.stime
|
95
|
+
|
96
|
+
w.run n_steps
|
97
|
+
|
98
|
+
times = Process.times
|
99
|
+
t1 = Time.now
|
100
|
+
pt1 = times.utime #+ times.stime
|
101
|
+
puts "process time: %8.2f" % (pt1-pt0)
|
102
|
+
puts "elapsed time: %8.2f" % (t1-t0)
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
__END__
|
107
|
+
|
108
|
+
The best case so far is:
|
109
|
+
|
110
|
+
without inert optimization
|
111
|
+
process time: 6.58
|
112
|
+
elapsed time: 6.59
|
113
|
+
|
114
|
+
with inert optimization
|
115
|
+
process time: 5.11
|
116
|
+
elapsed time: 5.12
|
data/bench/queue.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# Measures performance of redshift queues.
|
2
|
+
|
3
|
+
require 'redshift'
|
4
|
+
|
5
|
+
module Queue
|
6
|
+
class Clock < RedShift::Component
|
7
|
+
# the only continuous var in the whole system
|
8
|
+
strictly_continuous :time
|
9
|
+
flow {
|
10
|
+
diff " time' = 1 "
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
class Sender < RedShift::Component
|
15
|
+
strict_link :clock => Clock
|
16
|
+
|
17
|
+
constant :next_wakeup
|
18
|
+
strictly_constant :period
|
19
|
+
|
20
|
+
# list of target queues that this comp will send to
|
21
|
+
def targets
|
22
|
+
@targets ||= []
|
23
|
+
end
|
24
|
+
|
25
|
+
setup do
|
26
|
+
self.next_wakeup = period
|
27
|
+
end
|
28
|
+
|
29
|
+
transition do
|
30
|
+
guard " clock.time >= next_wakeup "
|
31
|
+
reset :next_wakeup => " clock.time + period "
|
32
|
+
action do
|
33
|
+
targets.each do |target|
|
34
|
+
target << :awake
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Receiver < RedShift::Component
|
41
|
+
queue :q
|
42
|
+
transition do
|
43
|
+
wait :q
|
44
|
+
action do
|
45
|
+
q.pop
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.make_world n_sender=1, n_receiver=0
|
51
|
+
w = RedShift::World.new
|
52
|
+
clock = w.create(Clock)
|
53
|
+
n_sender.times do |i|
|
54
|
+
sender = w.create(Sender) do |s|
|
55
|
+
s.clock = clock
|
56
|
+
s.next_wakeup = ((i % 99)+1) / 10.0
|
57
|
+
s.period = 10
|
58
|
+
n_receiver.times do
|
59
|
+
w.create(Receiver) do |r|
|
60
|
+
s.targets << r.q
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
w
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.do_bench
|
69
|
+
[1, 10, 100].each do |n_r|
|
70
|
+
[1, 10, 100].each do |n_s|
|
71
|
+
n_steps = 100_000 / (n_r * n_s)
|
72
|
+
do_bench_one(n_s, n_steps, n_r) {|r| yield r}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.do_bench_one(n_s, n_steps, n_r)
|
78
|
+
w = make_world(n_s, n_r)
|
79
|
+
r = bench do
|
80
|
+
w.run(n_steps)
|
81
|
+
end
|
82
|
+
|
83
|
+
yield " - %10d senders X %10d steps X %5d receivers: %8.2f" %
|
84
|
+
[n_s, n_steps, n_r, r]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if __FILE__ == $0
|
89
|
+
require File.join(File.dirname(__FILE__), 'bench')
|
90
|
+
puts "queue:"
|
91
|
+
Queue.do_bench_one(*ARGV.map{|s|s.to_i}) {|l| puts l}
|
92
|
+
end
|
data/bench/run
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'my-profile.rb'
|
4
|
+
|
5
|
+
class Object
|
6
|
+
def rbprofile prof_flag = true
|
7
|
+
if block_given?
|
8
|
+
$profiler.instance_eval do
|
9
|
+
save = @do_profiling
|
10
|
+
@do_profiling = prof_flag
|
11
|
+
yield
|
12
|
+
@do_profiling = save
|
13
|
+
end
|
14
|
+
else
|
15
|
+
$profiler.instance_eval {@do_profiling = prof_flag}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
bench_flag = ARGV.delete("b") || ARGV.delete("bench")
|
21
|
+
profile_flag = ARGV.delete("p") || ARGV.delete("profile")
|
22
|
+
rbprof_flag = ARGV.delete("rbprof")
|
23
|
+
|
24
|
+
prog_name = ARGV.shift
|
25
|
+
|
26
|
+
$REDSHIFT_CLIB_NAME = prog_name
|
27
|
+
|
28
|
+
case
|
29
|
+
when bench_flag
|
30
|
+
require prog_name; steps = $steps
|
31
|
+
require 'benchmark'
|
32
|
+
include Benchmark
|
33
|
+
bm(12) do |test|
|
34
|
+
for step in steps
|
35
|
+
test.report(step[0] + ":") do
|
36
|
+
step[1].call
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
when profile_flag
|
42
|
+
require prog_name; steps = $steps
|
43
|
+
for step in steps
|
44
|
+
# require 'profile' if step[0] == "run" # don't profile compilation
|
45
|
+
profile (step[0] == "run") do # only profile run, not compile or create
|
46
|
+
step[1].call
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
when rbprof_flag
|
51
|
+
require 'rbprof'; rbprofile false
|
52
|
+
require prog_name; steps = $steps
|
53
|
+
for step in steps
|
54
|
+
if step[0] == "run" # don't profile compilation
|
55
|
+
rbprofile {step[1].call}
|
56
|
+
else
|
57
|
+
step[1].call
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
else
|
62
|
+
require prog_name; steps = $steps
|
63
|
+
for step in steps
|
64
|
+
step[1].call
|
65
|
+
end
|
66
|
+
end
|
data/bench/simple.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'redshift'
|
2
|
+
|
3
|
+
class Thing < RedShift::Component
|
4
|
+
flow {
|
5
|
+
diff "w' = 1"
|
6
|
+
alg "ww = 2*w + (sin(w) + cos(w))*(sin(w) + cos(w))"
|
7
|
+
alg "www = ww-2"
|
8
|
+
diff "u' = www"
|
9
|
+
}
|
10
|
+
def inspect data = nil
|
11
|
+
d = "; #{data}" if data
|
12
|
+
vars = [
|
13
|
+
"w = #{w}"
|
14
|
+
]
|
15
|
+
super "#{vars.join(", ")}#{d}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Base < RedShift::Component
|
20
|
+
flow {
|
21
|
+
diff "x' = 1"
|
22
|
+
}
|
23
|
+
def inspect data = nil
|
24
|
+
d = "; #{data}" if data
|
25
|
+
vars = [
|
26
|
+
"x = #{x}"
|
27
|
+
]
|
28
|
+
super "#{vars.join(", ")}#{d}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Tester < Base
|
33
|
+
link :thing => Thing
|
34
|
+
flow {
|
35
|
+
alg "xx = 3*x"
|
36
|
+
diff "y' = xx"
|
37
|
+
diff "z' = y + 4*(thing.w+thing.u)"
|
38
|
+
}
|
39
|
+
|
40
|
+
def inspect data = nil
|
41
|
+
d = "; #{data}" if data
|
42
|
+
vars = [
|
43
|
+
"xx = #{xx}",
|
44
|
+
"y = #{y}",
|
45
|
+
"z = #{z}"
|
46
|
+
]
|
47
|
+
super "#{vars.join(", ")}#{d}"
|
48
|
+
end
|
49
|
+
|
50
|
+
setup do
|
51
|
+
self.thing = create Thing
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#----------------------------------#
|
56
|
+
|
57
|
+
n_obj = 100
|
58
|
+
n_iter = 100_000
|
59
|
+
|
60
|
+
# 10, 100_000 ==> 8.87 seconds
|
61
|
+
|
62
|
+
world = nil
|
63
|
+
$steps = [
|
64
|
+
["commit", proc { world = RedShift::World.new {|w| w.time_step = 0.05} }],
|
65
|
+
["create", proc { n_obj.times do world.create Tester end }],
|
66
|
+
["run", proc { world.run n_iter }]
|
67
|
+
]
|
68
|
+
|
69
|
+
END {
|
70
|
+
# puts "time_step = #{world.time_step}"
|
71
|
+
# puts "clock = #{world.clock}"
|
72
|
+
# t = world.find { |c| c.is_a? Tester }
|
73
|
+
# p t
|
74
|
+
}
|
data/bench/strictness.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'my-profile'
|
2
|
+
|
3
|
+
$strict = ARGV.delete("-s")
|
4
|
+
|
5
|
+
# This makes a 5x difference!
|
6
|
+
if $strict
|
7
|
+
$REDSHIFT_CLIB_NAME = "strictness-on"
|
8
|
+
else
|
9
|
+
$REDSHIFT_CLIB_NAME = "strictness-off"
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'redshift'
|
13
|
+
include RedShift
|
14
|
+
|
15
|
+
class SimpleComponent < Component
|
16
|
+
|
17
|
+
continuous :x
|
18
|
+
if $strict
|
19
|
+
strictly_continuous :y
|
20
|
+
strict_link :other => SimpleComponent
|
21
|
+
else
|
22
|
+
continuous :y
|
23
|
+
link :other => SimpleComponent
|
24
|
+
end
|
25
|
+
|
26
|
+
state :A, :B; default { start A; self.other = self }
|
27
|
+
|
28
|
+
flow A do
|
29
|
+
diff " y' = 1 + x " # y still strict even though x is not
|
30
|
+
end
|
31
|
+
|
32
|
+
5.times do
|
33
|
+
transition A => B do
|
34
|
+
guard " pow(y, 2) - sin(y) + cos(y) + other.y < 0 "
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class ComplexComponent < Component
|
41
|
+
|
42
|
+
attr_accessor :start_value
|
43
|
+
|
44
|
+
state :A, :B, :C, :D, :E1, :F; default { start A }
|
45
|
+
|
46
|
+
flow A do
|
47
|
+
diff "t' = 1"
|
48
|
+
end
|
49
|
+
|
50
|
+
transition A => B do
|
51
|
+
guard "t > 1"
|
52
|
+
action do
|
53
|
+
if @start_value
|
54
|
+
self.t = @start_value
|
55
|
+
@start_value = nil
|
56
|
+
else
|
57
|
+
self.t = 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
transition B => C, C => D, D => E1, E1 => F, F => A
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
n = 1000
|
67
|
+
hz = 100
|
68
|
+
ts = 1.0/hz
|
69
|
+
w = World.new { |w| w.time_step = ts }
|
70
|
+
n.times do w.create SimpleComponent end
|
71
|
+
hz.times do |i|
|
72
|
+
cc = w.create ComplexComponent
|
73
|
+
cc.start_value = i*ts
|
74
|
+
end
|
75
|
+
|
76
|
+
times = Process.times
|
77
|
+
t0 = Time.now
|
78
|
+
pt0 = times.utime #+ times.stime
|
79
|
+
profile false do
|
80
|
+
w.run 1000
|
81
|
+
end
|
82
|
+
times = Process.times
|
83
|
+
t1 = Time.now
|
84
|
+
pt1 = times.utime #+ times.stime
|
85
|
+
puts "process time: %8.2f" % (pt1-pt0)
|
86
|
+
puts "elapsed time: %8.2f" % (t1-t0)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Example showing how to use tkar to animate a redshift simulation.
|
2
|
+
#
|
3
|
+
# Tkar can be found at http://path.berkeley.edu/~vjoel/vis/tkar
|
4
|
+
|
5
|
+
require 'redshift'
|
6
|
+
include RedShift
|
7
|
+
|
8
|
+
class Ball < Component
|
9
|
+
continuous :x, :y, :v
|
10
|
+
|
11
|
+
flow do
|
12
|
+
diff "y' = v"
|
13
|
+
diff "v' = -9.8"
|
14
|
+
end
|
15
|
+
|
16
|
+
transition do
|
17
|
+
guard "y - 5 < 0 && v < 0"
|
18
|
+
reset :v => "-v"
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :id # so we can keep track of which is which in animation
|
22
|
+
end
|
23
|
+
|
24
|
+
world = World.new
|
25
|
+
#world.time_step = 0.01
|
26
|
+
|
27
|
+
ball_count = 10
|
28
|
+
balls = Array.new(ball_count) do |id|
|
29
|
+
world.create(Ball) do |ball|
|
30
|
+
ball.x = id * 10
|
31
|
+
ball.y = rand(450) + 100
|
32
|
+
ball.v = 0
|
33
|
+
ball.id = id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
## need --quiet option?
|
39
|
+
IO.popen("tkar --flip -v", "w") do |tkar|
|
40
|
+
# --flip means positive y is up
|
41
|
+
tkar.puts %{
|
42
|
+
title Bouncing ball
|
43
|
+
background gray95
|
44
|
+
height 600
|
45
|
+
width 600
|
46
|
+
bounds -300 0 300 600
|
47
|
+
shape ball oval-5,-5,5,5,fc:darkgreen,oc:red
|
48
|
+
shape ground line*0,0,*1,0,fc:purple,wi:4
|
49
|
+
add ground 10000 - 10 0 0 0 -300 300
|
50
|
+
view_at 0 540
|
51
|
+
}
|
52
|
+
balls.each do |ball|
|
53
|
+
tkar.puts %{
|
54
|
+
add ball #{ball.id} - 100 #{ball.x} #{ball.y} 0
|
55
|
+
}
|
56
|
+
end
|
57
|
+
tkar.flush
|
58
|
+
world.evolve 1000 do
|
59
|
+
balls.each do |ball|
|
60
|
+
tkar.puts "move #{ball.id} #{ball.x} #{ball.y}"
|
61
|
+
end
|
62
|
+
tkar.puts "update"
|
63
|
+
tkar.flush
|
64
|
+
#sleep 0.01
|
65
|
+
## need timer to make this realistic
|
66
|
+
end
|
67
|
+
puts "Press <enter> when done"
|
68
|
+
gets
|
69
|
+
end
|
70
|
+
rescue Errno::EPIPE, Interrupt
|
71
|
+
puts "Exited."
|
72
|
+
end
|