#include "tests/RandomTests.h"

#include "data/Array.h"
#include "test/Test.h"
#include "utils/Random.h"

static void testAverage() {
    Core::Random r(553);
    float sum = 0;
    for(int i = 0; i < 1000000; i++) {
        sum += static_cast<float>(r.next(2, 10));
    }
    sum /= 1000000.0f;
    CORE_TEST_FLOAT(6.0f, sum, 0.01f);
}

static void testCoin() {
    Core::Random r(553);
    Core::Array<int, 2> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.nextBool()]++;
    }
    CORE_TEST_FLOAT(0.0f, static_cast<float>(c[0] - c[1]) / 1000000.0f, 0.001f);
}

static void testDistribution() {
    Core::Random r(553);
    Core::Array<int, 102> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.next(1, c.getLength() - 2)]++;
    }
    CORE_TEST_EQUAL(0, c[0]);
    CORE_TEST_EQUAL(0, c[c.getLength() - 1]);
    for(int i = 1; i < c.getLength() - 1; i++) {
        CORE_TEST_FLOAT(0.01f, static_cast<float>(c[i]) / 1000000.0f, 0.001f);
    }
}

static void testFloatAverage() {
    Core::Random r(553);
    float sum = 0;
    for(int i = 0; i < 1000000; i++) {
        sum += r.nextFloat();
    }
    sum /= 1000000.0f;
    CORE_TEST_FLOAT(0.5f, sum, 0.001f);
}

static void testFloatCoin() {
    Core::Random r(553);
    Core::Array<int, 2> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.nextFloat() < 0.5f]++;
    }
    CORE_TEST_FLOAT(0.0f, static_cast<float>(c[0] - c[1]) / 1000000.0f, 0.001f);
}

static void testFloatDistribution() {
    Core::Random r(553);
    Core::Array<int, 102> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[static_cast<int>(r.nextFloat(1.0f, c.getLength() - 1))]++;
    }
    CORE_TEST_EQUAL(0, c[0]);
    CORE_TEST_EQUAL(0, c[c.getLength() - 1]);
    for(int i = 1; i < c.getLength() - 1; i++) {
        CORE_TEST_FLOAT(0.01f, static_cast<float>(c[i]) / 1000000.0f, 0.001f);
    }
}

void Core::RandomTests::test() {
    testAverage();
    testCoin();
    testDistribution();
    testFloatAverage();
    testFloatCoin();
    testFloatDistribution();
}