home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 02 Useful Techniques / 08 Zarozinski / src / ffllapi / FFLLBase.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-12-05  |  10.9 KB  |  516 lines

  1. //
  2. // File:    FFLLBase.cpp
  3. //
  4. // Purpose:    Base class for all FFLL files.
  5. //
  6. // Copyright ⌐ 1998-2001 Louder Than A Bomb! Software
  7. //
  8. // This file is part of the FFLL (Free Fuzzy Logic Library) project (http://ffll.sourceforge.net)
  9. // It is released under the BSD license, see http://ffll.sourceforge.net/license.txt for the full text.
  10. //
  11.  
  12. #include "FFLLBase.h"
  13. #include "FuzzyVariableBase.h"
  14.  
  15. #ifdef _DEBUG
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19.  
  20. // define literals, warning and error messages  
  21.  
  22. wchar_t* literals[] = 
  23.     { 
  24.     L"New",
  25.     L"Variable",
  26.     L"Set",
  27.     L"Output",
  28.     L"Copy of"
  29.     };
  30.  
  31. wchar_t* errors[] = 
  32.     { 
  33.     L"Variable Identifier Must Be Unique",
  34.     L"Set Identifier Must Be Unique Within The Variable",
  35.     L"The Variable's Minimum And Maximum Values Can Not Be The Same",
  36.     L"Invalid File Format",
  37.     L"Can Not Remove Output Variable",
  38.     L"Reached End Of File Before Reading Variables",
  39.     L"Reached End Of File Before Reading Rules",
  40.     L"Reached End Of File Before Reading Sets",
  41.     L"Model Already Has An Output Variable",
  42.     L"Error Allocating Memory",
  43.     L"Invalid Defuzzification Method",
  44.     L"Invalid Composition Method",
  45.     L"Invalid Inference Method",
  46.     L"Error Opening File",
  47.     L"Error Reading Variable Minimum Value",
  48.     L"Error Reading Variable Maximum Value"
  49.     };
  50. wchar_t* warnings[] = 
  51.     { 
  52.     NULL
  53.     };
  54.  
  55. //
  56. // Function:    FFLLBase()
  57. // 
  58. // Purpose:        FFLLBase constructor
  59. //
  60. // Arguments:
  61. //
  62. //        void* parent -    pointer to the parent of this object. For example if this is the
  63. //                        base for a variable, the parent will be the model.
  64. //
  65. // Returns:
  66. //
  67. //        nothing
  68. //
  69. // Author:    Michael Zarozinski
  70. // Date:    5/00
  71. // 
  72. // Modification History
  73. // Author    Date        Modification
  74. // ------    ----        ------------
  75. //
  76. //
  77. FFLLBase::FFLLBase(void* _parent)
  78. {
  79.     parent = _parent;
  80.     error_read = false;
  81.  
  82. }; // end FFLLBase::FFLLBase()
  83.   
  84. //
  85. // Function:    convert_to_ascii()
  86. // 
  87. // Purpose:    Utility function to convert from wide characters to ascii
  88. //            characters. The caller MUST free the memory allocated
  89. //
  90. // Arguments:
  91. //
  92. //        const wchar_t*    wstr            -    wide character string to convert
  93. //        const char*        replace_space     -    string to replace spaces with (optional)
  94. //
  95. // Returns:
  96. //
  97. //        char* - converted string
  98. //
  99. // Author:    Michael Zarozinski
  100. // Date:    9/01/01
  101. // 
  102. // Modification History
  103. // Author    Date        Modification
  104. // ------    ----        ------------
  105. //
  106. //
  107. FFLL_API char* convert_to_ascii(const wchar_t* wstr, char replace_space /* = -1 */)
  108. {
  109.     if (wstr == NULL)
  110.         return NULL;
  111.  
  112.      // get the ascii version of the id...
  113.     char* astr = new char[wcslen(wstr) + 1];
  114.  
  115.      sprintf(astr, "%S", wstr);
  116.  
  117.     // if a 'replace_space' character was passed, replace any spaces with that char
  118.     // replace any spaces with underscores
  119.  
  120.     if (replace_space >= 0)
  121.         {
  122.         int len = strlen(astr);
  123.  
  124.         while (len)
  125.             {
  126.             if (astr[len] == ' ')
  127.                 astr[len] = replace_space;
  128.             len--;
  129.             }
  130.         } // end if replace space
  131.  
  132.     return astr;
  133.  
  134. } // end convert_to_ascii()
  135.  
  136.   
  137. //
  138. // Function:    convert_to_wide_char()
  139. // 
  140. // Purpose:    Utility function to convert from ascii to wide characters
  141. //            The caller MUST free the memory allocated
  142. //
  143. // Arguments:
  144. //
  145. //        const char*    wstr -    ascii string to convert
  146. //
  147. // Returns:
  148. //
  149. //        wchar_t* - converted string
  150. //
  151. // Author:    Michael Zarozinski
  152. // Date:    9/01/01
  153. // 
  154. // Modification History
  155. // Author    Date        Modification
  156. // ------    ----        ------------
  157. //
  158. //
  159. FFLL_API wchar_t* convert_to_wide_char(const char* astr)
  160. {
  161.     if (astr == NULL)
  162.         return NULL;
  163.  
  164.      // get the ascii version of the id...
  165.     wchar_t* wstr = new wchar_t[strlen(astr) + 1];
  166.  
  167.      swprintf(wstr, L"%S", astr);
  168.  
  169.     return wstr;
  170.  
  171. } // end convert_to_wide_char()
  172.  
  173. //
  174. // Function:    get_msg_text()
  175. // 
  176. // Purpose:        Return the msg_text variable.
  177. //
  178. // Arguments:
  179. //
  180. //        none
  181. //
  182. // Returns:
  183. //
  184. //        const wchar_t* - the message text
  185. //
  186. // Author:    Michael Zarozinski
  187. // Date:    8/01
  188. // 
  189. // Modification History
  190. // Author    Date        Modification
  191. // ------    ----        ------------
  192. //
  193. //
  194. const wchar_t* FFLLBase::get_msg_text() const
  195. {
  196.     // since we're returning a pointer to the string in msg_text we can't just
  197.     // clear out msg_text. So we use the "read" flag that indicates
  198.     // that this error has been read at some point.
  199.  
  200.     // if we've already read this error, return null
  201.     if (error_read)
  202.         return NULL;
  203.  
  204.     error_read = true;
  205.      return((msg_text == L"") ? NULL : msg_text.data());
  206.  
  207. }; // end FFLLBase::get_msg_text()
  208.  
  209. //
  210. // Function:    set_msg_text()
  211. // 
  212. // Purpose:        Set the msg_text string so a human-readable error can be reported.
  213. //
  214. // Arguments:
  215. //
  216. //        int msg_id -    identifier of the message. This is converted to text via the
  217. //                        load_string() function.
  218. //
  219. // Returns:
  220. //
  221. //        void
  222. //
  223. // Author:    Michael Zarozinski
  224. // Date:    8/01
  225. // 
  226. // Modification History
  227. // Author    Date        Modification
  228. // ------    ----        ------------
  229. //
  230. //
  231. void FFLLBase::set_msg_text(int msg_id) const
  232. {
  233.      // vars are mutable so we can modify them event though this func is 'const'
  234.     error_read = false;
  235.     msg_text = load_string(msg_id);
  236.  
  237. }; // end FFLLBase::set_msg_text()
  238.  
  239.  
  240.  
  241. //
  242. // Function:    set_msg_text()
  243. // 
  244. // Purpose:        Set the msg_text string so a human-readable error can be reported.
  245. //
  246. // Arguments:
  247. //
  248. //        const std::wstring _text - text to set msg_text to
  249. //
  250. // Returns:
  251. //
  252. //        void
  253. //
  254. // Author:    Michael Zarozinski
  255. // Date:    8/01
  256. // 
  257. // Modification History
  258. // Author    Date        Modification
  259. // ------    ----        ------------
  260. //
  261. //    
  262.  
  263. void FFLLBase::set_msg_text(const std::wstring _text) const
  264. {
  265.     set_msg_text(_text.data());
  266.  
  267. }; // end FFLLBase::set_msg_text()
  268.  
  269.  
  270. //
  271. // Function:    set_msg_text()
  272. // 
  273. // Purpose:        Set the msg_text string so a human-readable error can be reported.
  274. //
  275. // Arguments:
  276. //
  277. //        const wchar_t* - text to set msg_text to
  278. //
  279. // Returns:
  280. //
  281. //        void
  282. //
  283. // Author:    Michael Zarozinski
  284. // Date:    8/01
  285. // 
  286. // Modification History
  287. // Author    Date        Modification
  288. // ------    ----        ------------
  289. //
  290. //    
  291.  
  292. void FFLLBase::set_msg_text(const wchar_t* _text /* = NULL */) const
  293. {
  294.     // NOTE: Class vars are mutable so we can modify them event though this func is 'const'
  295.     
  296.     // if text is null, we're clearing out any pre-existing error
  297.     if (_text == NULL)
  298.         {
  299.         // set error_read to true so we just get NULL returned if we call get_msg_text()
  300.         error_read = true;
  301.          msg_text = L"";
  302.         }
  303.      else
  304.         {
  305.         error_read = false;    
  306.         msg_text = _text;
  307.         }
  308.  
  309. } // end FFLLBase::set_msg_text()
  310.  
  311.   
  312.  
  313. //
  314. // Function:    load_string()
  315. // 
  316. // Purpose:    this function converts a #define to a string.  It's nothing special right now
  317. //            but provides a framework that can be expanded in the future
  318. //
  319. // Arguments:
  320. //
  321. //        int str_id    -    identifier for the string to load
  322. //
  323. // Returns:
  324. //
  325. //        const wchar_t* - string associated with the id passed in
  326. //
  327. // Author:    Michael Zarozinski
  328. // Date:    9/01/01
  329. // 
  330. // Modification History
  331. // Author    Date        Modification
  332. // ------    ----        ------------
  333. //
  334. //
  335. const wchar_t* FFLLBase::load_string(int str_id) const
  336. {
  337.     // convert to an index....
  338.  
  339.     if (str_id >= WARNING_BASE)
  340.         {
  341.         str_id -= WARNING_BASE;
  342.  
  343.         // make sure we don't go beyond the bounds...
  344.  
  345.         if (str_id >= sizeof(warnings))
  346.             {
  347.             assert(0);
  348.             return L"Message Not Defined";
  349.             }
  350.         else
  351.             return warnings[str_id];
  352.         }
  353.  
  354.      if (str_id >= ERROR_BASE)
  355.         {
  356.         str_id -= ERROR_BASE;
  357.  
  358.         // make sure we don't go beyond the bounds...
  359.  
  360.         if (str_id >= sizeof(errors))
  361.             {
  362.             assert(0);
  363.             return L"Message Not Defined";
  364.             }
  365.         else
  366.             return errors[str_id];
  367.         }
  368.  
  369.     if (str_id >= LITERAL_BASE)
  370.         {
  371.         str_id -= LITERAL_BASE;
  372.  
  373.         // make sure we don't go beyond the bounds...
  374.  
  375.         if (str_id >= sizeof(literals))
  376.             {
  377.             assert(0);
  378.             return L"Message Not Defined";
  379.             }
  380.         else
  381.             return literals[str_id];
  382.         }
  383.  
  384.     assert(0);
  385.     return L"Message Not Defined";
  386.  
  387. } // FFLLBase::load_string()
  388.  
  389. /////////////////////////////////////////////////////////////////////
  390. ////////// Trivial Functions That Don't Require Headers /////////////
  391. /////////////////////////////////////////////////////////////////////
  392.  
  393. void* FFLLBase::get_parent() const
  394. {
  395.     // any func that calls this needs to cast to the correct object otherwize
  396.     // the compiler gets very confused
  397.     return(parent);
  398.  
  399. }; // end FFLLBase::get_parent()
  400.          
  401. NodeValue::operator int()
  402. {
  403.     return value;
  404. };
  405. int& NodeValue::operator+=(const int& _value)
  406. {
  407.     value += _value; 
  408.     return value;
  409. };
  410. int& NodeValue::operator-=(const int& _value)
  411.     value -= _value; 
  412.     return value;
  413. };
  414. void NodeValue::operator<<(const int& _value)
  415.     value = _value;
  416. };
  417. int& NodeValue::operator=(const int& _value)
  418. {
  419.     value = _value; 
  420.     validate();        // virtual func
  421.     return value;
  422. };
  423.  
  424. // XNodeValue & YNodeValue use their validate() function to make sure values are
  425. // within the appropriate bounds.  The validiation is built-in so we don't have to
  426. // validate the values every time - that would be a pain.
  427.  
  428. int& XNodeValue::operator=(const int& _value)
  429. {
  430.     return NodeValue::operator =(_value);
  431. };
  432.  
  433. void XNodeValue::validate()
  434. {
  435.     if (value < 0)
  436.         value = 0;
  437.     if (value >= FuzzyVariableBase::get_x_array_count())
  438.         value = FuzzyVariableBase::get_x_array_max_idx();
  439. };
  440.  
  441.  
  442. int& YNodeValue::operator=(const int& _value)
  443. {
  444.     return NodeValue::operator =(_value);
  445. };
  446.  
  447. void YNodeValue::validate()
  448. {
  449.     if (value < 0)
  450.         value = 0;
  451.     if (value >= FuzzyVariableBase::get_dom_array_count())
  452.         value = FuzzyVariableBase::get_dom_array_max_idx();
  453. };
  454.  
  455.  
  456.  
  457.  
  458.  
  459. static char sDecimalSeparator = '.'; // dot by default
  460. static char sThousantSeparator =','; // comma by default
  461.  
  462. // call this to format a long to a string
  463. static char* __stdcall long2str( char* szBuffer, long lValue )
  464. {
  465.   char *p;                // pointer to traverse string
  466.   char *firstdig;         // pointer to first digit
  467.   char temp;              // temp char
  468.   unsigned digval;        // value of digit
  469.   unsigned long val;
  470.  
  471.   p = szBuffer;
  472.  
  473.   if (lValue < 0 ) {
  474.       // negative, so output '-' and negate
  475.      *p++ = '-';
  476.      val = (unsigned long)(-(long)lValue); // make it positive!!
  477.   } else
  478.      val = lValue;
  479.  
  480.   firstdig = p;    // save pointer to first digit
  481.  
  482.   int iDecimalPos = 0;
  483.  
  484.   do {
  485.      iDecimalPos ++;
  486.      if (iDecimalPos != 4)
  487.      {
  488.        digval = (unsigned) (val % 10);
  489.        val /= 10;                     // get next digit
  490.        *p++ = (char) (digval + '0');  // and store the digit
  491.      } else
  492.      {
  493.        *p++ = sThousantSeparator;
  494.        iDecimalPos = 0;
  495.      }
  496.   } while (val > 0);
  497.  
  498.   //  We now have the digit of the number in the buffer, 
  499.   // but in reverse order.  Thus we reverse them now.
  500.  
  501.   *p-- = '\0';    // terminate string; p points to last digit
  502.  
  503.   do {
  504.       temp = *p;
  505.       *p = *firstdig;
  506.       *firstdig = temp;   // swap *p and *firstdig
  507.       --p;
  508.       ++firstdig;         
  509.   } while (firstdig < p); // repeat until halfway
  510.  
  511.   return szBuffer;
  512. }
  513.  
  514.