Skip to content

Commit

Permalink
Initial
Browse files Browse the repository at this point in the history
  • Loading branch information
Gekctek committed Oct 23, 2023
1 parent 143c9d7 commit 5462b88
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 19 deletions.
10 changes: 5 additions & 5 deletions mops.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[dependencies]
base = "0.8.7"
base = "0.9.6"

[package]
name = ""
name = "random"
version = "0.1.0"
description = "A library for "
repository = "https://github.com/edjcase/motoko_"
description = "A library for random helper funtions"
repository = "https://github.com/edjcase/motoko_random"

[dev-dependencies]
test = "1.0.1"
test = "1.0.1"
3 changes: 0 additions & 3 deletions src/Library.mo

This file was deleted.

97 changes: 97 additions & 0 deletions src/RandomX.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import Random "mo:base/Random";
import Debug "mo:base/Debug";
import Int "mo:base/Int";
import Nat8 "mo:base/Nat8";
import Array "mo:base/Array";
import Iter "mo:base/Iter";
import Buffer "mo:base/Buffer";

module Module {
public type RandomBinomialGenerator = {
binomial : (Nat8) -> ?Nat8;
};
public type RandomByteGenerator = {
byte : () -> ?Nat8;
};
public type RandomRangeGenerator = {
range : (Nat8) -> ?Nat;
};
public type RandomCoinGenerator = {
coin : () -> ?Bool;
};
public type RandomNumberGenerator = RandomBinomialGenerator and RandomByteGenerator and RandomRangeGenerator and RandomCoinGenerator;

public func fromSeed(seed : Blob) : FiniteX {
FiniteX(seed);
};

public func randomInt(random : RandomRangeGenerator, min : Int, max : Int) : ?Int {
if (min > max) {
Debug.trap("Min cannot be larger than max");
};
let range : Nat = Int.abs(max - min) + 1;

var bitsNeeded : Nat = 0;
var temp : Nat = range;
while (temp > 0) {
temp := temp / 2;
bitsNeeded += 1;
};

let ?randVal = random.range(Nat8.fromNat(bitsNeeded)) else return null;
let randInt = min + (randVal % range);
?randInt;
};

public func randomNat(random : RandomRangeGenerator, min : Nat, max : Nat) : ?Nat {
let ?randInt = randomInt(random, min, max) else return null;
?Int.abs(randInt);
};

public func shuffleArray<T>(random : RandomRangeGenerator, array : [T]) : ?[T] {
let arraySize = array.size();
if (arraySize == 0) {
return ?array;
};
let shuffledArray = Buffer.fromArray<T>(array);
Buffer.reverse(shuffledArray);
var i : Nat = arraySize;
for (item in shuffledArray.vals()) {
i -= 1;
let ?randIdx = randomNat(random, 0, i) else return null;
let temp = shuffledArray.get(i);
shuffledArray.put(i, shuffledArray.get(randIdx));
shuffledArray.put(randIdx, temp);
};
return ?Buffer.toArray(shuffledArray);
};

public class FiniteX(seed : Blob) {
let random : RandomNumberGenerator = Random.Finite(seed);

public func byte() : ?Nat8 {
random.byte();
};

public func bool() : ?Bool {
random.coin();
};

public func int(min : Int, max : Int) : ?Int {
Module.randomInt(random, min, max);
};

public func nat(min : Nat, max : Nat) : ?Nat {
Module.randomNat(random, min, max);
};

public func shuffleArray<T>(array : [T]) : ?[T] {
Module.shuffleArray<T>(random, array);
};

public func randomElement<T>(array : [T]) : ?T {
let ?i = nat(0, array.size() - 1) else return null;
?array.get(i);
};
};
};
11 changes: 0 additions & 11 deletions test/Library.test.mo

This file was deleted.

76 changes: 76 additions & 0 deletions test/RandomX.test.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import Iter "mo:base/Iter";
import { test } "mo:test";
import Debug "mo:base/Debug";
import Int "mo:base/Int";
import RandomX "../src/RandomX";

let assertEqualInt = func(expected : Int, actual : ?Int) : () {
if (actual != ?expected) {
switch (actual) {
case (null) Debug.trap("Expected " # Int.toText(expected) # ", but ran out of entropy.");
case (?i) Debug.trap("Expected " # Int.toText(expected) # ", got " # Int.toText(i));
};
};
};

test(
"int",
func() {
let testCases : [{ seed : Blob; expected : Int; min : Int; max : Int }] = [
{
seed = "\A1\B2\C3\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = 1;
min = 0;
max = 10;
},
{
seed = "\A1\B2\C8\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = -3;
min = -4;
max = 5;
},
{
seed = "\A1\B2\C8\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = 711156982585303;
min = -1;
max = 1_000_000_000_000_000;
},
];
for (testCase in Iter.fromArray(testCases)) {
let rand = RandomX.fromSeed(testCase.seed);
let randInt = rand.int(testCase.min, testCase.max);
assertEqualInt(testCase.expected, randInt);
};
},
);

test(
"nat",
func() {
let testCases : [{ seed : Blob; expected : Nat; min : Nat; max : Nat }] = [
{
seed = "\A1\B2\C3\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = 1;
min = 0;
max = 10;
},
{
seed = "\A1\B2\C8\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = 2;
min = 1;
max = 5;
},
{
seed = "\A1\B2\C8\D4\E5\F6\10\11\12\13\14\15\16\17\18\19\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27\1A\1B\1C\1D\1E\1F\20\21\22\23\24\25\26\27";
expected = 711156982685303;
min = 99999;
max = 1_000_000_000_000_000;
},
];
for (testCase in Iter.fromArray(testCases)) {
let rand = RandomX.fromSeed(testCase.seed);
let randInt = rand.nat(testCase.min, testCase.max);
assertEqualInt(testCase.expected, randInt);
};
},
);

0 comments on commit 5462b88

Please sign in to comment.