Browse Source

Merge pull request #106 from hallzy/sys_random

Added a random() method for System
Marco Bambini 8 years ago
parent
commit
b27b738c9d

+ 8 - 0
docs/system.html

@@ -139,6 +139,14 @@
 	$ echo $?
 				</code></pre>
 				
+				<h4 class="section-h4">Random Number</h4>
+				<p>System has a random number generator:</p>
+				<pre><code class="swift">
+	func main() {
+		System.random(1, 10) // Returns an integer between 1 and 10 inclusively
+	}
+				</code></pre>
+
          	</div>
          	<!-- END CONTENT -->
          	

+ 34 - 0
src/runtime/gravity_core.c

@@ -8,6 +8,8 @@
 
 #include <inttypes.h>
 #include <math.h>
+#include <time.h>
+#include <stdlib.h>
 #include "gravity_core.h"
 #include "gravity_hash.h"
 #include "gravity_value.h"
@@ -1793,6 +1795,37 @@ static bool system_nanotime (gravity_vm *vm, gravity_value_t *args, uint16_t nar
 	RETURN_VALUE(VALUE_FROM_INT(t), rindex);
 }
 
+static bool system_random (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused(args)
+	if (nargs != 3) RETURN_ERROR("System.random() expects 2 integer arguments");
+
+	if (!VALUE_ISA_INT(GET_VALUE(1)) || !VALUE_ISA_INT(GET_VALUE(2))) RETURN_ERROR("System.random() arguments must be integers");
+
+	gravity_int_t num1 = VALUE_AS_INT(GET_VALUE(1));
+	gravity_int_t num2 = VALUE_AS_INT(GET_VALUE(2));
+
+	// Only Seed once
+	static bool already_seeded = false;
+	if (!already_seeded) {
+		srand(time(NULL));
+		already_seeded = true;
+	}
+
+	int r;
+	// if num1 is lower, consider it min, otherwise, num2 is min
+	if (num1 < num2) {
+		// returns a random integer between num1 and num2 inclusive
+		r = (rand() % (num2 - num1 + 1)) + num1;
+	}
+	else if (num1 > num2) {
+		r = (rand() % (num1 - num2 + 1)) + num2;
+	}
+	else {
+		r = num1;
+	}
+	RETURN_VALUE(VALUE_FROM_INT(r), rindex);
+}
+
 static bool system_realprint (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex, bool cr) {
 	#pragma unused (rindex)
 	for (uint16_t i=1; i<nargs; ++i) {
@@ -2076,6 +2109,7 @@ static void gravity_core_init (void) {
 	gravity_class_bind(system_meta, GRAVITY_SYSTEM_NANOTIME_NAME, NEW_CLOSURE_VALUE(system_nanotime));
 	gravity_class_bind(system_meta, GRAVITY_SYSTEM_PRINT_NAME, NEW_CLOSURE_VALUE(system_print));
 	gravity_class_bind(system_meta, GRAVITY_SYSTEM_PUT_NAME, NEW_CLOSURE_VALUE(system_put));
+	gravity_class_bind(system_meta, "random", NEW_CLOSURE_VALUE(system_random));
 	gravity_class_bind(system_meta, "exit", NEW_CLOSURE_VALUE(system_exit));
 	
 	gravity_value_t value = VALUE_FROM_OBJECT(computed_property(NULL, NEW_FUNCTION(system_get), NEW_FUNCTION(system_set)));

+ 23 - 0
test/random_int.gravity

@@ -0,0 +1,23 @@
+#unittest {
+	name: "Test System.random()";
+	error: NONE;
+	result: true;
+};
+
+func main() {
+  var c1 = System.random(1, 1) == 1
+
+  var r = System.random(1, 2)
+  var c2 = r >= 1 and r <= 2
+
+  r = System.random(-2, -1)
+  var c3 = r >= -2 and r <= -1
+
+  r = System.random(5, 0)
+  var c4 = r >= 0 and r <= 5
+
+  r = System.random(-1, 1)
+  var c5 = r >= -1 and r <= 1
+
+  return c1 and c2 and c3 and c4 and c5
+}

+ 8 - 0
test/random_int_error_args_not_ints.gravity

@@ -0,0 +1,8 @@
+#unittest {
+	name: "Test System.random() args not ints";
+	error: RUNTIME;
+};
+
+func main() {
+	return System.random("test", 1)
+}

+ 8 - 0
test/random_int_error_no_args.gravity

@@ -0,0 +1,8 @@
+#unittest {
+	name: "Test System.random() no arguments";
+	error: RUNTIME;
+};
+
+func main() {
+	return System.random()
+}

+ 40 - 0
test/random_int_multiple_attempts.gravity

@@ -0,0 +1,40 @@
+#unittest {
+	name: "System.random() test multiple calls of the same random() call";
+	error: NONE;
+	result: true;
+};
+
+func main() {
+	// This test is intended to run the same random() call multiple times and
+	// ensure that every single time, the random number that is generated is
+	// within the bounds specified
+
+	var min = 1
+	var max = 3
+
+  var r = System.random(min, max)
+  var b = r >= min and r <= max
+
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+  r = System.random(min, max)
+  b = r >= min and r <= max and b
+
+  return b;
+}