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
data/.bnsignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# The list of files that should be ignored by Mr Bones.
|
2
|
+
# Lines that start with '#' are comments.
|
3
|
+
#
|
4
|
+
# A .gitignore file can be used instead by setting it as the ignore
|
5
|
+
# file in your Rakefile:
|
6
|
+
#
|
7
|
+
# PROJ.ignore_file = '.gitignore'
|
8
|
+
#
|
9
|
+
# For a project with a C extension, the following would be a good set of
|
10
|
+
# exclude patterns (uncomment them if you want to use them):
|
11
|
+
# *.[oa]
|
12
|
+
# *~
|
13
|
+
announcement.txt
|
14
|
+
coverage
|
15
|
+
doc
|
16
|
+
pkg
|
17
|
+
*.bck
|
18
|
+
misc
|
19
|
+
junk
|
20
|
+
tmp
|
21
|
+
*/tmp
|
22
|
+
*/*/tmp
|
23
|
+
*/junk
|
data/.gitignore
CHANGED
data/README
CHANGED
@@ -1,5 +1,23 @@
|
|
1
|
-
|
1
|
+
= RedShift
|
2
|
+
|
3
|
+
A framework for simulation of networks of hybrid automata, similar to SHIFT and Lambda-SHIFT. Includes ruby-based DSL for defining simulation components, and ruby/C code generation and runtime.
|
4
|
+
|
5
|
+
There's no documentation yet. Start with the examples.
|
6
|
+
|
7
|
+
== Requirements
|
8
|
+
|
9
|
+
RedShift needs ruby 1.8.x and a compatible C compiler. If you can build native gems, you're all set.
|
10
|
+
|
11
|
+
== Env vars
|
12
|
+
|
13
|
+
If you have a multicore system and are using the gnu toolchain, set
|
14
|
+
|
15
|
+
REDSHIFT_MAKE_ARGS='-j -l2'
|
16
|
+
|
17
|
+
or some variation. You'll find that rebuilds of your simulation code go faster.
|
18
|
+
|
19
|
+
----
|
20
|
+
|
21
|
+
Copyright (C) 2001-2010, Joel VanderWerf, vjoel@users.sourceforge.net
|
22
|
+
Distributed under the Ruby license. See www.ruby-lang.org.
|
2
23
|
|
3
|
-
ruby install.rb config
|
4
|
-
ruby install.rb setup
|
5
|
-
ruby install.rb install
|
data/RELEASE-NOTES
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
redshift 1.3.18
|
2
|
+
|
3
|
+
- added robots example
|
4
|
+
|
5
|
+
- redshift builds isaac and buffer code at install time, rather than run time
|
6
|
+
|
7
|
+
- added isaac extension and reverted tests to use it again
|
8
|
+
|
9
|
+
- use REDSHIFT_MAKE_ARGS
|
10
|
+
|
11
|
+
- added -j2 switch to test
|
12
|
+
|
13
|
+
- added modular.rb for modular use of redshift DSL, and an example
|
14
|
+
|
15
|
+
- some rdoc improvements
|
16
|
+
|
1
17
|
redshift 1.3.17
|
2
18
|
|
3
19
|
- added shell example with plotting and tk animation
|
data/examples/lotka-volterra.rb
CHANGED
@@ -24,7 +24,7 @@ require 'redshift/util/plot'
|
|
24
24
|
include Plot::PlotUtils
|
25
25
|
|
26
26
|
gnuplot do |plot|
|
27
|
-
plot.command %{set title "
|
27
|
+
plot.command %{set title "Lotka-Volterra"}
|
28
28
|
plot.command %{set xlabel "time"}
|
29
29
|
plot.add data, %{using 1:2 title "foxes" with lines}
|
30
30
|
plot.add data, %{using 1:3 title "rabbits" with lines}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# This example shows how to define things in a module and include that in a
|
2
|
+
# Component or World class.
|
3
|
+
|
4
|
+
require 'redshift'
|
5
|
+
require 'redshift/util/modular'
|
6
|
+
|
7
|
+
module ThermoStuff
|
8
|
+
extend Modular
|
9
|
+
|
10
|
+
continuous :temp
|
11
|
+
|
12
|
+
state :Heat, :Off
|
13
|
+
|
14
|
+
flow :Heat do # Must quote constants, since they are defined later
|
15
|
+
diff "temp' = (68 - temp)/3"
|
16
|
+
end
|
17
|
+
|
18
|
+
flow :Off do
|
19
|
+
diff "temp' = (45 - temp)/10"
|
20
|
+
end
|
21
|
+
|
22
|
+
transition :Heat => :Off do
|
23
|
+
guard "temp > 68 - 0.1"
|
24
|
+
end
|
25
|
+
|
26
|
+
transition :Off => :Heat do
|
27
|
+
guard "temp < 66"
|
28
|
+
end
|
29
|
+
|
30
|
+
setup do
|
31
|
+
start :Off
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Thermostat < RedShift::Component
|
36
|
+
include ThermoStuff
|
37
|
+
|
38
|
+
default do
|
39
|
+
self.temp = 35
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
world = RedShift::World.new
|
44
|
+
thermostat = world.create Thermostat
|
45
|
+
|
46
|
+
world.evolve 30 do |w|
|
47
|
+
printf "%6.2f: %7.3f %s\n", w.clock, thermostat.temp, thermostat.state
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
= Robots
|
2
|
+
|
3
|
+
An example covering some of the basic language features plus some techniques for interactive simulation and for animating simulation output.
|
4
|
+
|
5
|
+
To run the example:
|
6
|
+
|
7
|
+
ruby robots.rb
|
8
|
+
|
9
|
+
Press ^C to break into a command shell, and then ^D to continue the simulation run. The "help" command in the shell shows you the commands beyond the basic irb.
|
10
|
+
|
11
|
+
Use -h from the command line to see the switches.
|
12
|
+
|
13
|
+
To change the setup of the world, edit robots.rb. You can add and move robots and missles.
|
14
|
+
|
15
|
+
You can also move the objects interactively in the Tk visualization.
|
16
|
+
|
17
|
+
Currently, the robots move around and the missles track and hit them.
|
18
|
+
|
19
|
+
= To do
|
20
|
+
|
21
|
+
== robots physics
|
22
|
+
|
23
|
+
- collision detection and effect on robot health
|
24
|
+
|
25
|
+
- walls and obstacles
|
26
|
+
|
27
|
+
== robot control
|
28
|
+
|
29
|
+
- command language to evade attackers and launch missiles based on radar
|
30
|
+
|
31
|
+
- maybe similar to RoboTalk (from RoboWar)
|
32
|
+
|
33
|
+
- multirobot coordination using comm channels
|
34
|
+
|
35
|
+
== game mechanics
|
36
|
+
|
37
|
+
- robot shop
|
38
|
+
|
39
|
+
- tournaments
|
40
|
+
|
41
|
+
== dev tools
|
42
|
+
|
43
|
+
- debugger
|
44
|
+
|
45
|
+
- plotter
|
46
|
+
|
47
|
+
== visualization
|
48
|
+
|
49
|
+
- for each sensor, show nearest robot by drawing arrow
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# This file encapsulates some relatively uninteresting tweaks and additions
|
2
|
+
# to make the demo go smoothly.
|
3
|
+
|
4
|
+
require 'redshift'
|
5
|
+
|
6
|
+
class RobotComponent < RedShift::Component
|
7
|
+
attr_accessor :name # for display; can be anything
|
8
|
+
attr_reader :id # for keeping track of tk objects; must be uniq int
|
9
|
+
|
10
|
+
default do
|
11
|
+
@id = world.next_id
|
12
|
+
@name = id
|
13
|
+
end
|
14
|
+
|
15
|
+
def tk_delete
|
16
|
+
"delete #{id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
state :Done
|
20
|
+
|
21
|
+
transition Done => Exit do
|
22
|
+
action do
|
23
|
+
world.exited << self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
require 'shell-world'
|
29
|
+
require 'robot'
|
30
|
+
|
31
|
+
class RobotWorld < RedShift::World
|
32
|
+
include ShellWorld
|
33
|
+
|
34
|
+
def show_status
|
35
|
+
grep(Robot) {|r| r.show_status}
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Explosion < RobotComponent
|
2
|
+
continuous :size, :max_size, :x, :y, :vx, :vy
|
3
|
+
continuous :t, :prev_t
|
4
|
+
|
5
|
+
setup do
|
6
|
+
self.t = self.prev_t = 0
|
7
|
+
end
|
8
|
+
|
9
|
+
state :Expanding
|
10
|
+
start Expanding
|
11
|
+
|
12
|
+
flow Expanding do
|
13
|
+
diff " x' = vx "
|
14
|
+
diff " y' = vy "
|
15
|
+
diff " size' = 10 * sqrt(size) "
|
16
|
+
diff " t' = 1 "
|
17
|
+
end
|
18
|
+
|
19
|
+
transition Expanding => Done do
|
20
|
+
guard " size > max_size "
|
21
|
+
end
|
22
|
+
|
23
|
+
transition Expanding => Expanding do
|
24
|
+
guard " t > prev_t "
|
25
|
+
action do
|
26
|
+
world.grep(Robot) do |r|
|
27
|
+
if (x - r.x)**2 + (y - r.y)**2 < size**2
|
28
|
+
r.messages <<
|
29
|
+
Robot::InflictDamage.new(10*(max_size - size)*(t - prev_t))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
reset :prev_t => "t"
|
34
|
+
end
|
35
|
+
|
36
|
+
def tk_add
|
37
|
+
"add explosion #{id} - 0 #{x} #{y} 0 #{size} #{-size}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# emit string representing current state
|
41
|
+
def tk_update
|
42
|
+
fade = ("%x" % ((size / max_size) * 256)) * 2
|
43
|
+
"moveto #{id} #{x} #{y}\n" +
|
44
|
+
"param #{id} 0 #{size}\n" +
|
45
|
+
"param #{id} 1 #{-size}\n" +
|
46
|
+
"param #{id} 2 0xFF#{fade}"
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Missile < RobotComponent
|
2
|
+
require 'explosion'
|
3
|
+
|
4
|
+
link :target => Robot
|
5
|
+
|
6
|
+
continuous :x, :y, :vx, :vy, :v, :heading, :power
|
7
|
+
constant :turn_rate
|
8
|
+
|
9
|
+
state :Seeking
|
10
|
+
start Seeking
|
11
|
+
|
12
|
+
default do
|
13
|
+
self.power = 40
|
14
|
+
self.v = 20
|
15
|
+
self.turn_rate = 60 * Math::PI / 180 # convert from degrees per sec
|
16
|
+
end
|
17
|
+
|
18
|
+
flow Seeking do
|
19
|
+
alg " vx = v * cos(heading) "
|
20
|
+
alg " vy = v * sin(heading) "
|
21
|
+
|
22
|
+
diff " x' = vx "
|
23
|
+
diff " y' = vy "
|
24
|
+
|
25
|
+
diff "power' = -1"
|
26
|
+
|
27
|
+
alg " distance =
|
28
|
+
sqrt(
|
29
|
+
pow(x - target.x, 2) +
|
30
|
+
pow(y - target.y, 2) ) "
|
31
|
+
|
32
|
+
alg " angle =
|
33
|
+
atan2(target.y - y,
|
34
|
+
target.x - x) "
|
35
|
+
|
36
|
+
alg " error = fmod(heading - angle, 2*#{Math::PI}) "
|
37
|
+
diff " heading' = turn_rate * (
|
38
|
+
error < #{-Math::PI/2} ?
|
39
|
+
#{-Math::PI/2} :
|
40
|
+
(error > #{Math::PI/2} ?
|
41
|
+
#{Math::PI/2} : -error)) "
|
42
|
+
end
|
43
|
+
|
44
|
+
transition Seeking => Done do
|
45
|
+
guard "power < 0"
|
46
|
+
end
|
47
|
+
|
48
|
+
transition Seeking => Done do
|
49
|
+
guard "distance < 1"
|
50
|
+
action do
|
51
|
+
unless target.state == Exit
|
52
|
+
create Explosion do |e|
|
53
|
+
e.size = 1
|
54
|
+
e.max_size = power
|
55
|
+
e.x = x
|
56
|
+
e.y = y
|
57
|
+
e.vx = vx
|
58
|
+
e.vy = vy
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# return string that adds an instance of the shape with label t.name,
|
65
|
+
# position based on (x, y), and rotation based on heading
|
66
|
+
def tk_add
|
67
|
+
"add missile #{id} - 11 #{x} #{y} #{heading}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# emit string representing current state
|
71
|
+
def tk_update
|
72
|
+
"moveto #{id} #{x} #{y}\n" +
|
73
|
+
"rot #{id} #{heading}"
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'tracker'
|
2
|
+
|
3
|
+
class Radar < RobotComponent
|
4
|
+
constant :period => 0.200
|
5
|
+
continuous :t
|
6
|
+
continuous :distance
|
7
|
+
continuous :angle
|
8
|
+
attr_accessor :host_robot, :nearest_robot
|
9
|
+
link :nearest_tracker => Tracker
|
10
|
+
|
11
|
+
attr_accessor :trackers
|
12
|
+
default do
|
13
|
+
self.trackers = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# add +robots+ to the list of objects tracked by this radar
|
17
|
+
def track_robots *robots
|
18
|
+
robots.flatten.each do |robot|
|
19
|
+
tracker = create Tracker
|
20
|
+
tracker.host = host_robot
|
21
|
+
tracker.target = robot
|
22
|
+
trackers << tracker
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
state :Sleep, :Measure
|
27
|
+
start Sleep
|
28
|
+
|
29
|
+
flow Sleep do
|
30
|
+
diff " t' = -1 "
|
31
|
+
end
|
32
|
+
|
33
|
+
flow Sleep, Measure do
|
34
|
+
alg " angle_deg = fmod(angle * #{180/Math::PI}, 360)"
|
35
|
+
end
|
36
|
+
|
37
|
+
transition Sleep => Measure do
|
38
|
+
guard " t <= 0 "
|
39
|
+
action do
|
40
|
+
scan_for_nearest_robot
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
transition Measure => Sleep do
|
45
|
+
reset :t => "period"
|
46
|
+
end
|
47
|
+
|
48
|
+
def scan_for_nearest_robot
|
49
|
+
self.nearest_tracker = trackers.min_by {|tracker| tracker.distance}
|
50
|
+
if nearest_tracker
|
51
|
+
self.nearest_robot = nearest_tracker.target ## how to delay this?
|
52
|
+
self.distance = nearest_tracker.distance
|
53
|
+
self.angle = nearest_tracker.angle
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
class Robot < RobotComponent
|
2
|
+
require 'radar'
|
3
|
+
require 'explosion'
|
4
|
+
require 'missile'
|
5
|
+
|
6
|
+
continuous :x, :y, :vx, :vy, :v, :heading, :power, :health
|
7
|
+
link :radar => :Radar
|
8
|
+
|
9
|
+
InflictDamage = Struct.new(:value)
|
10
|
+
queue :messages
|
11
|
+
|
12
|
+
default do
|
13
|
+
self.radar = create Radar
|
14
|
+
radar.host_robot = self
|
15
|
+
|
16
|
+
self.power = 100
|
17
|
+
self.health = 100
|
18
|
+
end
|
19
|
+
|
20
|
+
state :Stopped, :Rolling, :Exploding
|
21
|
+
start :Rolling
|
22
|
+
|
23
|
+
flow Stopped, Rolling do
|
24
|
+
alg " vx = v * cos(heading) "
|
25
|
+
alg " vy = v * sin(heading) "
|
26
|
+
|
27
|
+
alg " heading_deg = fmod(heading * #{180/Math::PI}, 360)"
|
28
|
+
|
29
|
+
diff " x' = vx "
|
30
|
+
diff " y' = vy "
|
31
|
+
|
32
|
+
# a bit of friction, i.e. deceleration proportional to velocity
|
33
|
+
diff " v' = -0.01 * v"
|
34
|
+
end
|
35
|
+
|
36
|
+
flow Rolling do
|
37
|
+
# it takes power to maintain speed
|
38
|
+
diff " power' = -1 "
|
39
|
+
end
|
40
|
+
|
41
|
+
transition Rolling => Stopped do
|
42
|
+
guard " power <= 0 "
|
43
|
+
end
|
44
|
+
|
45
|
+
transition Rolling => Exploding, Stopped => Exploding do
|
46
|
+
guard " health <= 0 "
|
47
|
+
action do
|
48
|
+
create Explosion do |e|
|
49
|
+
e.size = 1
|
50
|
+
e.max_size = 60
|
51
|
+
e.x = x
|
52
|
+
e.y = y
|
53
|
+
e.vx = vx
|
54
|
+
e.vy = vy
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
transition Exploding => Done
|
60
|
+
|
61
|
+
transition Rolling => Rolling, Stopped => Stopped do
|
62
|
+
wait :messages => InflictDamage
|
63
|
+
action do
|
64
|
+
m = messages.pop
|
65
|
+
case m
|
66
|
+
when RedShift::SimultaneousQueueEntries
|
67
|
+
dmg_msgs, other = m.partition {|n| InflictDamage === n}
|
68
|
+
messages.unpop other
|
69
|
+
dmg_msgs.each do |n|
|
70
|
+
self.health -= n.value
|
71
|
+
end
|
72
|
+
else
|
73
|
+
self.health -= m.value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# return string that adds an instance of the shape with label t.name,
|
79
|
+
# position based on (x, y), and rotation based on heading
|
80
|
+
def tk_add
|
81
|
+
"add robot #{id} - 10 #{x} #{y} #{heading}\n" +
|
82
|
+
"param #{id} 0 #{name}\n" +
|
83
|
+
"param #{id} 1 359\n" +
|
84
|
+
"param #{id} 2 359"
|
85
|
+
end
|
86
|
+
|
87
|
+
# emit string representing current state
|
88
|
+
def tk_update
|
89
|
+
e = (power / 100.0) * 359.9
|
90
|
+
h = (health / 100.0) * 359.9
|
91
|
+
"moveto #{id} #{x} #{y}\n" +
|
92
|
+
"rot #{id} #{heading}\n" +
|
93
|
+
"param #{id} 1 #{e}\n" +
|
94
|
+
"param #{id} 2 #{h}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def show_status
|
98
|
+
printf \
|
99
|
+
"%5.3f sec: closest blip is %s, at %8.3f meters, bearing %3d degrees\n",
|
100
|
+
world.clock,
|
101
|
+
radar.nearest_robot ? radar.nearest_robot.name : "none",
|
102
|
+
radar.distance,
|
103
|
+
(radar.angle * 180/Math::PI).round.abs
|
104
|
+
end
|
105
|
+
end
|