Merge remote-tracking branch 'cppcooper/cxxrandom-rel' into develop
						commit
						862fa08ba6
					
				| @ -0,0 +1,311 @@ | |||||||
|  | /* Plugin for exporting C++11 random number functionality
 | ||||||
|  | *Exports functions for random number generation | ||||||
|  | *Functions: | ||||||
|  | - seedRNG(seed) | ||||||
|  | - rollInt(min, max) | ||||||
|  | - rollDouble(min, max) | ||||||
|  | - rollNormal(mean, std_deviation) | ||||||
|  | - rollBool(chance_for_true) | ||||||
|  | - resetIndexRolls(string, array_length)  --String identifies the instance of SimpleNumDistribution to reset | ||||||
|  | - rollIndex(string, array_length)        --String identifies the instance of SimpleNumDistribution to use | ||||||
|  |                                          --(Shuffles a vector of indices, Next() increments through then reshuffles when end() is reached) | ||||||
|  | Author:  Josh Cooper | ||||||
|  | Created: Dec. 13 2017 | ||||||
|  | Updated: Dec. 21 2017 | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include <random> | ||||||
|  | #include <chrono> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <vector> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <cstdint> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | 
 | ||||||
|  | #include "Error.h" | ||||||
|  | #include "Core.h" | ||||||
|  | #include "DataFuncs.h" | ||||||
|  | #include <Console.h> | ||||||
|  | #include <Export.h> | ||||||
|  | #include <PluginManager.h> | ||||||
|  | /*
 | ||||||
|  | typedef unsigned short uint16_t; | ||||||
|  | typedef unsigned long long uint64_t; | ||||||
|  | typedef long long int64_t; | ||||||
|  | using uint16_t = unsigned short; | ||||||
|  | using uint64_t = unsigned long long; | ||||||
|  | using int64_t = long long;*/ | ||||||
|  | 
 | ||||||
|  | using namespace DFHack; | ||||||
|  | DFHACK_PLUGIN("cxxrandom"); | ||||||
|  | #define PLUGIN_VERSION 2.0 | ||||||
|  | color_ostream *cout = nullptr; | ||||||
|  | 
 | ||||||
|  | //command_result cxxrandom (color_ostream &out, std::vector <std::string> & parameters);
 | ||||||
|  | DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &commands) | ||||||
|  | { | ||||||
|  |     cout = &out; | ||||||
|  |     /*
 | ||||||
|  |     commands.push_back(PluginCommand( | ||||||
|  |         "cxxrandom", "C++xx Random Numbers", cxxrandom, false, | ||||||
|  |         "  This plugin cannot be used on the commandline.\n" | ||||||
|  |         "  Import into a lua script to have access to exported RNG functions:\n" | ||||||
|  |         "    local rng = require('plugins.cxxrandom')\n\n" | ||||||
|  |         "  Exported Functions:\n" | ||||||
|  |         "    rng.ResetIndexRolls(string_ref, total_indices)\n" | ||||||
|  |         "    rng.RollIndex(string_ref, total_indices)\n" | ||||||
|  |         "    rng.RollInt(min, max)\n" | ||||||
|  |         "    rng.RollDouble(min, max)\n" | ||||||
|  |         "    rng.RollNormal(mean, std_deviation)\n" | ||||||
|  |         "    rng.RollBool(chance_of_true)\n" | ||||||
|  |         "    rng.BlastDistributions()\n\n" | ||||||
|  |     ));*/ | ||||||
|  |     return CR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DFhackCExport command_result plugin_shutdown (color_ostream &out) | ||||||
|  | { | ||||||
|  |     return CR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) | ||||||
|  | { | ||||||
|  |     return CR_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #pragma region "EnginesKeeper Stuff" | ||||||
|  | 
 | ||||||
|  | class EnginesKeeper | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     EnginesKeeper() {} | ||||||
|  |     std::unordered_map<uint16_t, std::mt19937_64> m_engines; | ||||||
|  |     uint16_t counter = 0; | ||||||
|  | public: | ||||||
|  |     static EnginesKeeper& Instance() | ||||||
|  |     { | ||||||
|  |         static EnginesKeeper instance; | ||||||
|  |         return instance; | ||||||
|  |     } | ||||||
|  |     uint16_t NewEngine( uint64_t seed ) | ||||||
|  |     { | ||||||
|  |         std::mt19937_64 engine( seed != 0 ? seed : std::chrono::system_clock::now().time_since_epoch().count() ); | ||||||
|  |         m_engines[++counter] = engine; | ||||||
|  |         return counter; | ||||||
|  |     } | ||||||
|  |     void DestroyEngine( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         m_engines.erase( id ); | ||||||
|  |     } | ||||||
|  |     void NewSeed( uint16_t id, uint64_t seed ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_engines.find( id ) != m_engines.end() ); | ||||||
|  |         m_engines[id].seed( seed != 0 ? seed : std::chrono::system_clock::now().time_since_epoch().count() ); | ||||||
|  |     } | ||||||
|  |     std::mt19937_64& RNG( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_engines.find( id ) != m_engines.end() ); | ||||||
|  |         return m_engines[id]; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #pragma endregion | ||||||
|  | 
 | ||||||
|  | #pragma region "EngineKeeper Wrappers" | ||||||
|  | 
 | ||||||
|  | uint16_t GenerateEngine( uint64_t seed ) | ||||||
|  | { | ||||||
|  |     return EnginesKeeper::Instance().NewEngine( seed ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DestroyEngine( uint16_t id ) | ||||||
|  | { | ||||||
|  |     EnginesKeeper::Instance().DestroyEngine( id ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NewSeed( uint16_t id, uint64_t seed ) | ||||||
|  | { | ||||||
|  |     EnginesKeeper::Instance().NewSeed( id, seed ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #pragma endregion | ||||||
|  | 
 | ||||||
|  | #pragma region "std Distribution Rollers" | ||||||
|  | 
 | ||||||
|  | int      rollInt(uint16_t id, int min, int max) | ||||||
|  | { | ||||||
|  |     std::uniform_int_distribution<int> ND(min, max); | ||||||
|  |     return ND(EnginesKeeper::Instance().RNG(id)); | ||||||
|  | } | ||||||
|  |           | ||||||
|  | double   rollDouble(uint16_t id, double min, double max) | ||||||
|  | { | ||||||
|  |     std::uniform_real_distribution<double> ND(min, max); | ||||||
|  |     return ND(EnginesKeeper::Instance().RNG(id)); | ||||||
|  | } | ||||||
|  |           | ||||||
|  | double   rollNormal(uint16_t id, double mean, double stddev) | ||||||
|  | { | ||||||
|  |     std::normal_distribution<double> ND(mean, stddev); | ||||||
|  |     return ND(EnginesKeeper::Instance().RNG(id)); | ||||||
|  | } | ||||||
|  |           | ||||||
|  | bool     rollBool(uint16_t id, float p) | ||||||
|  | { | ||||||
|  |     std::bernoulli_distribution ND(p); | ||||||
|  |     return ND(EnginesKeeper::Instance().RNG(id)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #pragma endregion | ||||||
|  | 
 | ||||||
|  | #pragma region "Number Sequence Stuff" | ||||||
|  | 
 | ||||||
|  | class NumberSequence | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     unsigned short m_position = 0; | ||||||
|  |     std::vector<int64_t> m_numbers; | ||||||
|  | public: | ||||||
|  |     NumberSequence(){} | ||||||
|  |     NumberSequence( int64_t start, int64_t end ) | ||||||
|  |     { | ||||||
|  |         for( int64_t i = start; i <= end; ++i ) | ||||||
|  |         { | ||||||
|  |             m_numbers.push_back( i ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     void Add( int64_t num ) { m_numbers.push_back( num ); } | ||||||
|  |     void Reset()            { m_numbers.clear(); } | ||||||
|  |     int64_t Next() | ||||||
|  |     { | ||||||
|  |         if(m_position >= m_numbers.size()) | ||||||
|  |         { | ||||||
|  |             m_position = 0; | ||||||
|  |         } | ||||||
|  |         return m_numbers[m_position++]; | ||||||
|  |     } | ||||||
|  |     void Shuffle( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         std::shuffle( std::begin( m_numbers ), std::end( m_numbers ), EnginesKeeper::Instance().RNG( id ) ); | ||||||
|  |     } | ||||||
|  |     void Print() | ||||||
|  |     { | ||||||
|  |         char buffer1[256] = {0}; | ||||||
|  |         char buffer2[256] = {0}; | ||||||
|  |         for( auto v : m_numbers ) | ||||||
|  |         { | ||||||
|  |             sprintf( buffer2, "%s%d", buffer1, v ); | ||||||
|  |             sprintf( buffer1, "%s ", buffer2 ); | ||||||
|  |         } | ||||||
|  |         cout->print( buffer1 ); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | class SequenceKeeper | ||||||
|  | { | ||||||
|  | private: | ||||||
|  |     SequenceKeeper() {} | ||||||
|  |     std::unordered_map<uint16_t, NumberSequence> m_sequences; | ||||||
|  |     uint16_t counter = 0; | ||||||
|  | public: | ||||||
|  |     static SequenceKeeper& Instance() | ||||||
|  |     { | ||||||
|  |         static SequenceKeeper instance; | ||||||
|  |         return instance; | ||||||
|  |     } | ||||||
|  |     uint16_t MakeNumSequence( int64_t start, int64_t end ) | ||||||
|  |     { | ||||||
|  |         m_sequences[++counter] = NumberSequence( start, end ); | ||||||
|  |         return counter; | ||||||
|  |     } | ||||||
|  |     uint16_t MakeNumSequence() | ||||||
|  |     { | ||||||
|  |         m_sequences[++counter] = NumberSequence(); | ||||||
|  |         return counter; | ||||||
|  |     } | ||||||
|  |     void DestroySequence( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         m_sequences.erase( id ); | ||||||
|  |     } | ||||||
|  |     void AddToSequence( uint16_t id, int64_t num ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_sequences.find( id ) != m_sequences.end() ); | ||||||
|  |         m_sequences[id].Add( num ); | ||||||
|  |     } | ||||||
|  |     void Shuffle( uint16_t id, uint16_t rng_id ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_sequences.find( id ) != m_sequences.end() ); | ||||||
|  |         m_sequences[id].Shuffle( rng_id ); | ||||||
|  |     } | ||||||
|  |     int64_t NextInSequence( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_sequences.find( id ) != m_sequences.end() ); | ||||||
|  |         return m_sequences[id].Next(); | ||||||
|  |     } | ||||||
|  |     void PrintSequence( uint16_t id ) | ||||||
|  |     { | ||||||
|  |         CHECK_INVALID_ARGUMENT( m_sequences.find( id ) != m_sequences.end() ); | ||||||
|  |         auto seq = m_sequences[id]; | ||||||
|  |         seq.Print(); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #pragma endregion | ||||||
|  | 
 | ||||||
|  | #pragma region "Sequence Wrappers" | ||||||
|  | 
 | ||||||
|  | uint16_t MakeNumSequence( int64_t start, int64_t end ) | ||||||
|  | { | ||||||
|  |     if( start == end ) | ||||||
|  |     { | ||||||
|  |         return SequenceKeeper::Instance().MakeNumSequence(); | ||||||
|  |     } | ||||||
|  |     return SequenceKeeper::Instance().MakeNumSequence( start, end ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void     DestroyNumSequence( uint16_t id ) | ||||||
|  | { | ||||||
|  |     SequenceKeeper::Instance().DestroySequence( id ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void     AddToSequence( uint16_t id, int64_t num ) | ||||||
|  | { | ||||||
|  |     SequenceKeeper::Instance().AddToSequence( id, num ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void     ShuffleSequence( uint16_t rngID, uint16_t id ) | ||||||
|  | { | ||||||
|  |     SequenceKeeper::Instance().Shuffle( id, rngID ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int64_t  NextInSequence( uint16_t id ) | ||||||
|  | { | ||||||
|  |     return SequenceKeeper::Instance().NextInSequence( id ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void DebugSequence( uint16_t id ) | ||||||
|  | { | ||||||
|  |     SequenceKeeper::Instance().PrintSequence( id ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #pragma endregion | ||||||
|  | 
 | ||||||
|  | DFHACK_PLUGIN_LUA_FUNCTIONS { | ||||||
|  |     DFHACK_LUA_FUNCTION(GenerateEngine), | ||||||
|  |     DFHACK_LUA_FUNCTION(DestroyEngine), | ||||||
|  |     DFHACK_LUA_FUNCTION(NewSeed), | ||||||
|  |     DFHACK_LUA_FUNCTION(rollInt), | ||||||
|  |     DFHACK_LUA_FUNCTION(rollDouble), | ||||||
|  |     DFHACK_LUA_FUNCTION(rollNormal), | ||||||
|  |     DFHACK_LUA_FUNCTION(rollBool), | ||||||
|  |     DFHACK_LUA_FUNCTION(MakeNumSequence), | ||||||
|  |     DFHACK_LUA_FUNCTION(DestroyNumSequence), | ||||||
|  |     DFHACK_LUA_FUNCTION(AddToSequence), | ||||||
|  |     DFHACK_LUA_FUNCTION(ShuffleSequence), | ||||||
|  |     DFHACK_LUA_FUNCTION(NextInSequence), | ||||||
|  |     DFHACK_LUA_FUNCTION(DebugSequence), | ||||||
|  |     DFHACK_LUA_END | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| @ -0,0 +1,214 @@ | |||||||
|  | local _ENV = mkmodule('plugins.cxxrandom') | ||||||
|  | 
 | ||||||
|  | function MakeNewEngine(seed) | ||||||
|  |     if type(seed) == 'number' then | ||||||
|  |         if seed == 0 then | ||||||
|  |             print(":WARNING: Seeds equal to 0 are used if no seed is provided. This indicates to cxxrandom.plug.dll that the engine needs to be seeded with the current time.\nRecommendation: use a non-zero value for your seed, or don't provide a seed to use the time since epoch(1969~).") | ||||||
|  |         end | ||||||
|  |         return GenerateEngine(seed) | ||||||
|  |     elseif type(seed) == 'nil' then | ||||||
|  |         return GenerateEngine(0) | ||||||
|  |     else | ||||||
|  |         error("Argument `seed` must be a number, or nil.") | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: crng | ||||||
|  | ------------- | ||||||
|  | crng = {} | ||||||
|  | function crng:new(engineID, destroyEngineOnDestruction, distrib) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     local idtype = type(engineID) | ||||||
|  |     local flagtype = type(destroyEngineOnDestruction) | ||||||
|  |      | ||||||
|  |     if idtype == 'number' then | ||||||
|  |         o.rngID = engineID | ||||||
|  |     elseif idtype == 'nil' then | ||||||
|  |         o.rngID = GenerateEngine(0) | ||||||
|  |     else | ||||||
|  |         error("Invalid argument type (engineID): " .. tostring(engineID)) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     if flagtype ~= 'nil' and flagtype == 'boolean' then | ||||||
|  |         o.destroyid = destroyEngineOnDestruction | ||||||
|  |     elseif flagtype == 'nil' then | ||||||
|  |         o.destroyid = true | ||||||
|  |     else | ||||||
|  |         error("Invalid arugment type (destroyEngineOnDestruction): " .. tostring(destroyEngineOnDestruction)) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     if type(distrib) ~= 'nil' then | ||||||
|  |         if type(distrib) == 'table' and type(distrib.next) == 'function' then | ||||||
|  |             o.distrib = distrib | ||||||
|  |             o.distrib.rngID = o.rngID | ||||||
|  |         else | ||||||
|  |             error("Invalid distribution used as an argument. Cannot set this as the number distribution.") | ||||||
|  |         end | ||||||
|  |     end | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | --crng destructor - we may need to destroy the engine, the user may be doing it manually though | ||||||
|  | function crng:__gc() | ||||||
|  |     if self.destroyid then | ||||||
|  |         DestroyEngine(self.rngID) | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | function crng:changeSeed(seed) | ||||||
|  |     if type(seed) == 'number' then | ||||||
|  |         if seed == 0 then | ||||||
|  |             print(":WARNING: Seeds equal to 0 are used if no seed is provided. This indicates to cxxrandom.plug.dll that the engine needs to be seeded with the current time.\nRecommendation: use a non-zero value for your seed, or don't provide a seed to use the time since epoch(1969~).") | ||||||
|  |         end | ||||||
|  |         return NewSeed(self.rngID, seed) | ||||||
|  |     elseif type(seed) == 'nil' then | ||||||
|  |         return NewSeed(self.rngID, 0) | ||||||
|  |     else | ||||||
|  |         error("Argument `seed` must be a number, or nil.") | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | function crng:setNumDistrib(distrib) | ||||||
|  |     if type(distrib) == 'table' and type(distrib.next) == 'function' then | ||||||
|  |         self.distrib = distrib | ||||||
|  |         self.distrib.rngID = self.rngID | ||||||
|  |     else | ||||||
|  |         error("Invalid distribution used as an argument. Cannot set this as the number distribution.") | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | function crng:next() | ||||||
|  |     if type(self.distrib) == 'table' and type(self.distrib.next) == 'function' then | ||||||
|  |         return self.distrib:next(self.rngID) | ||||||
|  |     else | ||||||
|  |         error("crng object does not have a valid number distribution set") | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | function crng:shuffle() | ||||||
|  |     if type(self.distrib) == 'table' and type(self.distrib.shuffle) == 'function' then | ||||||
|  |         self.distrib:shuffle(self.rngID) | ||||||
|  |     else | ||||||
|  |         print(":WARNING: No self.distrib.shuffle not found.") | ||||||
|  |         changeSeed(0) | ||||||
|  |     end | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: normal_distribution | ||||||
|  | ---------------------------- | ||||||
|  | normal_distribution = {} | ||||||
|  | function normal_distribution:new(avg, stddev) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     if type(avg) ~= 'number' or type(stddev) ~= 'number' then | ||||||
|  |         error("Invalid arguments in normal_distribution construction. Average and standard deviation must be numbers.") | ||||||
|  |     end | ||||||
|  |     o.average = avg | ||||||
|  |     o.std_deviation = stddev | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | function normal_distribution:next(id) | ||||||
|  |     return rollNormal(id, self.average, self.std_deviation) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: real_distribution | ||||||
|  | ---------------------------- | ||||||
|  | real_distribution = {} | ||||||
|  | function real_distribution:new(min, max) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     if type(min) ~= 'number' or type(max) ~= 'number' then | ||||||
|  |         error("Invalid arguments in real_distribution construction. min and max must be numbers.") | ||||||
|  |     end | ||||||
|  |     o.min = min | ||||||
|  |     o.max = max | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | function real_distribution:next(id) | ||||||
|  |     return rollDouble(id, self.min, self.max) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: int_distribution | ||||||
|  | ---------------------------- | ||||||
|  | int_distribution = {} | ||||||
|  | function int_distribution:new(min, max) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     if type(min) ~= 'number' or type(max) ~= 'number' then | ||||||
|  |         error("Invalid arguments in int_distribution construction. min and max must be numbers.") | ||||||
|  |     end | ||||||
|  |     o.min = min | ||||||
|  |     o.max = max | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | function int_distribution:next(id) | ||||||
|  |     return rollInt(id, self.min, self.max) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: bool_distribution | ||||||
|  | ---------------------------- | ||||||
|  | bool_distribution = {} | ||||||
|  | function bool_distribution:new(chance) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     if type(min) ~= 'number' or type(max) ~= 'number' then | ||||||
|  |         error("Invalid arguments in bool_distribution construction. min and max must be numbers.") | ||||||
|  |     end | ||||||
|  |     o.p = chance | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | function bool_distribution:next(id) | ||||||
|  |     return rollBool(id, self.p) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | --Class: num_sequence | ||||||
|  | ---------------------------- | ||||||
|  | num_sequence = {} | ||||||
|  | function num_sequence:new(a,b) | ||||||
|  |     local o = {} | ||||||
|  |     self.__index = self | ||||||
|  |     local btype = type(b) | ||||||
|  |     local atype = type(a) | ||||||
|  |     if atype == 'number' and btype == 'number' then | ||||||
|  |         if a == b then | ||||||
|  |             print(":WARNING: You've provided two equal arguments to initialize your sequence with. This is the mechanism used to indicate to cxxrandom.plug.dll that an empty sequence is desired.\nRecommendation: provide no arguments if you wish for an empty sequence.") | ||||||
|  |         end | ||||||
|  |         o.seqID = MakeNumSequence(a, b) | ||||||
|  |     elseif atype == 'table' then | ||||||
|  |         o.seqID = MakeNumSequence(0,0) | ||||||
|  |         for _,v in pairs(a) do | ||||||
|  |             if type(v) ~= 'number' then | ||||||
|  |                 error("num_sequence can only be initialized using numbers. " .. tostring(v) .. " is not a number.") | ||||||
|  |             end | ||||||
|  |             AddToSequence(o.seqID, v) | ||||||
|  |         end | ||||||
|  |     elseif atype == "nil" and btype == "nil" then | ||||||
|  |         o.seqID = MakeNumSequence(0,0) | ||||||
|  |     else | ||||||
|  |         error("Invalid arguments - a: " .. tostring(a) .. " and b: " .. tostring(b)) | ||||||
|  |     end | ||||||
|  |     print("seqID:"..o.seqID) | ||||||
|  |     setmetatable(o,self) | ||||||
|  |     return o | ||||||
|  | end | ||||||
|  | function num_sequence:__gc() | ||||||
|  |     DestroyNumSequence(self.seqID) | ||||||
|  | end | ||||||
|  | function num_sequence:add(x) | ||||||
|  |     if type(x) ~= 'number' then | ||||||
|  |         error("Cannot add non-number to num_sequence.") | ||||||
|  |     end | ||||||
|  |     AddToSequence(self.seqID, x) | ||||||
|  | end | ||||||
|  | function num_sequence:next() | ||||||
|  |     return NextInSequence(self.seqID) | ||||||
|  | end | ||||||
|  | function num_sequence:shuffle() | ||||||
|  |     if self.rngID == 'nil' then | ||||||
|  |         error("Add num_sequence object to crng as distribution, before attempting to shuffle.") | ||||||
|  |     end | ||||||
|  |     ShuffleSequence(self.rngID, self.seqID) | ||||||
|  | end | ||||||
|  | 
 | ||||||
|  | return _ENV | ||||||
		Loading…
	
		Reference in New Issue