Home Page Downloads Contact Us

Free Open Source Artificial Intelligence C++ Parts

aiParts Open Source Project  

Home Page
Open Source
Contact
Free Downloads
Releases and Credits
Software Status
License
v0.9.3 README File
About rrproj
assigning people and/or equipment to projects
High-Hope Technique
History of the AI
View Source Files
and how they are organized
Making Programs
Development Notes
Using aiParts
Your Application
Support and Services

aiParts Source File

//**********************************************************************
//  aipBase.cpp  -  function bodies for aipBase.h
//
//  Copyright (c)  1999, 2005, 2007, 2008  Brian Marshall
//
//  See the license at end of this file.
//
//  Developers/Contributers:
//    [BRM] Brian Marshall - Calgary - bmarshal@agt.net
//
//  14/07/13  [BRM] included 
//  08/07/09  [BRM] new random_num(), logging, is_one_chance_in_x()
//                  multiple small changes
//  05/11/07  [BRM] random_num() now in class aipBase 
//  05/11/01  [BRM] added aip_strncpy() that always terminates string
//  05/09/10  [BRM] development began
//
//----------------------------------------------------------------------

#include "aipBase.h"

#include <string.h>
#include <iostream>
#include <stdlib.h>

using namespace std;

//======================================================================
//  Definition of static members

aipRand  aipBase::m_rand;   // random number generator

aipLogger  * aipBase::m_logger = 0;   // optional logger

//======================================================================
//  Global functions
//
//----------------------------------------------------------------------
//  strncpy that terminates the string, returns length

int aip_strncpy (char *dest, const char *src, int max_len) {

  strncpy (dest, src, max_len);
  dest[max_len] = '\0';

  return strlen(dest);

}

//----------------------------------------------------------------------
//  Get a string from string x and write it to val.
//
//  One or more sequential delimiters starting at x are ignored.
//  The string ends just before the terminating delimiter, and a
//  pointer to this delimiter is returned (or zero on failure).
//
//  If the specified delimiter is '~', any character other than
//  a letter or digit will be a delimiter.
//
//  The string will not be longer than maxlen (up to 100).

const char * aip_get_str (const char *x, long maxlen, 
                          char *str, char delim) {

  if (maxlen <  1) return 0;
  if (maxlen > 100) maxlen = 100;

  *str = '\0';
  int slen = 0;

  if (!x) return 0;

  while (1) {
      if ( aip_is_delim(*x,delim) ) {
      if (!slen) {
        x++;
        continue;   // skip over leading delimiters
      } else {
        break;      // found end of string
      }
    }
    if (slen < maxlen) {
      *str++ = *x;
      slen++;
    }
    x++;
  }
  *str = '\0';

  if (!slen) return 0;  // string was not found

  return x;   // last character read from x

}

//----------------------------------------------------------------------
//  Get an long value from string x and write it to val.
//
//  One or more sequential delimiters starting at x are ignored.
//  The string ends just before the terminating delimiter, and a
//  pointer to this delimiter is returned (or zero on failure).
//
//  If the specified delimiter is '~', any character other than
//  a letter or digit will be a delimiter.

const char * aip_get_val (const char *x, long maxlen, 
                          long *val, char delim) {

  char buf[21];
  const char *last_char = aip_get_str (x, 20, buf, delim);
  if (!last_char) return 0;

  if (maxlen < 10) buf[maxlen] = '\0';

  *val = atol(buf);

  return last_char;

}

//----------------------------------------------------------------------
//  Return true if x is a delimiter character.  If delim is '~', 
//  any char other than a letter or digit is a delimiter.

int aip_is_delim (char x, char delim) {

  if (delim == '~') {
    if ( !( (x >= '0' && x <= '9') ||
            (x >= 'A' && x <= 'Z') ||
            (x >= 'a' && x <= 'z') ) ) return 1;
  } else {
    if (x == delim || x == '\0' || x == '\n') return 1;
  }

  return 0;

}

//======================================================================
//  aipRand
//
//----------------------------------------------------------------------
//  sub-random-number-generator -
//  Return a pseudo-random number from the set [0,1,2,3,...,9999].
//
//  This function can be used to implement 11 different sub-rngs -
//  for each parameter, there is an array with 11 values.  At any
//  time, there are two sub-rngs - rand_1() calls this function
//  and uses the first set of parameters; rand_2() calls this
//  function and uses one of the remaining 10 sets of parameters.
//
//  rand_1() and rand_2() produce low-quality random numbers;
//  combining them produces a better quality of random numbers.

long aipRand::sub_rng (long idx) {

  if (idx < 0) idx = 0;
  if (idx >= Num_Sub_RNG) idx = Num_Sub_RNG - 1;

  long  a = Rand_a[idx];
  long  c = Rand_c[idx];
  long  m = 10000;

  long x;
  if (idx == 0) {  // for rand_1()
    x = m_rand_seed_1 = (a * m_rand_seed_1 + c) % m;
  } else {         // for rand_2()
    x = m_rand_seed_2 = (a * m_rand_seed_2 + c) % m;
  }

  return x;

}

//----------------------------------------------------------------------
//  first sub-RNG (that does not change)

long  aipRand::rand_1 () {

  return sub_rng(0);

}

//----------------------------------------------------------------------
//  second sub-RNG (that changes periodically)

long  aipRand::rand_2 () {

  if (m_rand_2_idx < 1) m_rand_2_idx = 1;
  if (m_rand_2_idx >= Num_Sub_RNG) m_rand_2_idx = Num_Sub_RNG - 1;

  return sub_rng(m_rand_2_idx);

}

//----------------------------------------------------------------------
//  return a pseudo-random number in the range 0 to 9999 inclusive
//
//  Two low-quality random number are generated, with sub-RNGs
//  rand_1() and rand_2(), and combined to make a better-quality 
//  random number.  
//
//  After this function is called a certain number of times, 
//  the following static members are changed:
//    - which set of parameters, including the starting seed,
//         used by rand_2() is randomly changed
//    - number of calls until we do this again is randomly set

long aipRand::random_num () {

  if (m_rand_2_idx < Rand_Null_Test) {    // initial setup
    m_rand_2_idx = 1;
    m_rand_count = 500;
    m_rand_seed_1 = Rand_s[0];
    m_rand_seed_2 = Rand_s[m_rand_2_idx];
    for (int i=0; i<100; i++) {
      m_deck[i] = rand_1();
    }
    m_deck_len = 100;
  }

  if ( --m_rand_count <= 0 ) {  // use different sub-RNG in rand_2()
    m_rand_2_idx = (rand_1() * (Num_Sub_RNG-1)) / 10000 + 1;
    m_rand_count = 300 + ( (rand_1()*500) / 10000 );
    m_rand_seed_2 = Rand_s[m_rand_2_idx];
  }


  long j = rand_2() / 100;
  long x = m_deck[j];
  m_deck[j] = rand_1();
  return x;

}

//======================================================================
//  aipBase  -  return a pseudo-random number in the range 0 to 9999
//
//----------------------------------------------------------------------
//  return a pseudo-random number in the range 0 to 9999

long aipBase::random_num () {

  return m_rand.random_num ();

}

//----------------------------------------------------------------------
//  return a pseudo-random number in the specified range

long aipBase::random_num (long lo, long hi) {

  if (lo == hi) return lo;

  if (lo > hi) { long temp_flip = lo; lo = hi; hi = temp_flip; }

  if ( (hi-lo) > 100000 ) hi = lo + 100000 + 1;

  long x = ( random_num() * ((hi-lo)+1) ) / 10000 + lo;

  return x;

}


//----------------------------------------------------------------------
//  Return true 1 in x times, otherwise return false.

int aipBase::is_one_chance_in_x (long x) {

  if (x < 2) return 1;
  if (x > 100000) return 0;

  return (random_num(1,x)==1) ? 1 : 0;

}


//----------------------------------------------------------------------
//  Write a character string to the log (generally for debugging)

void aipBase::log (const char *x) const {

  if (m_logger) {
    m_logger->log(x);
  } else {
    cout << x;
  }

}

//----------------------------------------------------------------------
//  Write a double to the log (generally for debugging)

void aipBase::log (double x) const {

  if (m_logger) {
    m_logger->log(x);
  } else {
    cout << x;
  }

}

//----------------------------------------------------------------------
//  Write a long to the log (generally for debugging)

void aipBase::log (long x) const {

  if (m_logger) {
    m_logger->log(x);
  } else {
    cout << x;
  }

}

//======================================================================
//  aipMsg
//
//----------------------------------------------------------------------
//  Constructor

aipMsg::aipMsg(short t, short st, aipG g) { set(t, st, g); }

//----------------------------------------------------------------------
//  Destructor

aipMsg::~aipMsg () {}

//----------------------------------------------------------------------
//  set the goodness

void aipMsg::set (aipG g) { m_g = g; }

//----------------------------------------------------------------------
//  set the private variables

void aipMsg::set (short t, short st, aipG g) { 

  m_typ    = t;  
  m_subtyp = st;  
  m_g      = g;

}

//======================================================================
//  aipFileLogger  - not tested
//
//----------------------------------------------------------------------
//  Constructor

aipFileLogger::aipFileLogger (const char *file_name) {

  m_stream = fopen (file_name, "w");

}

//----------------------------------------------------------------------
//  Destructor

aipFileLogger::~aipFileLogger () {

  if (m_stream) fclose(m_stream);

}

//----------------------------------------------------------------------
//  is_valid

int aipFileLogger::is_valid () {

  return (m_stream ? 1 : 0);

}

//----------------------------------------------------------------------
//  write a string

void aipFileLogger::log (const char *x) {

  if (!is_valid() || !x) return;

  fprintf (m_stream, "%s", x);

}

//----------------------------------------------------------------------
//  write a double value

void aipFileLogger::log (double x) {

  if (!is_valid()) return;

  fprintf (m_stream, "%f", x);

}

//----------------------------------------------------------------------
//  write a long value

void aipFileLogger::log (long x) {

  if (!is_valid()) return;

  fprintf (m_stream, "%ld", x);

}

//======================================================================
//  aipStringLogger
//
//----------------------------------------------------------------------
//  Constructor

aipStringLogger::aipStringLogger (long max_len) {

  if (max_len < 1 || max_len > 10000) { m_max_len = 0; return; }

  m_str = new char[max_len+1];
  if (!m_str) { m_max_len = 0; return; }

  m_str_len = 0;
  m_max_len = max_len;

}

//----------------------------------------------------------------------
//  Destructor

aipStringLogger::~aipStringLogger () {

  if (m_str) delete m_str;

}

//----------------------------------------------------------------------
//  is_valid

int aipStringLogger::is_valid () {

  return (m_max_len>0 ? 1 : 0);

}

//----------------------------------------------------------------------
//  write a string

void aipStringLogger::log (const char *x) {

  if (!is_valid() || !x || *x=='\0') return;

  long max_wrt = m_max_len - m_str_len;
  if (max_wrt <= 0) return;

  long xlen = strlen(x);
  if (xlen > max_wrt) xlen = max_wrt;

  aip_strncpy (m_str+m_str_len, x, xlen);  // add to end

  m_str_len += xlen;

}

//----------------------------------------------------------------------
//  write a double value

void aipStringLogger::log (double x) {

  if (!is_valid()) return;

  char buf[31];
  sprintf (buf, "%f", x);

  log(buf);

}

//----------------------------------------------------------------------
//  write a long value

void aipStringLogger::log (long x) {

  if (!is_valid()) return;

  char buf[31];
  sprintf (buf, "%ld", x);

  log(buf);

}

//======================================================================
//                           License
//
//   Permission is hereby granted, free of charge, to any 
//   person obtaining a copy of this software and associated 
//   documentation files (the "Software"), to deal in the Software 
//   without restriction, including without limitation the rights 
//   to use, copy, modify, merge, publish, distribute, sublicense, 
//   and/or sell copies of the Software, and to permit persons to 
//   whom the Software is furnished to do so, subject to the 
//   following conditions:
//
//   The copyright notice and this license shall be included in all 
//   copies or substantial portions of the Software.
//
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
//   NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
//   OTHER DEALINGS IN THE SOFTWARE.
//
//
//**********************************************************************