Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

SCA_RandomActuator.cpp

Go to the documentation of this file.
00001 
00006 
00007 #include "BoolValue.h"
00008 #include "IntValue.h"
00009 #include "FloatValue.h"
00010 #include "SCA_IActuator.h"
00011 #include "SCA_RandomActuator.h"
00012 #include "math.h"
00013 
00014 #include "MT_Transform.h"
00015 /* ------------------------------------------------------------------------- */
00016 /* Native functions                                                          */
00017 /* ------------------------------------------------------------------------- */
00018 
00019 SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, 
00020                                                                          long seed,
00021                                                                          SCA_RandomActuator::KX_RANDOMACT_MODE mode,
00022                                                                          float para1,
00023                                                                          float para2,
00024                                                                          const CCString &propName,
00025                                                                          PyTypeObject* T)
00026         : SCA_IActuator(gameobj, T),
00027           m_distribution(mode),
00028           m_propname(propName),
00029           m_parameter1(para1),
00030           m_parameter2(para2) 

00031 {
00032         m_base = new SCA_RandomNumberGenerator(seed);
00033         m_counter = 0;
00034         enforceConstraints();
00035 } 
00036 
00037 SCA_RandomActuator::~SCA_RandomActuator() { /* intentionally empty */ } 
00038 
00039 bool SCA_RandomActuator::Update(double curtime,double deltatime)

00040 {
00041         bool result = false;    
00042         bool bNegativeEvent = IsNegativeEvent();
00043         CValue *tmpval;
00044 
00045         if (bNegativeEvent)
00046                 return false; // do nothing on negative events
00047 
00048         switch (m_distribution) {
00049         case KX_RANDOMACT_BOOL_CONST: {
00050                 /* un petit peu filthy */
00051                 bool res = !(m_parameter1 < 0.5);
00052                 tmpval = new CBoolValue(res);
00053         }
00054         break;
00055         case KX_RANDOMACT_BOOL_UNIFORM: {
00056                 /* flip a coin */
00057                 bool res; 
00058                 if (m_counter > 31) {
00059                         m_previous = m_base->Draw();
00060                         res = ((m_previous & 0x1) == 0);
00061                         m_counter = 1;
00062                 } else {
00063                         res = (((m_previous >> m_counter) & 0x1) == 0);
00064                         m_counter++;
00065                 }
00066                 tmpval = new CBoolValue(res);
00067         }
00068         break;
00069         case KX_RANDOMACT_BOOL_BERNOUILLI: {
00070                 /* 'percentage' */
00071                 bool res;
00072                 res = (m_base->DrawFloat() < m_parameter1);
00073                 tmpval = new CBoolValue(res);
00074         }
00075         break;
00076         case KX_RANDOMACT_INT_CONST: {
00077                 /* constant */
00078                 tmpval = new CIntValue((int) floor(m_parameter1));
00079         }
00080         break;
00081         case KX_RANDOMACT_INT_UNIFORM: {
00082                 /* uniform (toss a die) */
00083                 int res; 
00084                 /* The [0, 1] interval is projected onto the [min, max+1] domain,    */
00085                 /* and then rounded.                                                 */
00086                 res = (int) floor( ((m_parameter2 - m_parameter1 + 1) * m_base->DrawFloat())
00087                                                    + m_parameter1);
00088                 tmpval = new CIntValue(res);
00089         }
00090         break;
00091         case KX_RANDOMACT_INT_POISSON: {
00092                 /* poisson (queues) */
00093                 /* If x_1, x_2, ... is a sequence of random numbers with uniform     */
00094                 /* distribution between zero and one, k is the first integer for     */
00095                 /* which the product x_1*x_2*...*x_k < exp(-\lamba).                 */
00096                 float a = 0.0, b = 0.0;
00097                 int res = 0;
00098                 /* The - sign is important here! The number to test for, a, must be  */
00099                 /* between 0 and 1.                                                  */
00100                 a = exp(-m_parameter1);
00101                 /* a quickly reaches 0.... so we guard explicitly for that.          */
00102                 if (a < FLT_MIN) a = FLT_MIN;
00103                 b = m_base->DrawFloat();
00104                 while (b >= a) {
00105                         b = b * m_base->DrawFloat();
00106                         res++;
00107                 };      
00108                 tmpval = new CIntValue(res);
00109         }
00110         break;
00111         case KX_RANDOMACT_FLOAT_CONST: {
00112                 /* constant */
00113                 tmpval = new CFloatValue(m_parameter1);
00114         }
00115         break;
00116         case KX_RANDOMACT_FLOAT_UNIFORM: {
00117                 float res = ((m_parameter2 - m_parameter1) * m_base->DrawFloat())
00118                         + m_parameter1;
00119                 tmpval = new CFloatValue(res);
00120         }
00121         break;
00122         case KX_RANDOMACT_FLOAT_NORMAL: {
00123                 /* normal (big numbers): para1 = mean, para2 = std dev               */
00124                 float x = 0.0, y = 0.0, s = 0.0, t = 0.0;
00125                 do {
00126                         x = 2.0 * m_base->DrawFloat() - 1.0;
00127                         y = 2.0 * m_base->DrawFloat() - 1.0;
00128                         s = x*x + y*y;
00129                 } while ( (s >= 1.0) || (s == 0.0) );
00130                 t = x * sqrt( (-2.0 * log(s)) / s);
00131                 tmpval = new CFloatValue(m_parameter1 + m_parameter2 * t);
00132         }
00133         break;
00134         case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: {
00135                 /* 1st order fall-off. I am very partial to using the half-life as    */
00136                 /* controlling parameter. Using the 'normal' exponent is not very     */
00137                 /* intuitive...                                                       */
00138                 /* tmpval = new CFloatValue( (1.0 / m_parameter1)                     */
00139                 tmpval = new CFloatValue( (m_parameter1) 
00140                                                                   * (-log(1.0 - m_base->DrawFloat())) );
00141 
00142         }
00143         break;
00144         default:
00145                 ; /* unknown distribution... */
00146         }
00147 
00148         /* Round up: assign it */
00149         CValue *prop = GetParent()->GetProperty(m_propname);
00150         if (prop) {
00151                 prop->SetValue(tmpval);
00152         }
00153         tmpval->Release();
00154 
00155         return false;
00156 }
00157 
00158 void SCA_RandomActuator::enforceConstraints() {
00159         /* The constraints that are checked here are the ones fundamental to     */
00160         /* the various distributions. Limitations of the algorithms are checked  */
00161         /* elsewhere (or they should be... ).                                    */
00162         switch (m_distribution) {
00163         case KX_RANDOMACT_BOOL_CONST:
00164         case KX_RANDOMACT_BOOL_UNIFORM:
00165         case KX_RANDOMACT_INT_CONST:
00166         case KX_RANDOMACT_INT_UNIFORM:
00167         case KX_RANDOMACT_FLOAT_UNIFORM:
00168         case KX_RANDOMACT_FLOAT_CONST:
00169                 ; /* Nothing to be done here. We allow uniform distro's to have      */
00170                 /* 'funny' domains, i.e. max < min. This does not give problems.     */
00171                 break;
00172         case KX_RANDOMACT_BOOL_BERNOUILLI: 
00173                 /* clamp to [0, 1] */
00174                 if (m_parameter1 < 0.0) {
00175                         m_parameter1 = 0.0;
00176                 } else if (m_parameter1 > 1.0) {
00177                         m_parameter1 = 1.0;
00178                 }
00179                 break;
00180         case KX_RANDOMACT_INT_POISSON: 
00181                 /* non-negative */
00182                 if (m_parameter1 < 0.0) {
00183                         m_parameter1 = 0.0;
00184                 }
00185                 break;
00186         case KX_RANDOMACT_FLOAT_NORMAL: 
00187                 /* standard dev. is non-negative */
00188                 if (m_parameter2 < 0.0) {
00189                         m_parameter2 = 0.0;
00190                 }
00191                 break;
00192         case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: 
00193                 /* halflife must be non-negative */
00194                 if (m_parameter1 < 0.0) {
00195                         m_parameter1 = 0.0;
00196                 }
00197                 break;
00198         default:
00199                 ; /* unknown distribution... */
00200         }
00201 }
00202 
00203 /* ------------------------------------------------------------------------- */
00204 /* Python functions                                                          */
00205 /* ------------------------------------------------------------------------- */
00206 
00207 /* Integration hooks ------------------------------------------------------- */
00208 PyTypeObject SCA_RandomActuator::Type = {
00209         PyObject_HEAD_INIT(&PyType_Type)
00210         0,
00211         "SCA_RandomActuator",
00212         sizeof(SCA_RandomActuator),
00213         0,
00214         PyDestructor,
00215         0,
00216         __getattr,
00217         __setattr,
00218         0, //&MyPyCompare,
00219         __repr,
00220         0, //&cvalue_as_number,
00221         0,
00222         0,
00223         0,
00224         0
00225 };
00226 
00227 PyParentObject SCA_RandomActuator::Parents[] = {
00228         &SCA_RandomActuator::Type,
00229         &SCA_IActuator::Type,
00230         &SCA_ILogicBrick::Type,
00231         &CValue::Type,
00232         NULL
00233 };
00234 
00235 PyMethodDef SCA_RandomActuator::Methods[] = {
00236         {"setSeed",         (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc},
00237         {"getSeed",         (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc},
00238         {"getPara1",        (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc},
00239         {"getPara2",        (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc},
00240         {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc},
00241         {"setProperty",     (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
00242         {"getProperty",     (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
00243         {"setBoolConst",    (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc},
00244         {"setBoolUniform",  (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc},
00245         {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc},
00246         {"setIntConst",     (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc},
00247         {"setIntUniform",   (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc},
00248         {"setIntPoisson",   (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc},
00249         {"setFloatConst",   (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc},
00250         {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc},
00251         {"setFloatNormal",  (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc},
00252         {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc},
00253         {NULL,NULL} //Sentinel
00254 };
00255 
00256 PyObject* SCA_RandomActuator::_getattr(char* attr) {
00257         _getattr_up(SCA_IActuator);
00258 }
00259 
00260 /* 1. setSeed                                                            */
00261 char SCA_RandomActuator::SetSeed_doc[] = 
00262 "setSeed(seed)\n"
00263 "\t- seed: integer\n"
00264 "\tSet the initial seed of the generator. Equal seeds produce\n"
00265 "\tequal series. If the seed is 0, the generator will produce\n"
00266 "\tthe same value on every call.\n";
00267 PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
00268         long seedArg;
00269         if(!PyArg_ParseTuple(args, "i", &seedArg)) {
00270                 return NULL;
00271         }
00272         
00273         m_base->SetSeed(seedArg);
00274         
00275         Py_Return;
00276 }
00277 /* 2. getSeed                                                            */
00278 char SCA_RandomActuator::GetSeed_doc[] = 
00279 "getSeed()\n"
00280 "\tReturns the initial seed of the generator. Equal seeds produce\n"
00281 "\tequal series.\n";
00282 PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
00283         return PyInt_FromLong(m_base->GetSeed());
00284 }
00285 
00286 /* 4. getPara1                                                           */
00287 char SCA_RandomActuator::GetPara1_doc[] = 
00288 "getPara1()\n"
00289 "\tReturns the first parameter of the active distribution. Refer\n"
00290 "\tto the documentation of the generator types for the meaning\n"
00291 "\tof this value.";
00292 PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) {
00293         return PyFloat_FromDouble(m_parameter1);
00294 }
00295 
00296 /* 6. getPara2                                                           */
00297 char SCA_RandomActuator::GetPara2_doc[] = 
00298 "getPara2()\n"
00299 "\tReturns the first parameter of the active distribution. Refer\n"
00300 "\tto the documentation of the generator types for the meaning\n"
00301 "\tof this value.";
00302 PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) {
00303         return PyFloat_FromDouble(m_parameter2);
00304 }
00305 
00306 /* 8. getDistribution                                                    */
00307 char SCA_RandomActuator::GetDistribution_doc[] = 
00308 "getDistribution()\n"
00309 "\tReturns the type of the active distribution.\n";
00310 PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) {
00311         return PyInt_FromLong(m_distribution);
00312 }
00313 
00314 /* 9. setProperty                                                        */
00315 char SCA_RandomActuator::SetProperty_doc[] = 
00316 "setProperty(name)\n"
00317 "\t- name: string\n"
00318 "\tSet the property to which the random value is assigned. If the \n"
00319 "\tgenerator and property types do not match, the assignment is ignored.\n";
00320 PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
00321         char *nameArg;
00322         if (!PyArg_ParseTuple(args, "s", &nameArg)) {
00323                 return NULL;
00324         }
00325 
00326         CValue* prop = GetParent()->FindIdentifier(nameArg);
00327 
00328         if (prop) {
00329                 m_propname = nameArg;
00330         } else {
00331                 ; /* not found ... */
00332         }
00333         
00334         Py_Return;
00335 }
00336 /* 10. getProperty                                                       */
00337 char SCA_RandomActuator::GetProperty_doc[] = 
00338 "getProperty(name)\n"
00339 "\tReturn the property to which the random value is assigned. If the \n"
00340 "\tgenerator and property types do not match, the assignment is ignored.\n";
00341 PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
00342         return PyString_FromString(m_propname);
00343 }
00344 
00345 /* 11. setBoolConst */
00346 char SCA_RandomActuator::SetBoolConst_doc[] = 
00347 "setBoolConst(value)\n"
00348 "\t- value: 0 or 1\n"
00349 "\tSet this generator to produce a constant boolean value.\n";
00350 PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, 
00351                                                                                         PyObject* args, 
00352                                                                                         PyObject* kwds) {
00353         int paraArg;
00354         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
00355                 return NULL;
00356         }
00357         
00358         m_distribution = KX_RANDOMACT_BOOL_CONST;
00359         if (paraArg == KX_TRUE) {
00360                 m_parameter1 = 1;
00361         }
00362         
00363         Py_Return;
00364 }
00365 /* 12. setBoolUniform, */
00366 char SCA_RandomActuator::SetBoolUniform_doc[] = 
00367 "setBoolUniform()\n"
00368 "\tSet this generator to produce true and false, each with 50%% chance of occuring\n";
00369 PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, 
00370                                                                                           PyObject* args, 
00371                                                                                           PyObject* kwds) {
00372         /* no args */
00373         m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
00374         enforceConstraints();
00375         Py_Return;
00376 }
00377 /* 13. setBoolBernouilli,  */
00378 char SCA_RandomActuator::SetBoolBernouilli_doc[] = 
00379 "setBoolBernouilli(value)\n"
00380 "\t- value: a float between 0 and 1\n"
00381 "\tReturn false value * 100%% of the time.\n";
00382 PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, 
00383                                                                                                  PyObject* args, 
00384                                                                                                  PyObject* kwds) {
00385         float paraArg;
00386         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
00387                 return NULL;
00388         }
00389         
00390         m_distribution = KX_RANDOMACT_BOOL_CONST;
00391         m_parameter1 = paraArg; 
00392         enforceConstraints();
00393         Py_Return;
00394 }
00395 /* 14. setIntConst,*/
00396 char SCA_RandomActuator::SetIntConst_doc[] = 
00397 "setIntConst(value)\n"
00398 "\t- value: integer\n"
00399 "\tAlways return value\n";
00400 PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, 
00401                                                                                    PyObject* args, 
00402                                                                                    PyObject* kwds) {
00403         int paraArg;
00404         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
00405                 return NULL;
00406         }
00407         
00408         m_distribution = KX_RANDOMACT_INT_CONST;
00409         m_parameter1 = paraArg;
00410         enforceConstraints();
00411         Py_Return;
00412 }
00413 /* 15. setIntUniform,*/
00414 char SCA_RandomActuator::SetIntUniform_doc[] = 
00415 "setIntUniform(lower_bound, upper_bound)\n"
00416 "\t- lower_bound: integer\n"
00417 "\t- upper_bound: integer\n"
00418 "\tReturn a random integer between lower_bound and\n"
00419 "\tupper_bound. The boundaries are included.\n";
00420 PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, 
00421                                                                                          PyObject* args, 
00422                                                                                          PyObject* kwds) {
00423         int paraArg1, paraArg2;
00424         if(!PyArg_ParseTuple(args, "ii", &paraArg1, &paraArg2)) {
00425                 return NULL;
00426         }
00427         
00428         m_distribution = KX_RANDOMACT_INT_UNIFORM;
00429         m_parameter1 = paraArg1;
00430         m_parameter2 = paraArg2;
00431         enforceConstraints();
00432         Py_Return;
00433 }
00434 /* 16. setIntPoisson,           */
00435 char SCA_RandomActuator::SetIntPoisson_doc[] = 
00436 "setIntPoisson(value)\n"
00437 "\t- value: float\n"
00438 "\tReturn a Poisson-distributed number. This performs a series\n"
00439 "\tof Bernouilli tests with parameter value. It returns the\n"
00440 "\tnumber of tries needed to achieve succes.\n";
00441 PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, 
00442                                                                                          PyObject* args, 
00443                                                                                          PyObject* kwds) {
00444         float paraArg;
00445         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
00446                 return NULL;
00447         }
00448         
00449         m_distribution = KX_RANDOMACT_INT_POISSON;
00450         m_parameter1 = paraArg; 
00451         enforceConstraints();
00452         Py_Return;
00453 }
00454 /* 17. setFloatConst,*/
00455 char SCA_RandomActuator::SetFloatConst_doc[] = 
00456 "setFloatConst(value)\n"
00457 "\t- value: float\n"
00458 "\tAlways return value\n";
00459 PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, 
00460                                                                                          PyObject* args, 
00461                                                                                          PyObject* kwds) {
00462         float paraArg;
00463         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
00464                 return NULL;
00465         }
00466         
00467         m_distribution = KX_RANDOMACT_FLOAT_CONST;
00468         m_parameter1 = paraArg; 
00469         enforceConstraints();
00470         Py_Return;
00471 }
00472 /* 18. setFloatUniform, */
00473 char SCA_RandomActuator::SetFloatUniform_doc[] = 
00474 "setFloatUniform(lower_bound, upper_bound)\n"
00475 "\t- lower_bound: float\n"
00476 "\t- upper_bound: float\n"
00477 "\tReturn a random integer between lower_bound and\n"
00478 "\tupper_bound.\n";
00479 PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, 
00480                                                                                            PyObject* args, 
00481                                                                                            PyObject* kwds) {
00482         float paraArg1, paraArg2;
00483         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
00484                 return NULL;
00485         }
00486         
00487         m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
00488         m_parameter1 = paraArg1;
00489         m_parameter2 = paraArg2;
00490         enforceConstraints();
00491         Py_Return;
00492 }
00493 /* 19. setFloatNormal, */
00494 char SCA_RandomActuator::SetFloatNormal_doc[] = 
00495 "setFloatNormal(mean, standard_deviation)\n"
00496 "\t- mean: float\n"
00497 "\t- standard_deviation: float\n"
00498 "\tReturn normal-distributed numbers. The average is mean, and the\n"
00499 "\tdeviation from the mean is characterized by standard_deviation.\n";
00500 PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, 
00501                                                                                           PyObject* args, 
00502                                                                                           PyObject* kwds) {
00503         float paraArg1, paraArg2;
00504         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
00505                 return NULL;
00506         }
00507         
00508         m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
00509         m_parameter1 = paraArg1;
00510         m_parameter2 = paraArg2;
00511         enforceConstraints();
00512         Py_Return;
00513 }
00514 /* 20. setFloatNegativeExponential, */
00515 char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = 
00516 "setFloatNegativeExponential(half_life)\n"
00517 "\t- half_life: float\n"
00518 "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
00519 "\tis characterized by half_life.\n";
00520 PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self, 
00521                                                                                                                    PyObject* args, 
00522                                                                                                                    PyObject* kwds) {
00523         float paraArg;
00524         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
00525                 return NULL;
00526         }
00527         
00528         m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
00529         m_parameter1 = paraArg; 
00530         enforceConstraints();
00531         Py_Return;
00532 }
00533         
00534 /* eof */

Generated at Thu Feb 1 13:03:11 2001 for Ketsji Game Engine by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000