//
// new 08-20-11 (jdl).  Mersenne Twister, made into a class with some member functions I want.
//
//
// Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura, All rights reserved.                          
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the 
//      following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the 
//      following disclaimer in the documentation and/or other materials provided with the distribution.
//
//   3. The names of its contributors may not be used to endorse or promote products derived from this software 
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
//
//
//
//
//
//
//


#ifdef NEED_PCH
   #include "pch.h"
#else
   #include "stdafx.h"
#endif // !NEED_PCH

#include "time.h"



#include "globs.h"
#include "sha1.h"
#include "math.h"
#include "mt64.h"
#include <chrono>
#include <thread>
#include <string>

#ifdef _WIN32
#include <windows.h>
#include <process.h>
#include <conio.h>
#include "mmsystem.h"
#else
#define _kbhit kbhit
#define _getch getch
#endif // !_WIN32



#ifndef MAX
#define MAX(A, B)         ((A) > (B) ? (A) : (B))
#define MA3(A, B, C)      (MAX((MAX((A),(B))),(C)))
#define MA4(A, B, C, D)   (MAX((MAX((A),(B))),(MAX((C),(D)))))
#define MIN(A, B)         ((A) < (B) ? (A) : (B))
#define MI3(A, B, C)      (MIN((MIN((A),(B))),(C)))
#define MI4(A, B, C, D)   (MIN((MIN((A),(B))),(MIN((C),(D)))))
#endif // MAX


int MT64::m_nAllCalls = 0;




// qxbitVal()

static int bitVal(const unsigned long long &iGuy, int iBit) {
   unsigned long long ullMask = 1LL << iBit;
   return ((iGuy & ullMask) != 0);
} // end of bitVal()...





//
// New 06-10-13 (jdl)
//
//
// Note: caller must ensure everybody in range; we do NOT check (we're intended to be fast, inner call).  qxl: inline?
//
//
//
//
//
// qxswap2Bits()
//

static int swap2Bits(unsigned long long *ullArray, int elem0, int bit0, int elem1, int bit1) {

   // sanity check:
   if((elem0 == elem1) && (bit0 == bit1))
      return 0;                              // silly situation, but we succeeded in doing nothing, as asked.


   int bitval0 = bitVal(ullArray[elem0], bit0);
   int bitval1 = bitVal(ullArray[elem1], bit1);

   if(bitval0 == bitval1) {
      // nothing to do!
   } else {
      // swap, which means exor each bit.
      unsigned long long mask0 = 1LL << bit0;
      unsigned long long mask1 = 1LL << bit1;
      ullArray[elem0] ^= mask0;
      ullArray[elem1] ^= mask1;
   } // !if(bitval0 == bitval1)


   return 0;
} // static int swap2Bits(unsigned long long *ullArray, int elem0, int bit0, int elem1, int bit1)





//
//
//
//
//
//
//
// qxrescrambleVector()
//

int MT64::rescrambleVector(std::vector<unsigned long long> &inOut, int nCycle) {
   if(inOut.size() != 10)
      return -1;

   unsigned char *pio = (unsigned char *)(&inOut[0]);

   for(int i=0; i<nCycle; i++) {

      // feed this into hash.  We feed in changes as we go:
      CSHA1 aCsp;
      for(int ii=0; ii<4; ii++) {
         aCsp.Reset();
         for(int jj=0; jj<ii+4; jj++) {
            aCsp.Update(pio, 80);
         } // for(int jj=0; jj<ii+4; jj++)
         aCsp.Final();
         unsigned char *pucWalk = pio + 20*ii;       // stagger.  Not really random w/ respect to each other, but not bad!
         aCsp.GetHash(pucWalk);
      } // for(int ii=0; ii<256; ii++)
   } // for(int i=0; i<nCycle; i++)



   return 0;
} // int rescrambleVector(std::vector<unsigned long long> &inOut)






//
//
// Input:
//    cData, datLen: password-like data.  This is NOT a null-terminated string; pass in datLen to use.
//
// Output:
//    fillMe: filled with 10 unsigned long long's.  80 bytes of quasi-random data.  Use to call MT64::init_by_array64().
//
//
//
// 09-22-11 (jdl): change from static free function to static member function.
//
// qxbytesToVector()
//

void MT64::bytesToVector(const unsigned char *cData, int datLen, std::vector<unsigned long long> &fillMe) {
   fillMe.resize(10);                              // 10 unsigned long long's, each 64 bits, or 640 bits.  80 bytes.
   unsigned char *pucFill = (unsigned char *)(&fillMe[0]);

   // qprintf(fp_inf, "Fairly early in bytesToVector() with datLen %d.\n", datLen); qflush(fp_inf); // qxtemp

   // feed this into hash:
   CSHA1 aCsp;
   // qprintf(fp_inf, "declared CSHA1.\n"); qflush(fp_inf); // qxtemp
   for(int ii=0; ii<4; ii++) {
      aCsp.Reset();
      // qprintf(fp_inf, "Reset on iteration %d\n", ii); qflush(fp_inf); // qxtemp
      for(int jj=0; jj<ii+4; jj++) {
         aCsp.Update(cData, datLen);
         // qprintf(fp_inf, "Update on iteration %d\n", jj); qflush(fp_inf); // qxtemp         
      } // for(int jj=0; jj<ii+4; jj++)
      // qprintf(fp_inf, "Before Final().\n"); qflush(fp_inf);  // qxtemp      
      aCsp.Final();
      // qprintf(fp_inf, "Back from Final().\n"); qflush(fp_inf);  // qxtemp
      unsigned char *pucWalk = pucFill + 20*ii;       // stagger.  Not really random w/ respect to each other, but not bad!
      aCsp.GetHash(pucWalk);
      // qprintf(fp_inf, "Back from GetHash().\n"); qflush(fp_inf);  // qxtemp
   } // for(int ii=0; ii<4; ii++)

   // qprintf(fp_inf, "Ready to leave bytesToVector()...\n"); qflush(fp_inf);
   return;
} // end of static void bytesToVector(const unsigned char *cData, int datLen, std::vector<unsigned long long> &fillMe)






//
//
// Input:
//    cData, datLen: password-like data.  This is NOT a null-terminated string; pass in datLen to use.
//
// Output:
//    fillMe: filled with 10 unsigned long long's.  80 bytes of quasi-random data.  Use to call MT64::init_by_array64().
//    fillM2: filled with 10 unsigned long long's.  80 bytes of quasi-random data.  Use to call MT64::init_by_array64().
//    nCycle: number of times to cycle for the slow guy.
//
//
//
// 09-22-11 (jdl): change from static free function to static member function.
// 01-06-15 (jdl): fillM2: takes longer to form.
// 10-25-23 (jdl): nCycle.
//
// qxbytesToVector()
//

void MT64::bytesToVector(const unsigned char *cData, int datLen, std::vector<unsigned long long> &fillMe, std::vector<unsigned long long> &fillM2, int nCycle) {

   // fast guy:
   bytesToVector(cData, datLen, fillMe);

   // slow guy:
   fillM2 = fillMe;
   for(int i=0; i<nCycle; i++) {
      rescrambleVector(fillM2);
   } // for(int i=0; i<nCycle; i++)

   return;
} // end of static void bytesToVector(const unsigned char *cData, int datLen, std::vector<unsigned long long> &fillMe)




MT64::MT64(bool bNoInit)
   : m_mti(NN+1)   // mti==NN+1 means mt[NN] is not initialized
   , m_nCallsSinceInit(0)

{
   if(!bNoInit) {
     // get ahold of a seed and use it:
      std::vector<unsigned long long> ull0;
      MT64::getAutoSeed(ull0);
      init_by_array64(&(ull0[0]), ull0.size());
   } // if(!bNoInit)

} // end of default MT64 constructor...



MT64::MT64(unsigned long long seed)
   : m_mti(NN+1)   // mti==NN+1 means mt[NN] is not initialized
   , m_nCallsSinceInit(0)

{

   init_genrand64(seed);
} // end of long long MT64 constructor...



MT64::MT64(const unsigned long long init_key[], unsigned long long key_length)

   : m_mti(NN+1)   // mti==NN+1 means mt[NN] is not initialized
   , m_nCallsSinceInit(0)

{

   init_by_array64(init_key, key_length);
} // end of array'd MT64 constructor...




MT64::MT64(const MT64 &rs) {
   m_mti = rs.m_mti;
   m_nCallsSinceInit = rs.m_nCallsSinceInit;
   for(int i=0; i<NN; i++) {
      m_mt[i] = rs.m_mt[i];
   } // for(int i=0; i<NN; i++)
} // end of MT64 copy constructor...




// 08-18-25: zero out memory on destruction.

MT64::~MT64() {
   // nothing to be done.  No memory to be freed that won't be freed automatically.

   for(int i=0; i<NN; i++)
      m_mt[i] = 0;

   m_mti = m_nCallsSinceInit = 0;

   return;
} // end of MT64 destructor...





const MT64 &MT64::operator=(const MT64 &rs) {
   if(this != &rs) {
      m_mti = rs.m_mti;
      m_nCallsSinceInit = rs.m_nCallsSinceInit;
      for(int i=0; i<NN; i++) {
         m_mt[i] = rs.m_mt[i];
      } // for(int i=0; i<NN; i++)
   } // if(this != &rs)

   return *this;
} // end of MT64::operator=(const MT64 &rs)...






//
// initializes mt[NN] with a seed 
//
// qxinit_genrand64()
//

void MT64::init_genrand64(unsigned long long seed) {

   m_mt[0] = seed;
   for(m_mti=1; m_mti<NN; m_mti++) {
      m_mt[m_mti] =  (6364136223846793005ULL * (m_mt[m_mti-1] ^ (m_mt[m_mti-1] >> 62)) + m_mti);
   } // for(m_mti=1; m_mti<NN; m_mti++)

   m_nCallsSinceInit = 0;
   return;
} // end of void MT64::init_genrand64(unsigned long long seed)...



//
// initializes mt[NN] with a seed 
//
//
//
//
// qxinit_genrand32()
//

void MT64::init_genrand32(unsigned int seed) {
   std::vector<unsigned long long> fillMe;


   bool bDbg = false;
   if(bDbg) {
      qprintf(fp_dbg, "\ngenrand32() seed in: %0lX.\n", seed);
      bytesToVector((const unsigned char *)(&seed), sizeof(seed), fillMe);
      for(int i=0; i<(int)fillMe.size(); i++) {
         qprintf(fp_dbg, "%0llX ", fillMe[i]);
      } // for(int i=0; i<(int)fillMe.size(); i++)
      qprintf(fp_dbg, "\n");
   } else {
      bytesToVector((const unsigned char *)(&seed), sizeof(seed), fillMe);
   } // !if(bDbg)



   this->init_by_array64(&(fillMe[0]), fillMe.size());

   m_nCallsSinceInit = 0;
   return;
} // end of void MT64::init_genrand32(unsigned int seed)...




//
// initialize by an array with array-length.  init_key is the array for initializing keys; key_length is its length:
//
//
//
// qxinit_by_array64()
//

void MT64::init_by_array64(const unsigned long long init_key[], unsigned long long key_length) {

   unsigned long long i, j, k;
   init_genrand64(19650218ULL);
   i=1; j=0;
   k = (NN>key_length ? NN : key_length);
   for (; k; k--) {
      m_mt[i] = (m_mt[i] ^ ((m_mt[i-1] ^ (m_mt[i-1] >> 62)) * 3935559000370003845ULL))
        + init_key[j] + j; /* non linear */
      i++; j++;
      if (i>=NN) { m_mt[0] = m_mt[NN-1]; i=1; }
      if (j>=key_length) j=0;
   }
   for (k=NN-1; k; k--) {
      m_mt[i] = (m_mt[i] ^ ((m_mt[i-1] ^ (m_mt[i-1] >> 62)) * 2862933555777941757ULL))
        - i; /* non linear */
      i++;
      if (i>=NN) { m_mt[0] = m_mt[NN-1]; i=1; }
   }

   m_mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */ 

   m_nCallsSinceInit = 0;
   return;
} // end of void MT64::init_by_array64(unsigned long long init_key[], unsigned long long key_length)...



//
// new 11-15-16
//
//
//
// qxinit_by_otherMT64()

void MT64::init_by_otherMT64(const MT64 &otherMT64) {
   std::vector<unsigned long long> anLLSeed;
   otherMT64.getSeedFromState(anLLSeed);
   this->init_by_array64(&(anLLSeed[0]), anLLSeed.size());

   return;
} // void MT64::init_by_otherMT64(const MT64 &otherMT64)





// generates a random number on [0, 2^64-1]-interval
//
//
//
// qxgenrand64_int64()
//

unsigned long long MT64::genrand64_int64(void) {

   int i;
   unsigned long long x;
   static unsigned long long mag01[2]={0ULL, MATRIX_A};
   m_nCallsSinceInit++;    // for this instance
   m_nAllCalls++;          // for all instances

   if (m_mti >= NN) { /* generate NN words at one time */

      /* if init_genrand64() has not been called, */
      /* a default initial seed is used     */
      if (m_mti == NN+1) 
         init_genrand64(5489ULL); 

      for (i=0;i<NN-MM;i++) {
         x = (m_mt[i]&UM)|(m_mt[i+1]&LM);
         m_mt[i] = m_mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
      }
      for (;i<NN-1;i++) {
         x = (m_mt[i]&UM)|(m_mt[i+1]&LM);
         m_mt[i] = m_mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
      }
      x = (m_mt[NN-1]&UM)|(m_mt[0]&LM);
      m_mt[NN-1] = m_mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];

      m_mti = 0;
   }
  
   x = m_mt[m_mti++];

   x ^= (x >> 29) & 0x5555555555555555ULL;
   x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
   x ^= (x << 37) & 0xFFF7EEE000000000ULL;
   x ^= (x >> 43);

   return x;
} // end of unsigned long long MT64::genrand64_int64(void)...




//
// generates a random number on [0, 2^63-1]-interval
//
//
//
// qxgenrand64_int63()
//

long long MT64::genrand64_int63(void) {

   return (long long)(genrand64_int64() >> 1);
} // end of long long MT64::genrand64_int63(void)...




//
// generates a random number on [0, 2^32-1]-interval
//
//
//
// qxgenrand64_int32()
//

unsigned int MT64::genrand64_int32(void) {

   return (unsigned int)(genrand64_int64() >> 32);
} // end of long long MT64::genrand64_int32(void)...




//
// generates a random number on [0, 2^31-1]-interval
//
//
//
// qxgenrand64_int31()
//

int MT64::genrand64_int31(void) {

   return (int)(genrand64_int64() >> 33);
} // end of long long MT64::genrand64_int31(void)...





//
// generates a random number on [0,1]-real-interval
//
//
//
// qxgenrand64_real1()
//

double MT64::genrand64_real1(void) {

   return (genrand64_int64() >> 11) * (1.0/9007199254740991.0);
} // double MT64::genrand64_real1(void)...




// generates a random number on [0,1)-real-interval
//
//
//
// qxgenrand64_real2()
//

double MT64::genrand64_real2(void) {

    return (genrand64_int64() >> 11) * (1.0/9007199254740992.0);
} // double MT64::genrand64_real2(void)...




// generates a random number on (0,1)-real-interval
//
//
//
// qxgenrand64_real3()
//

double MT64::genrand64_real3(void) {

    return ((genrand64_int64() >> 12) + 0.5) * (1.0/4503599627370496.0);
} // double MT64::genrand64_real3(void)...





//
// gives slightly uneven results; always makes exactly one call to core function.
//
//
// Input:
//    zeroToMeMinusOne: range of output values desired.
//
// Output:
//    return value: [0, zeroToMeMinusOne-1]
//
//
//
// qxrand_n_quick()
//

unsigned int MT64::rand_n_quick(unsigned int zeroToMeMinusOne) {
   // sanity check:
   if(zeroToMeMinusOne < 2)
      return 0;

   unsigned long long ullRand = this->genrand64_int64();
   unsigned int ulRet = ullRand % zeroToMeMinusOne;


   return ulRet;
} // end of unsigned int MT64::rand_n_quick(unsigned int zeroToMeMinusOne)...
        
        
        



//
// gives uniform results; may make two or more calls to core function.
//
//
// Input:
//    zeroToMeMinusOne: range of output values desired.
//
// Output:
//    return value: [0, zeroToMeMinusOne-1]
//
//
//
//
// qxrand_n_fancy()
//

unsigned int MT64::rand_n_fancy(unsigned int zeroToMeMinusOne) {
   // sanity check:
   if(zeroToMeMinusOne < 2)
      return 0;

   unsigned long long ullDiv  = MAX_ULL / zeroToMeMinusOne;
   unsigned long long ullMult = ullDiv * zeroToMeMinusOne;    // probably slightly less than MAX_ULL

   unsigned long long ullRand = MAX_ULL;

   while(ullRand >= ullMult) {
      // this is the zone where unevenness happens; get another sample:
      ullRand = this->genrand64_int64();
   } // while(ullRand >= ullMult)

   unsigned int ulRet = ullRand % zeroToMeMinusOne;

   return ulRet;
} // unsigned int MT64::rand_n_fancy(unsigned int zeroToMeMinusOne)...
        
        
        






//
// using hash, fills 10 64-bit guys for use as seed.  80 bytes.  qxl: randomize w/ files on disk.
//
// this is a static function.
//
// Input:
//   fillMe: we'll overwrite its contents.
// //   pTime (default NULL): if non-NULL and non-zero pointed to, use for time(0) value.
// //   pTGT  (default NULL): if non-NULL and non-zero pointed to, use for timeGetTime() value.
//
//
// Output:
//   return value: 0.
//   fillMe: 640 quasi-random bits filled in, as 10 64-bit unsigned long long's.
// //   pTime: if not passed in NULL (default), fill in time(0) return.
// //   pTGT:  if not passed in NULL (default), fill in timeGetTime() return.
//
//
// WARNING: for this to work "normally", pTime and pTGT should be NULL, or if either or both is not, values
// pointed to should be zero!
//
//
// 11-02-19 (jdl): bring in chrono function(s); get rid of defunct optional outputs.
// 11-07-19 (jdl): use chrono function(s) better.
//
// qxgetAutoSeed()
//

int MT64::getAutoSeed(std::vector<unsigned long long> &fillMe) { // , unsigned int *pTime, unsigned int *pTGT) {
   fillMe.resize(10);                              // 10 unsigned long long's, each 64 bits, or 640 bits.

   unsigned long long t0 = time(0);                // seconds since some time in 1970's

#ifdef _WIN32
   unsigned long long tgt = timeGetTime();         // milliseconds since Windows was started.
   std::chrono::steady_clock::time_point now = std::chrono::high_resolution_clock::now();
   std::chrono::steady_clock::time_point nonInit;

   auto dift = now - nonInit;
   unsigned long long no2 = dift.count();


   unsigned long long hii = no2 / 1000000;
   unsigned long long low = no2 % 1000000;
   unsigned long long temp =  t0 * hii     +    low;

   bytesToVector((const unsigned char *)(&temp), sizeof(temp), fillMe);
#else 
   struct timespec ts1, ts2, ts3, ts4;
   int i1 = clock_getres(CLOCK_REALTIME, &ts1);
   qprintf(fp_dbg, "CLOCK_REALTIME: %lld seconds, %lld nanoseconds.\n", ts1.tv_sec, (long long)ts1.tv_nsec);
   
   int i2 = clock_getres(CLOCK_MONOTONIC, &ts2);
   qprintf(fp_dbg, "CLOCK_MONOTONIC: %lld seconds, %lld nanoseconds.\n", ts2.tv_sec, (long long)ts2.tv_nsec);
   
   int i3 = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts3);
   qprintf(fp_dbg, "CLOCK_PROCESS_CPUTIME_ID: %lld seconds, %lld nanoseconds.\n", ts3.tv_sec, (long long)ts3.tv_nsec);
   
   int i4 = clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts4);
   qprintf(fp_dbg, "CLOCK_THREAD_CPUTIME_ID: %lld seconds, %lld nanoseconds.\n", ts4.tv_sec, (long long)ts4.tv_nsec);
   
   qprintf(fp_dbg, "return values %d %d %d %d.\n", i1, i2, i3, i4);
   
   int j1 = clock_gettime(CLOCK_REALTIME, &ts1);
   qprintf(fp_dbg, "CLOCK_REALTIME: %lld seconds, %lld nanoseconds.\n", ts1.tv_sec, (long long)ts1.tv_nsec);
   
   int j2 = clock_gettime(CLOCK_MONOTONIC, &ts2);
   qprintf(fp_dbg, "CLOCK_MONOTONIC: %lld seconds, %lld nanoseconds.\n", ts2.tv_sec, (long long)ts2.tv_nsec);
   
   int j3 = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts3);
   qprintf(fp_dbg, "CLOCK_PROCESS_CPUTIME_ID: %lld seconds, %lld nanoseconds.\n", ts3.tv_sec, (long long)ts3.tv_nsec);
   
   int j4 = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts4);
   qprintf(fp_dbg, "CLOCK_THREAD_CPUTIME_ID: %lld seconds, %lld nanoseconds.\n", ts4.tv_sec, (long long)ts4.tv_nsec);
   
   qprintf(fp_dbg, "return values %d %d %d %d.\n", j1, j2, j3, j4);

   unsigned long long ulla[2];
   qprintf(fp_dbg, "size of ulla: %d.\n", sizeof(ulla));
   // qprintf(fp_std, "ulla size: %d.\n", (int)ulla.size());
   
   ulla[0] = ts1.tv_sec;
   ulla[1] = ts1.tv_nsec;
   
   // bytesToVector((const unsigned char *)(&t0), sizeof(t0), fillMe);   // qxfix!  For Linux.
   bytesToVector((const unsigned char *)(&ulla), sizeof(ulla), fillMe);
#endif // !_WIN32    

   return 0;
} // end of int MT64::getAutoSeed(std::vector<unsigned long long> &fillMe)...






//
// new 01-25-16.  Not static.  Gets a seed from the current internal state (for use with another instance, perhaps).
//
//
//
//
//
// qxgetSeedFromState()
//

int MT64::getSeedFromState(std::vector<unsigned long long> &fillMe) const {

   int nBytesInM_mt = NN * sizeof(unsigned long long);

   bytesToVector((const unsigned char *)m_mt, nBytesInM_mt, fillMe);

   return 0;
} // int MT64::getSeedFromState(std::vector<unsigned long long> &fillMe) const





//
// new 08-22-11, from randd.cpp version.
//
// Input:
//    this: ready to be re-initialized from password
//    [user types password, followed by Enter]
//
//
// Output:
//    this: initialized from password.
//
//
//
// qxrandFromPwd()
//

int MT64::randFromPwd(void) {
   std::vector<unsigned long long> fillMe;

   getSeedFromPwd(fillMe);

   this->init_by_array64(&(fillMe[0]), fillMe.size());

   return 0;
} // end of randFromPwd()



//
// new 08-23-11, from free function in jgraph.cpp.
//
// Input:
//    cInOut: array of UCHAR to scramble or unscramble.
//    nDo: number of bytes (UCHAR's) to scramble/unscramble.
//    nConserv (default false): if true, fewer calls to expensive MT64 functions.
//
//
// Output:
//    cInOut: modified "randomly" so as to be unrecognizeable, or to restore sense.
//
//
//
// 05-08-25: bConserv (default false).
//
// qxscramUnscram()
//

int MT64::scramUnscram(UCHAR *cInOut, int nDo, bool bConserv) {
   int i;

   if(nDo <= 0) return -1;

   if(!bConserv) {
      for(i=0; i<nDo; i++) {
         UCHAR iOld = cInOut[i];
         UCHAR iRand= (UCHAR)(this->genrand64_int32() & 0xFF);    // 0 .. 255
         UCHAR iNew = iOld ^ iRand;   // exclusive-or
         cInOut[i]  = iNew;
      } // for(i=0; i<nDo; i++)
   } else {
      // bConserv, new 05-08-25
#ifdef BRIEFLY_25_05_08
      BitSrc aBtS;
      for(i=0; i<nDo; i++) {
         UCHAR iOld = cInOut[i];
         UCHAR iRand= (UCHAR)(aBtS.getNbits(8, this));
         UCHAR iNew = iOld ^ iRand;   // exclusive-or
         cInOut[i]  = iNew;
      } // for(i=0; i<nDo; i++)
#endif // BRIEFLY_25_05_08

      // new 05-09-25
      unsigned long long *pull = (unsigned long long *)cInOut;
      int n64 = nDo / 8;
      int xtr = nDo % 8;
      for(int i=0; i<n64; i++) {
         unsigned long long ullOld = pull[i];
         unsigned long long ullrnd = this->genrand64_int64();
         unsigned long long ullnew = ullOld ^ ullrnd;
         pull[i]                   = ullnew;
      } // for(int i=0; i<n64; i++)

      if(xtr > 0) {
         BitSrc aBtS;
         int ioff = n64 * 8;
         for(int i=0; i<xtr; i++) {
            int j = i + ioff;
            UCHAR iOld = cInOut[j];
            UCHAR iRand= (UCHAR)(aBtS.getNbits(8, this));
            UCHAR iNew = iOld ^ iRand;   // exclusive-or
            cInOut[j]  = iNew;
         } // for(int i=0; i<xtr; i++)
      } // if(xtr > 0) 
   } // !if(!bConserv)

   return 0;
} // end of scramUnscram()




//
// new 06-10-13 (jdl)
//
// Input:
//    pFromMe (default NULL): if non-NULL, use pFromMe to scramble "this"; otherwise, use a copy of "this".
//
// Output:
//    "this" is scrambled.
//
//
//
// Notes: 1/0 madness: if we have 52 cards, designated [0 .. 51], we want to START with 52 possible values.
// Is it better to walk holding 52, then reference 0 .. n-1?  Yes.
//
//
//
//
//
//
// qxshuffleMe()
//

int MT64::shuffleMe(MT64 *pFromMe) {
   bool bDidAllocate = false;
   if(pFromMe == NULL) {
      pFromMe = new MT64(*this);
      bDidAllocate = true;
   } // if(pFromMe == NULL)

   for(int iWalk=BITS_PER_ULL*NN; iWalk>0; iWalk--) {
      int iSwap = iWalk - 1;
      int jSwap = pFromMe->rand_n_fancy(iWalk);     // 0 .. iWalk-1

      if(jSwap == iSwap)
         continue;                                  // this guy doesn't move.

      int index0 = iSwap / BITS_PER_ULL;
      int offst0 = iSwap % BITS_PER_ULL;
      int index1 = jSwap / BITS_PER_ULL;
      int offst1 = jSwap % BITS_PER_ULL;
      int i      = swap2Bits(m_mt, index0, offst0, index1, offst1);
   } // for(int iWalk=BITS_PER_ULL*NN; iWalk>0; iWalk--)


   if(bDidAllocate) {
      delete pFromMe; pFromMe=NULL;
   } // if(bDidAllocate)

   return 0;
} // end of int MT64::shuffleMe(MT64 *pFromMe)..






//
// from random32, which got it from:
// From http://java.sun.com/j2se/1.4.2/docs/api/java/util/Random.html
//
// Returns the next pseudorandom, Gaussian ("normally") distributed double value with mean 0.0 and standard deviation 1.0 from this random number generator's sequence.
//
//
//
//
//
// qxNextGaussian()
//

double MT64::NextGaussian() {
   static double nextNextGaussian = 0.0;
   static bool bHaveNextNextGaussian = false;
   if (bHaveNextNextGaussian) {
      bHaveNextNextGaussian = false;
      return nextNextGaussian;
   } else {
      double v1, v2, s;
      do { 
         v1 = 2.0 * this->realcc() - 1.0;   // between -1.0 and 1.0
         v2 = 2.0 * this->realcc() - 1.0;   // between -1.0 and 1.0
         s = v1 * v1 + v2 * v2;
      } while (s >= 1.0 || s == 0.0);
      double multiplier = sqrt(-2.0 * log(s)/s);
      nextNextGaussian = v2 * multiplier;
      bHaveNextNextGaussian = true;
      return v1 * multiplier;
   } // !if (bHaveNextNextGaussian)
} // end of NextGaussian()...






