#include "tests/RandomTests.h"
#include "tests/Test.h"
#include "utils/Random.h"
#include "utils/Array.h"

static void testAverage(Test& test) {
    Random r(553);
    float sum = 0;
    for(int i = 0; i < 1000000; i++) {
        sum += r.next(2, 10);
    }
    sum /= 1000000.0f;
    test.checkFloat(6.0f, sum, 0.01f, "average");
}

static void testCoin(Test& test) {
    Random r(553);
    Array<int, 2> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.next() & 1]++;
    }
    test.checkFloat(0.0f, (c[0] - c[1]) / 1000000.0f, 0.001f, "coin");
}

static void testDistribution(Test& test) {
    Random r(553);
    Array<int, 102> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.next(1, c.getLength() - 2)]++;
    }
    test.checkEqual(0, c[0], "distribution does not underflow");
    test.checkEqual(0, c[c.getLength() - 1], "distribution does not overflow");
    for(int i = 1; i < c.getLength() - 1; i++) {
        test.checkFloat(0.01f, c[i] / 1000000.0f, 0.001f, "distribution");
    }
}

static void testFloatAverage(Test& test) {
    Random r(553);
    float sum = 0;
    for(int i = 0; i < 1000000; i++) {
        sum += r.nextFloat();
    }
    sum /= 1000000.0f;
    test.checkFloat(0.5f, sum, 0.001f, "float average");
}

static void testFloatCoin(Test& test) {
    Random r(553);
    Array<int, 2> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.nextFloat() < 0.5f]++;
    }
    test.checkFloat(0.0f, (c[0] - c[1]) / 1000000.0f, 0.001f, "float coin");
}

static void testFloatDistribution(Test& test) {
    Random r(553);
    Array<int, 102> c(0);
    for(int i = 0; i < 1000000; i++) {
        c[r.nextFloat(1.0f, c.getLength() - 1)]++;
    }
    test.checkEqual(0, c[0], "float distribution does not underflow");
    test.checkEqual(0, c[c.getLength() - 1], "float distribution does not overflow");
    for(int i = 1; i < c.getLength() - 1; i++) {
        test.checkFloat(0.01f, c[i] / 1000000.0f, 0.001f, "float distribution");
    }
}

void RandomTests::test() {
    Test test("Random");
    testAverage(test);
    testCoin(test);
    testDistribution(test);
    testFloatAverage(test);
    testFloatCoin(test);
    testFloatDistribution(test);
    test.finalize();
}