Calculations
Wizardry and Steamworks
&
BIO-SE
Carbon Credits Simulator
Field Area
d
Mouse Area |-----|
_ - *****
*_| 1m | *****
|_| d | *****
| *****
1m - *****
A(*) A(B)
s scalar(d) * d
v= - => v = -------------
t t
Mouse visits all the locations
on the field in time t. We assume
that all locations contain plants
and that, initially, the surface
of the plant is equal to the
surface of the mouse.
A plant grows every 3600s. It has
to grow 4 times to reach full maturity.
Thus, a plant reaches maturity after:
M(P) = 4 * 3600s = 14400s
Hence, HAS to take at LEAST 14400s
to visit all the locations on the field
in order to give any plant the chance
to reach full maturity.
Thus, the speed that the mouse should
move at is given by:
scalar(d) * d
(1) v = -------------
14400s
We know that the top speed of the mouse
is approximately 3.6(1)m/s. However the
mice will not always run at their top
speed.
On average we select the midpoint as
being the average speed:
V(mouse) = 1.8m/s
Substituting, we obtain how large the area
of the field must be so that a mouse
moving at the average speed of 1.8m/s
will cover the entire area of the field
as well as giving an arbitrary plant a
chance to reach full maturity:
scalar(d) * d = 1.8m/s * 14400s
Favorably, taking the geometry of the field
as being a square, we can obtain the
length length of one of the side of
the field:
---------------
d = / V(mouse) * t ~= 160.996m
v
Which represents the MAXIMAL length of the
side of the square so that an arbitrary
plant gets a chance to reach maturity.
That is because the model assumes that a
mouse will visit a new location every time
the mouse moves.
Coming back to the field of plants:
* * * * *
* * * * *
* * * * * 1
P(*) = ----------
* * * * * N pts
And given an uniform selection of points
every point where a plant can be found
stands an equal chance to be selected on
the next draw.
When the mouse visits that point, it eats
the plant so that point becomes visited.
d
|---------|_
* * * * * |
|
* * * * * |
| d
* * * * * |
Consumed |
---------> * * * * -
We know that the total number of valid nodes
is:
(2) N(nodes) = d^2
In order to draw a particular point from the
field we need N/N trials. To draw another
unique point we need N/(N-1) trials.
Generalizing the total number of trials before
the field has been entirely sweeped using the
uniform selection of points is given by:
(3) TT = N(nodes) * H(N(nodes))
where H is the harmonic series from 1 to N
points on the field:
N
+-----
\ 1 1 1
H(N)= + - = 1 + ----- + ------ + ...
/ n (i+1) (i+2)
+-----
i=1
Example 1
That means that given the length d of the
square field, we can calculate how many
trials are needed (a mouse travelling from
point to point) before the entire field
has been swept of plants.
(2) N(nodes)= d^2
(3) TT = N(nodes) * H(N(nodes))
By choosing the length of the side of the
square d, we obtain the number of points
the mouse will visit on the field before
we can be sure that the whole field has
been swept of plants.
Example 2
We can calculate the average velocity of
the mouse so that an arbitrary plant will
be given the chance to reach maturity
before it is eaten by a traveling mouse.
scalar(d) * d
V = -------------
t
where t is the time a plant takes to reach
full maturity and d is length of the side
of the square field.
Example 3
As a completion to Example 1, given a square
field with the legnth of the side of the
square d and a plant placed arbitrarily on
the field, we can calculate the probability
if that plant to be eaten by the mouse
1
P(*) = -----
N
N = d^2
As we can see from our numeric calculations
the length of the side of the square
should AT LEAST be 138.821m, giving us an
area of appoximatively:
25914 m^2 ~= 26 km^2
So that a mouse traveling at an average
uniform speed of 1.8m/s would give an
arbitrary plant the chance to grow to
full maturity, instead of consuming it
before that.
Comments
Ironically, the errors that will occurr
will be due to physical model and the
coding itself rather than the mathematical
model.
For instance, there is no rationale
behind the movements of the mouse
and the next hop generator selects
random destinations for the mouse based
on uniformly scattered plots accross
the field.
The only parameters as seen from above
are reduced to:
* average uniform mouse speed
* length of the side of the square field
* time for a plant to reach full maturity.
Similarly, the physical movement is
simulated through dampening which implies
an acceleration or decelaration which might
incur errors leading to results that
should not be interpreted as a consequence
of a particular biological event.
More precisely, given a fixed choice of d,
a fixed choice of the velocity v and a choice
of a time t, one can trigger a resource
exhaustion, where all the plants are consumed
before they reach maturity. However, that is
not due to some biological process but rather
a consequence of carefully selected values.
Under the current abstraction, the choice of
the geometric shape of the field or mice is
irrelevant. Even if we could choose to
repeat the calculations in a circular field,
the only difference is that the calculations
will be different but they will still be
under the constraints of the abstracted model.
Wander Module
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// CONFIGURATION //
//////////////////////////////////////////////////////////
// The minimum distance in meters when the
// primitive will consider that it has reached
// its next destination.
float TARGET_AFFINITY = .2;
///////////////////////////////////////////////////////////////////////////
// INTERNALS //
///////////////////////////////////////////////////////////////////////////
vector origin = ZERO_VECTOR;
float radius = 0;
integer fuel = 0;
integer tid;
vector wasCirclePoint() {
float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) {
llOwnerSay((string)<x,y,0>);
return <x, y, 0>;
}
return wasCirclePoint();
}
moveTo(vector destination) {
llTargetRemove(tid);
tid = llTarget(destination, TARGET_AFFINITY);
llLookAt(destination, .6, .6);
float distance = llVecDist(llGetPos(), destination);
llOwnerSay("time:" + (string)(distance/.1151));
if(distance/.1151 > .05) {
llMoveToTarget(destination, distance/.1151);
return;
}
llMoveToTarget(destination, .05);
}
key owner = NULL_KEY;
key objCol = NULL_KEY;
default
{
state_entry() {
llSetStatus(STATUS_PHYSICS, FALSE);
llSetText("Primsect\n" + (string)fuel + "$", <1,1,1>, 1);›
tid = (integer)("0x"+llGetSubString((string)owner,-8,-1)) ^ 0xBFFFFFFF;
llOwnerSay("listening: " + (string)tid);
tid = llListen(tid, "[K] Soil", "", "");
}
on_rez(integer param) {
owner = llGetOwner();
}
listen(integer channel, string name, key id, string message) {
list chat = llParseString2List(message, ["="], [""]);
if(llList2String(chat, 0) != "@center") return;
llListenRemove(tid);
list para = llParseString2List(llList2String(chat, 1), ["|"], [""]);
origin.x = llList2Float(para, 0);
origin.y = llList2Float(para, 1);
origin.z = llList2Float(para, 2) + 1;
llSetPos(origin);
radius = llList2Float(para, 3);
state wander;
}
}
state wander
{
state_entry() {
llSetStatus(STATUS_PHYSICS, TRUE);
llSetForce(<0,0,9.81> * llGetMass(), 0);
llSetStatus(STATUS_ROTATE_X|STATUS_ROTATE_Y|STATUS_ROTATE_Z, FALSE);
llVolumeDetect(TRUE);
llCollisionFilter("[K] Grass", "", 1);
moveTo(origin + wasCirclePoint());
}
collision(integer num) {
if(llDetectedKey(0) == objCol) return;
objCol = llDetectedKey(0);
fuel += llList2Integer(llGetObjectDetails(objCol, [OBJECT_DESC]), 0)/10;
llSetText("Primsect\n" + (string)fuel + "$", <1,1,1>, 1);
}
at_target(integer tnum, vector targetpos, vector ourpos) {
//if(tnum != tid) return;
llOwnerSay("REACHED TARGET");
moveTo(origin + wasCirclePoint());
}
}
Rezzing Module
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// INTERNALS //
///////////////////////////////////////////////////////////////////////////
vector origin = ZERO_VECTOR;
vector scale = ZERO_VECTOR;
vector wasCirclePoint(float radius) {
float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
return <x, y, 0>;
return wasCirclePoint(radius);
}
key owner = NULL_KEY;
integer chan = 0;
default
{
state_entry() {
origin = llGetPos();
scale = llGetScale();
chan = (integer)("0x"+llGetSubString((string)owner,-8,-1)) ^ 0xBFFFFFFF;
chan = llListen(chan, "[K] Grass", "", "");
llSetTimerEvent(1);
}
on_rez(integer param) {
owner = llGetOwner();
}
listen(integer channel, string name, key id, string message) {
list chat = llParseString2List(message, ["="], [""]);
if(llList2String(chat, 0) != "@spawn") return;
llListenRemove(chan);
list para = llParseString2List(llList2String(chat, 1), ["|"], [""]);
vector objOrigin = ZERO_VECTOR;
objOrigin.x = llList2Float(para, 0);
objOrigin.y = llList2Float(para, 1);
objOrigin.z = origin.z;
llRezObject("[K] Primsect", origin + wasCirclePoint(.6), ZERO_VECTOR, ZERO_ROTATION, 1);
}
touch_start(integer total_number) {
llRezObject("[K] Primsect", origin + wasCirclePoint(scale.x/2), ZERO_VECTOR, ZERO_ROTATION, 1);
}
timer() {
integer chan = (integer)("0x"+llGetSubString((string)owner,-8,-1)) ^ 0xBFFFFFFF;
llRegionSay(chan, "@center=" + (string)origin.x + "|" + (string)origin.y + "|" + (string)origin.z + "|" + (string)(scale.x/2));
}
}
Growth Module
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////
// CONFIGURATION //
//////////////////////////////////////////////////////////
// The delay in seconds to wait b
// before the object grows another
// GROWTH_PER_INTERVAL meters.
float GROWTH_INTERVAL = 3600;
//////////////////////////////////////////////////////////
// INTERNALS //
//////////////////////////////////////////////////////////
integer fuel = 10;
vector pos = ZERO_VECTOR;
key owner = NULL_KEY;
integer chan = 0;
default
{
state_entry() {
pos = llGetPos();
chan = (integer)("0x"+llGetSubString((string)owner,-8,-1)) ^ 0xBFFFFFFF;
state growth;
}
on_rez(integer param) {
owner = llGetOwner();
}
}
state growth
{
state_entry() {
llCollisionFilter("[K] Primsect", "", 1);
llSetObjectDesc((string)fuel);
llSetText("Grass\n" + (string)fuel + "$", <1,1,1>, 1);
llSetTimerEvent(GROWTH_INTERVAL);
}
collision(integer num) {
llRegionSay(chan, "@consumed=" + (string)pos.x + "|" + (string)pos.y);
llOwnerSay("Bye bye...");
}
timer() {
vector size = llGetScale();
if(size.z >= .5) {
llRegionSay(chan, "@spawn=" + (string)pos.x + "|" + (string)pos.y);
llSetTimerEvent(GROWTH_INTERVAL*4);
return;
}
size += <.1, .1, .1>;
llSetScale(<size.x, size.y, size.z>);
pos.z += .05;
llSetPos(<pos.x, pos.y, pos.z>);
fuel += 10;
llSetObjectDesc((string)fuel);
llSetText((string)fuel + "$", <1,1,1>, 1);
}
}