Configuration
The beginning model for this example walkthrough of Point and Shoot has three actions: two stimuli and a response, declared in the following Cord configuration (from file Config.cord):
config MovementActions
{
action static void SailboatController.Sail(Heading heading,int hours,int knots);
action event static void SailboatController.RunAground(int atx, int aty);
action static void SailboatController.Rescue();
// ... configuration switches ...
}
The most important stimulus is Sail
, which commands the sailboat to move in a certain direction, at a certain speed, for a certain time. The RunAground
response is emitted by the sailboat if it hits the lake shore as a result of the last Sail
call. After this, the sailboat can no longer sail until it receives a Rescue
stimulus, which transports it to the starting location and restores its sailing capacity.
Sail
uses an enumerated type from the SUT implementation to represent possible headings. It maps each heading to a corresponding angle, in degrees, with respect to the east-west direction. The Heading
enumeration is shown in the following code example (from file Implementation.cs
).
public enum Heading
{
N = 90,
S = 270,
E = 0,
W = 180,
NE = 45,
NW = 135,
SE = 315,
SW = 225
}
A static class is used in the model program. Its state consists of the position of the sailboat and a flag indicated if the boat has run aground, as shown in the following model code example (from file Model.cs
).
namespace Sailboat.Model
{
public static class SailboatModel
{
static int x, y;
static bool runAground = false;
static bool agroundFired = false;
// ... Other Model Program Code (described in the following)
}
}
Sail
is modeled in a single rule method. Its enabling conditions require that the sailboat has not already run aground and that the time and speed parameters have positive values, as shown in the following example code (from file Model.cs
).
[Rule]
static void Sail(Heading heading, int hours, int knots)
{
// Because the Math functions will influence the parameter generation functions,
// the parameters are explicitly expanded here to preclude that influence.
Combination.Expand(heading, hours, knots);
Condition.IsTrue(!runAground);
Condition.IsTrue(hours > 0);
Condition.IsTrue(knots > 0);
int miles = knots * hours;
double radians = ((int) heading * Math.PI / 180);
x += (int) Math.Round(miles * Math.Cos(radians));
y += (int) Math.Round(miles * Math.Sin(radians));
if (x < 0)
{
runAground = true;
x = 0;
}
else if (x > 1000)
{
runAground = true;
x = 1000;
}
if (y < 0)
{
runAground = true;
y = 0;
}
else if (y > 1000)
{
runAground = true;
y = 1000;
}
}
Position updates are calculated with a polar-to-rectangular conversion algorithm and rounded to the closest integer.
The Sail
rule contains logic that effectively defines the size and shape of the lake by setting the runAground
flag to be true if the position is negative or beyond 1000, either in latitude or in longitude.
The following example code (from file Model.cs
) defines rules for the remaining actions.
[Rule]
static void RunAground(int atx, int aty)
{
Condition.IsTrue(runAground);
Condition.IsTrue(!agroundFired);
Condition.IsTrue(atx == x);
Condition.IsTrue(aty == y);
agroundFired = true;
}
[Rule]
static void Rescue()
{
Condition.IsTrue(runAground);
Condition.IsTrue(agroundFired);
x = y = 0;
runAground = false;
agroundFired = false;
}
RunAground
sets agroundFired
flag to true when the sailboat hits a lake shore, so its enabling conditions require it to be currently aground and for agroundFired
not to have been set previously. Without the second condition, the event would keep firing indefinitely once the sailboat runs aground. The only effect of this rule is to set agroundFired
to true
.
Rescue
can be performed only if the sailboat is already aground and agroundFired
has been set. It resets its position to the initial location and re-enables Sail
by setting runAground
and agroundFired
to false.
Remember that our accepting state condition requires the sailboat to be at the point of origin, as shown in the following example code (from file Model.cs
).
[AcceptingStateCondition]
static bool InitialPosition()
{
return x == 0 && y == 0;
}