redshift 1.3.17 → 1.3.18
Sign up to get free protection for your applications and to get access to all the features.
- data/.bnsignore +23 -0
- data/.gitignore +7 -6
- data/README +22 -4
- data/RELEASE-NOTES +16 -0
- data/examples/lotka-volterra.rb +1 -1
- data/examples/modular-component-def.rb +49 -0
- data/examples/robots/README +49 -0
- data/examples/robots/lib/base.rb +38 -0
- data/examples/robots/lib/explosion.rb +48 -0
- data/examples/robots/lib/missile.rb +75 -0
- data/examples/robots/lib/radar.rb +56 -0
- data/examples/robots/lib/robot.rb +105 -0
- data/examples/robots/lib/shell-world.rb +167 -0
- data/examples/robots/lib/tracker.rb +16 -0
- data/examples/robots/robots.rb +53 -0
- data/examples/shell.rb +1 -2
- data/ext/redshift/buffer/buffer.c +102 -0
- data/ext/redshift/buffer/buffer.h +17 -0
- data/ext/redshift/buffer/dir.rb +1 -0
- data/ext/redshift/buffer/extconf.rb +2 -0
- data/ext/redshift/util/isaac/extconf.rb +2 -0
- data/ext/redshift/util/isaac/isaac.c +129 -0
- data/ext/redshift/util/isaac/rand.c +140 -0
- data/ext/redshift/util/isaac/rand.h +61 -0
- data/lib/redshift/mixins/shell.rb +72 -0
- data/lib/redshift/redshift.rb +1 -1
- data/lib/redshift/syntax.rb +12 -5
- data/lib/redshift/target/c/component-gen.rb +11 -8
- data/lib/redshift/target/c/flow/buffer.rb +17 -126
- data/lib/redshift/target/c/flow/delay.rb +5 -5
- data/lib/redshift/target/c/library.rb +12 -1
- data/lib/redshift/util/histogram.rb +1 -1
- data/lib/redshift/util/irb-shell.rb +81 -0
- data/lib/redshift/util/isaac.rb +22 -0
- data/lib/redshift/util/modular.rb +48 -0
- data/lib/redshift/util/tkar-driver.rb +1 -2
- data/lib/redshift/util/tracer/var.rb +1 -1
- data/lib/redshift/world.rb +9 -3
- data/rakefile +9 -1
- data/test/test.rb +23 -9
- data/test/test_buffer.rb +1 -1
- data/test/test_flow_trans.rb +3 -20
- metadata +50 -46
- data/lib/redshift/mixins/irb-shell.rb +0 -151
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'redshift/mixins/shell'
|
2
|
+
require 'redshift/util/plot'
|
3
|
+
|
4
|
+
# Adds an interactive ruby shell with plotting and animation commands.
|
5
|
+
module ShellWorld
|
6
|
+
include RedShift::Shell
|
7
|
+
|
8
|
+
def entered
|
9
|
+
@entered ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def exited
|
13
|
+
@exited ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def main_loop_with_shell_and_tk(argv=[])
|
17
|
+
if argv.delete "-h"
|
18
|
+
puts <<-END
|
19
|
+
|
20
|
+
-s start in shell
|
21
|
+
(otherwise, run until ^C breaks into shell)
|
22
|
+
|
23
|
+
-t start with tk animation
|
24
|
+
(otherwise, run without tk until the "tk" command)
|
25
|
+
|
26
|
+
END
|
27
|
+
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
|
31
|
+
puts "^C to break into shell; 'help' for shell help"
|
32
|
+
tk if argv.delete "-t"
|
33
|
+
shell.run if argv.delete "-s"
|
34
|
+
|
35
|
+
loop do
|
36
|
+
evolve 100000000 do
|
37
|
+
puts "clock: #{clock}"
|
38
|
+
#sleep 0.01
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def help
|
44
|
+
puts <<-END
|
45
|
+
The current object is #{self.inspect}. Some commands:
|
46
|
+
|
47
|
+
q -- quit
|
48
|
+
sh! -- enter a system command shell
|
49
|
+
run N -- run quickly for N time steps (integer)
|
50
|
+
evolve T -- run quickly for T seconds (float)
|
51
|
+
tk -- turn on Tk window (-t on command line to start this way)
|
52
|
+
tk false -- turn off Tk window
|
53
|
+
|
54
|
+
Local vars persist between interrupts.
|
55
|
+
Continue slow execution by pressing Ctrl-D (maybe Ctrl-Z on windows).
|
56
|
+
Press Ctrl-C again to break into the shell. Use -s on command line
|
57
|
+
to start in shell.
|
58
|
+
END
|
59
|
+
end
|
60
|
+
|
61
|
+
def sh!
|
62
|
+
system ENV['SHELL'] || default_shell
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_shell
|
66
|
+
puts "No SHELL environment variable, trying /bin/bash"
|
67
|
+
"/bin/bash"
|
68
|
+
end
|
69
|
+
|
70
|
+
def next_id
|
71
|
+
@next_id ||= 1
|
72
|
+
@next_id += 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def create(*)
|
76
|
+
c = super
|
77
|
+
entered << c
|
78
|
+
c
|
79
|
+
end
|
80
|
+
|
81
|
+
def before_shell
|
82
|
+
@tkar.catch_up_within 0 if @tkar
|
83
|
+
puts "\nStopped #{self.inspect}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def after_shell
|
87
|
+
@tkar.catch_up_within 0 if @tkar
|
88
|
+
puts "\nRunning #{self.inspect}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def dragger id, x, y
|
92
|
+
c = find {|c| c.id == id}
|
93
|
+
c.x, c.y = x, y
|
94
|
+
end
|
95
|
+
|
96
|
+
def tk turn_on = true
|
97
|
+
require 'redshift/util/tkar-driver'
|
98
|
+
if turn_on
|
99
|
+
if not @tkar or @tkar.closed?
|
100
|
+
@tkar = TkarDriver.new(method :dragger) do |pipe|
|
101
|
+
pipe.puts <<-END
|
102
|
+
title Robot World
|
103
|
+
background gray95
|
104
|
+
height 600
|
105
|
+
width 600
|
106
|
+
view_at -50 -20
|
107
|
+
zoom_to 4
|
108
|
+
|
109
|
+
shape cone \ arc5,0,10,10,fc:yellow,oc:black,extent:30,start:165,style:pieslice \
|
110
|
+
text2,2,anchor:c,justify:center,width:100,text:*0,fc:blue
|
111
|
+
|
112
|
+
shape robot cone*0 \
|
113
|
+
arc5,5,2,2,fc:green,oc:green,extent:*1,start:0,style:pieslice \
|
114
|
+
arc5,-5,2,2,fc:red,oc:red,extent:*2,start:0,style:pieslice
|
115
|
+
|
116
|
+
shape circle oval*0,*0,*1,*1,oc:red
|
117
|
+
shape explosion oval*0,*0,*1,*1,oc:*2,fc:*2
|
118
|
+
shape missile \
|
119
|
+
arc2,0,4,4,fc:red,oc:black,extent:20,start:170,style:pieslice
|
120
|
+
|
121
|
+
END
|
122
|
+
## the view_at seems to be needed to overcome a little
|
123
|
+
## centering bug in tkar
|
124
|
+
|
125
|
+
each do |component|
|
126
|
+
pipe.puts component.tk_add if defined?(component.tk_add)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
tk_update
|
131
|
+
end
|
132
|
+
|
133
|
+
elsif not turn_on and @tkar
|
134
|
+
@tkar.close
|
135
|
+
@tkar = nil
|
136
|
+
end
|
137
|
+
@tkar
|
138
|
+
end
|
139
|
+
|
140
|
+
def tk_update
|
141
|
+
if @tkar and
|
142
|
+
(entered.size > 0 or exited.size > 0 or (clock % 0.1).abs < 0.01)
|
143
|
+
@tkar.update do |pipe|
|
144
|
+
entered.each do |component|
|
145
|
+
pipe.puts component.tk_add if defined?(component.tk_add)
|
146
|
+
end
|
147
|
+
|
148
|
+
each do |component|
|
149
|
+
pipe.puts component.tk_update if defined?(component.tk_update)
|
150
|
+
end
|
151
|
+
|
152
|
+
exited.each do |component|
|
153
|
+
pipe.puts component.tk_delete if defined?(component.tk_delete)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def run(*)
|
160
|
+
super do
|
161
|
+
tk_update
|
162
|
+
entered.clear
|
163
|
+
exited.clear
|
164
|
+
yield self if block_given?
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# computes true distance and bearing angle to a single target,
|
2
|
+
# but won't scale up very well
|
3
|
+
class Tracker < RobotComponent
|
4
|
+
link :host => Robot
|
5
|
+
link :target => Robot
|
6
|
+
|
7
|
+
flow do
|
8
|
+
alg " distance =
|
9
|
+
sqrt(
|
10
|
+
pow(host.x - target.x, 2) +
|
11
|
+
pow(host.y - target.y, 2) ) "
|
12
|
+
alg " angle =
|
13
|
+
atan2(target.y - host.y,
|
14
|
+
target.x - host.x) "
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
require 'base'
|
3
|
+
|
4
|
+
world = RobotWorld.new
|
5
|
+
world.time_step = 0.01
|
6
|
+
|
7
|
+
r1 = world.create Robot do |r|
|
8
|
+
r.name = "robot 1"
|
9
|
+
r.x = 0
|
10
|
+
r.y = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
r2 = world.create Robot do |r|
|
14
|
+
r.name = "robot 2"
|
15
|
+
r.x = -50
|
16
|
+
r.y = 0
|
17
|
+
r.heading = 0.1 * Math::PI
|
18
|
+
r.v = 10
|
19
|
+
end
|
20
|
+
|
21
|
+
r3 = world.create Robot do |r|
|
22
|
+
r.name = "robot 3"
|
23
|
+
r.x = 70
|
24
|
+
r.y = 10
|
25
|
+
r.heading = -0.9 * Math::PI
|
26
|
+
r.v = 5
|
27
|
+
end
|
28
|
+
|
29
|
+
30.times do |i|
|
30
|
+
world.create Missile do |m|
|
31
|
+
m.x = -40
|
32
|
+
m.y = 40 + i*2
|
33
|
+
m.v = 20 - (i%10)
|
34
|
+
m.target = r2
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
20.times do |i|
|
39
|
+
world.create Missile do |m|
|
40
|
+
m.x = -30
|
41
|
+
m.y = 40 + i*2
|
42
|
+
m.v = 20 - (i%10)
|
43
|
+
m.heading = i / 20
|
44
|
+
m.target = r3
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
robots = world.grep(Robot)
|
49
|
+
robots.each do |r|
|
50
|
+
r.radar.track_robots robots - [r]
|
51
|
+
end
|
52
|
+
|
53
|
+
world.main_loop_with_shell_and_tk(ARGV)
|
data/examples/shell.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# Shows how to use a customized IRB shell to handle Ctrl-C interrupts
|
2
2
|
|
3
3
|
require 'redshift'
|
4
|
-
require 'redshift/mixins/irb-shell'
|
5
4
|
include RedShift
|
6
5
|
|
7
6
|
require 'redshift/util/plot'
|
@@ -9,7 +8,7 @@ include Plot::PlotUtils
|
|
9
8
|
|
10
9
|
# Adds an interactive ruby shell with plotting and animation commands.
|
11
10
|
module ShellWorld
|
12
|
-
include RedShift::
|
11
|
+
include RedShift::World::Shell
|
13
12
|
|
14
13
|
def help
|
15
14
|
puts <<-END
|
@@ -0,0 +1,102 @@
|
|
1
|
+
#include "buffer.h"
|
2
|
+
|
3
|
+
void rs_buffer_init(RSBuffer *buf, long len, double fill)
|
4
|
+
{
|
5
|
+
int i;
|
6
|
+
buf->ptr = ALLOC_N(double, len);
|
7
|
+
buf->len = len;
|
8
|
+
buf->offset = 0;
|
9
|
+
for (i=0; i<len; i++) {
|
10
|
+
buf->ptr[i] = fill;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
void rs_buffer_resize(RSBuffer *buf, long len)
|
15
|
+
{
|
16
|
+
long i;
|
17
|
+
long old_len = buf->len;
|
18
|
+
long offset = buf->offset;
|
19
|
+
double *ptr = buf->ptr;
|
20
|
+
double *dst, *src;
|
21
|
+
double fill;
|
22
|
+
|
23
|
+
if (len < old_len) {
|
24
|
+
if (offset < len) {
|
25
|
+
dst = ptr + offset;
|
26
|
+
src = ptr + offset + old_len - len;
|
27
|
+
memmove(dst, src, (len - offset) * sizeof(double));
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
dst = ptr;
|
31
|
+
src = ptr + offset - len;
|
32
|
+
offset = 0;
|
33
|
+
memmove(dst, src, len * sizeof(double));
|
34
|
+
}
|
35
|
+
REALLOC_N(ptr, double, len);
|
36
|
+
// ## maybe better: don't release space, just use less of it
|
37
|
+
}
|
38
|
+
else if (len > old_len) {
|
39
|
+
REALLOC_N(ptr, double, len);
|
40
|
+
|
41
|
+
fill = ptr[offset];
|
42
|
+
dst = ptr + offset + len - old_len;
|
43
|
+
src = ptr + offset;
|
44
|
+
memmove(dst, src, (old_len - offset) * sizeof(double));
|
45
|
+
|
46
|
+
for (i = 0; i < len - old_len; i++) {
|
47
|
+
ptr[offset + i] = fill;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
else
|
51
|
+
return;
|
52
|
+
|
53
|
+
buf->len = len;
|
54
|
+
buf->offset = offset;
|
55
|
+
buf->ptr = ptr;
|
56
|
+
}
|
57
|
+
|
58
|
+
void rs_buffer_inhale_array(RSBuffer *buf, VALUE ary)
|
59
|
+
{
|
60
|
+
int size, i;
|
61
|
+
|
62
|
+
Check_Type(ary, T_ARRAY);
|
63
|
+
|
64
|
+
size = RARRAY_LEN(ary);
|
65
|
+
if (buf->ptr) {
|
66
|
+
REALLOC_N(buf->ptr, double, size);
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
buf->ptr = ALLOC_N(double, size);
|
70
|
+
}
|
71
|
+
buf->len = size;
|
72
|
+
buf->offset = 0;
|
73
|
+
|
74
|
+
for (i = 0; i < size; i++) {
|
75
|
+
buf->ptr[i] = NUM2DBL(RARRAY_PTR(ary)[i]);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
VALUE rs_buffer_exhale_array(RSBuffer *buf)
|
80
|
+
{
|
81
|
+
VALUE ary;
|
82
|
+
int i;
|
83
|
+
int j;
|
84
|
+
int size;
|
85
|
+
|
86
|
+
size = buf->len;
|
87
|
+
ary = rb_ary_new2(size);
|
88
|
+
RARRAY_LEN(ary) = size;
|
89
|
+
for (i = buf->offset, j=0; i < size; i++, j++) {
|
90
|
+
RARRAY_PTR(ary)[j] = rb_float_new(buf->ptr[i]);
|
91
|
+
}
|
92
|
+
for (i = 0; i < buf->offset; i++, j++) {
|
93
|
+
RARRAY_PTR(ary)[j] = rb_float_new(buf->ptr[i]);
|
94
|
+
}
|
95
|
+
|
96
|
+
return ary;
|
97
|
+
}
|
98
|
+
|
99
|
+
void
|
100
|
+
Init_buffer()
|
101
|
+
{
|
102
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef buffer_h
|
2
|
+
#define buffer_h
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
|
6
|
+
typedef struct {
|
7
|
+
long len;
|
8
|
+
long offset;
|
9
|
+
double *ptr;
|
10
|
+
} RSBuffer;
|
11
|
+
|
12
|
+
void rs_buffer_init(RSBuffer *buf, long len, double fill);
|
13
|
+
void rs_buffer_resize(RSBuffer *buf, long len);
|
14
|
+
void rs_buffer_inhale_array(RSBuffer *buf, VALUE ary);
|
15
|
+
VALUE rs_buffer_exhale_array(RSBuffer *buf);
|
16
|
+
|
17
|
+
#endif
|
@@ -0,0 +1 @@
|
|
1
|
+
REDSHIFT_BUFFER_DIR = File.dirname(File.expand_path(__FILE__))
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "rand.h"
|
3
|
+
|
4
|
+
#ifndef min
|
5
|
+
# define min(a,b) (((a)<(b)) ? (a) : (b))
|
6
|
+
#endif /* min */
|
7
|
+
|
8
|
+
static VALUE
|
9
|
+
ISAAC_s_allocate(VALUE klass)
|
10
|
+
{
|
11
|
+
randctx *ctx;
|
12
|
+
|
13
|
+
return Data_Make_Struct(klass, randctx, NULL, NULL, ctx);
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Seed the generator with an array of up to ISAAC::RANDSIZ integers in the
|
18
|
+
* range 0..2**32-1. More entries are ignored. Missing entries are treated
|
19
|
+
* as 0. Returns +nil+.
|
20
|
+
*/
|
21
|
+
static VALUE
|
22
|
+
ISAAC_srand(VALUE self, VALUE ary)
|
23
|
+
{
|
24
|
+
int i;
|
25
|
+
randctx *ctx;
|
26
|
+
|
27
|
+
Check_Type(ary, T_ARRAY);
|
28
|
+
|
29
|
+
Data_Get_Struct(self, randctx, ctx);
|
30
|
+
|
31
|
+
MEMZERO(ctx, randctx, 1);
|
32
|
+
for (i=min(RANDSIZ, RARRAY_LEN(ary))-1; i>=0; i--) {
|
33
|
+
ctx->randrsl[i] = NUM2UINT(RARRAY_PTR(ary)[i]);
|
34
|
+
}
|
35
|
+
rs_isaac_init(ctx, 1);
|
36
|
+
|
37
|
+
return Qnil;
|
38
|
+
}
|
39
|
+
|
40
|
+
/*
|
41
|
+
* Return a random integer in the range 0..2**32-1.
|
42
|
+
*/
|
43
|
+
static VALUE
|
44
|
+
ISAAC_rand32(VALUE self)
|
45
|
+
{
|
46
|
+
randctx *ctx;
|
47
|
+
|
48
|
+
Data_Get_Struct(self, randctx, ctx);
|
49
|
+
|
50
|
+
if (!ctx->randcnt--) {
|
51
|
+
rs_isaac_rand(ctx);
|
52
|
+
ctx->randcnt=RANDSIZ-1;
|
53
|
+
}
|
54
|
+
|
55
|
+
return UINT2NUM(ctx->randrsl[ctx->randcnt]);
|
56
|
+
}
|
57
|
+
|
58
|
+
/*
|
59
|
+
* Return a random float in the range 0..1.
|
60
|
+
*/
|
61
|
+
static VALUE
|
62
|
+
ISAAC_rand(VALUE self)
|
63
|
+
{
|
64
|
+
randctx *ctx;
|
65
|
+
|
66
|
+
Data_Get_Struct(self, randctx, ctx);
|
67
|
+
|
68
|
+
if (!ctx->randcnt--) {
|
69
|
+
rs_isaac_rand(ctx);
|
70
|
+
ctx->randcnt=RANDSIZ-1;
|
71
|
+
}
|
72
|
+
|
73
|
+
return rb_float_new(ctx->randrsl[ctx->randcnt] / 4294967295.0);
|
74
|
+
}
|
75
|
+
|
76
|
+
/* :nodoc: */
|
77
|
+
static VALUE
|
78
|
+
ISAAC_marshal_dump(VALUE self)
|
79
|
+
{
|
80
|
+
randctx *ctx;
|
81
|
+
int i;
|
82
|
+
int ary_size = sizeof(randctx)/sizeof(ub4);
|
83
|
+
VALUE ary;
|
84
|
+
|
85
|
+
Data_Get_Struct(self, randctx, ctx);
|
86
|
+
|
87
|
+
ary = rb_ary_new2(ary_size);
|
88
|
+
for (i = 0; i < ary_size; i++) {
|
89
|
+
rb_ary_push(ary, UINT2NUM(((ub4 *)ctx)[i]));
|
90
|
+
}
|
91
|
+
|
92
|
+
return ary;
|
93
|
+
}
|
94
|
+
|
95
|
+
/* :nodoc: */
|
96
|
+
static VALUE
|
97
|
+
ISAAC_marshal_load(VALUE self, VALUE ary)
|
98
|
+
{
|
99
|
+
randctx *ctx;
|
100
|
+
int i;
|
101
|
+
int ary_size = sizeof(randctx)/sizeof(ub4);
|
102
|
+
|
103
|
+
Data_Get_Struct(self, randctx, ctx);
|
104
|
+
|
105
|
+
if (RARRAY_LEN(ary) != ary_size)
|
106
|
+
rb_raise(rb_eArgError, "bad length in loaded ISAAC data");
|
107
|
+
|
108
|
+
for (i = 0; i < ary_size; i++) {
|
109
|
+
((ub4 *)ctx)[i] = NUM2UINT(RARRAY_PTR(ary)[i]);
|
110
|
+
}
|
111
|
+
|
112
|
+
return self;
|
113
|
+
}
|
114
|
+
|
115
|
+
void
|
116
|
+
Init_isaac()
|
117
|
+
{
|
118
|
+
VALUE ISAAC;
|
119
|
+
|
120
|
+
ISAAC = rb_define_class("ISAAC", rb_cObject);
|
121
|
+
rb_define_alloc_func(ISAAC, ISAAC_s_allocate);
|
122
|
+
rb_define_method(ISAAC, "srand", ISAAC_srand, 1);
|
123
|
+
rb_define_method(ISAAC, "rand32", ISAAC_rand32, 0);
|
124
|
+
rb_define_method(ISAAC, "rand", ISAAC_rand, 0);
|
125
|
+
rb_define_method(ISAAC, "marshal_dump", ISAAC_marshal_dump, 0);
|
126
|
+
rb_define_method(ISAAC, "marshal_load", ISAAC_marshal_load, 1);
|
127
|
+
|
128
|
+
rb_const_set(ISAAC, rb_intern("RANDSIZ"), UINT2NUM(RANDSIZ));
|
129
|
+
}
|