Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions include/chaiscript/extras/random.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef CHAISCRIPT_EXTRAS_RANDOM_HPP_
#define CHAISCRIPT_EXTRAS_RANDOM_HPP_

#include <memory>
#include <random>

#include <chaiscript/chaiscript.hpp>

namespace chaiscript {
namespace extras {
namespace random {
class MT19937_Engine {
public:
MT19937_Engine()
: m_engine(std::random_device{}())
{
}

explicit MT19937_Engine(unsigned int t_seed)
: m_engine(t_seed)
{
}

MT19937_Engine(const MT19937_Engine &) = default;
MT19937_Engine &operator=(const MT19937_Engine &) = default;

void seed(unsigned int t_seed) {
m_engine.seed(t_seed);
}

int random_int(int t_min, int t_max) {
std::uniform_int_distribution<int> dist(t_min, t_max);
return dist(m_engine);
}

double random_float(double t_min, double t_max) {
std::uniform_real_distribution<double> dist(t_min, t_max);
return dist(m_engine);
}

private:
std::mt19937 m_engine;
};

ModulePtr bootstrap(ModulePtr m = std::make_shared<Module>())
{
m->add(user_type<MT19937_Engine>(), "MT19937_Engine");
m->add(constructor<MT19937_Engine ()>(), "MT19937_Engine");
m->add(constructor<MT19937_Engine (unsigned int)>(), "MT19937_Engine");
m->add(constructor<MT19937_Engine (const MT19937_Engine &)>(), "MT19937_Engine");

m->add(fun(&MT19937_Engine::seed), "seed");
m->add(fun(&MT19937_Engine::random_int), "random_int");
m->add(fun(&MT19937_Engine::random_float), "random_float");

m->add(fun([](MT19937_Engine &t_lhs, const MT19937_Engine &t_rhs) -> MT19937_Engine & {
t_lhs = t_rhs;
return t_lhs;
}), "=");

return m;
}
}
}
}

#endif /* CHAISCRIPT_EXTRAS_RANDOM_HPP_ */
6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ add_executable(string_methods_test string_methods.cpp)
target_link_libraries(string_methods_test ${LIBS})
target_include_directories(string_methods_test PUBLIC "${chaiscript_SOURCE_DIR}/include")
ADD_CATCH_TESTS(string_methods_test)

# Random
add_executable(random_test random.cpp)
target_link_libraries(random_test ${LIBS})
target_include_directories(random_test PUBLIC "${chaiscript_SOURCE_DIR}/include")
ADD_CATCH_TESTS(random_test)
1 change: 1 addition & 0 deletions tests/math.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#define CATCH_CONFIG_NO_POSIX_SIGNALS
//#include <sstream>
#include "catch.hpp"

Expand Down
75 changes: 75 additions & 0 deletions tests/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#define CATCH_CONFIG_MAIN
#define CATCH_CONFIG_NO_POSIX_SIGNALS
#include "catch.hpp"

#include <chaiscript/chaiscript.hpp>
#include <chaiscript/chaiscript_stdlib.hpp>
#include "../include/chaiscript/extras/random.hpp"

TEST_CASE( "MT19937_Engine type is usable in ChaiScript", "[random]" ) {
auto randomlib = chaiscript::extras::random::bootstrap();

auto stdlib = chaiscript::Std_Lib::library();
chaiscript::ChaiScript chai(stdlib);
chai.add(randomlib);

SECTION("default constructor creates a valid engine") {
const auto result = chai.eval<int>("var rng = MT19937_Engine(); rng.random_int(0, 100)");
CHECK(result >= 0);
CHECK(result <= 100);
}

SECTION("seeded constructor creates a valid engine") {
const auto result = chai.eval<int>("var rng = MT19937_Engine(42u); rng.random_int(0, 100)");
CHECK(result >= 0);
CHECK(result <= 100);
}

SECTION("seed produces deterministic sequences") {
chai.eval("var rng = MT19937_Engine()");
chai.eval("rng.seed(42u)");
const auto first = chai.eval<int>("rng.random_int(0, 1000)");
chai.eval("rng.seed(42u)");
const auto second = chai.eval<int>("rng.random_int(0, 1000)");
CHECK(first == second);
}

SECTION("copy constructor copies engine state") {
chai.eval("var rng = MT19937_Engine(99u)");
chai.eval("var rng2 = MT19937_Engine(rng)");
const auto a = chai.eval<int>("rng.random_int(0, 1000)");
const auto b = chai.eval<int>("rng2.random_int(0, 1000)");
CHECK(a == b);
}

SECTION("assignment copies engine state") {
chai.eval("var rng = MT19937_Engine(77u)");
chai.eval("var rng2 = MT19937_Engine()");
chai.eval("rng2 = rng");
const auto a = chai.eval<int>("rng.random_int(0, 1000)");
const auto b = chai.eval<int>("rng2.random_int(0, 1000)");
CHECK(a == b);
}

SECTION("random_int returns values in range") {
chai.eval("var rng = MT19937_Engine(42u)");
const auto result = chai.eval<int>("rng.random_int(5, 10)");
CHECK(result >= 5);
CHECK(result <= 10);
}

SECTION("random_float returns values in range") {
chai.eval("var rng = MT19937_Engine(42u)");
const auto result = chai.eval<double>("rng.random_float(0.0, 1.0)");
CHECK(result >= 0.0);
CHECK(result < 1.0);
}

SECTION("different seeds produce different sequences") {
chai.eval("var rng1 = MT19937_Engine(1u)");
chai.eval("var rng2 = MT19937_Engine(2u)");
const auto a = chai.eval<int>("rng1.random_int(0, 1000000)");
const auto b = chai.eval<int>("rng2.random_int(0, 1000000)");
CHECK(a != b);
}
}
1 change: 1 addition & 0 deletions tests/string_methods.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#define CATCH_CONFIG_NO_POSIX_SIGNALS
#include <string>
#include "catch.hpp"

Expand Down