redshift 1.3.17 → 1.3.18
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/.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
|
+
}
|