Commit b453345554

Andrew Kelley <superjoe30@gmail.com>
2016-01-03 08:30:41
add rand example that doesn't yet work
1 parent 1abb4e5
Changed files (3)
example
guess_number
rand
std
example/guess_number/main.zig
@@ -18,19 +18,19 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
         return 1;
     }
 
-    print_str("Seed: ");
-    print_u64(seed);
-    print_str("\n");
-
-    /*
     var rand_state = rand_init(seed);
 
-    const answer = rand_int(&rand_state, 0, 100) + 1;
+    const answer = rand_u64(&rand_state, 0, 100) + 1;
 
+    print_str("Answer: ");
+    print_u64(answer);
+    print_str("\n");
+
+    /*
     while (true) {
         const line = readline("\nGuess a number between 1 and 100: ");
 
-        if (const guess ?= parse_number(line)) {
+        if (const guess ?= parse_u64(line)) {
             if (guess > answer) {
                 print_str("Guess lower.\n");
             } else if (guess < answer) {
example/rand/main.zig
@@ -0,0 +1,103 @@
+// Mersenne Twister
+const ARRAY_SIZE : u16 = 624;
+
+/// Use `rand_init` to initialize this state.
+pub struct Rand {
+    array: [u32; ARRAY_SIZE],
+    index: #typeof(ARRAY_SIZE),
+
+    /// Get 32 bits of randomness.
+    pub fn get_u32(r: &Rand) -> u32 {
+        if (r.index == 0) {
+            r.generate_numbers();
+        }
+
+        // temper the number
+        var y : u32 = r.array[r.index];
+        y ^= y >> 11;
+        y ^= (y >> 7) & 0x9d2c5680;
+        y ^= (y >> 15) & 0xefc60000;
+        y ^= y >> 18;
+
+        r.index = (r.index + 1) % ARRAY_SIZE;
+        return y;
+    }
+
+    /// Write `count` bytes of randomness into `buf`.
+    pub fn get_bytes(r: &Rand, buf: &u8, count: usize) {
+        var bytes_left = r.get_bytes_aligned(buf, buf, count);
+        if (bytes_left > 0) {
+            var rand_val_array : [u8; #sizeof(u32)];
+            *(rand_val_array.ptr as &u32) = r.get();
+            while (bytes_left > 0) {
+                buf[count - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left];
+                bytes_left -= 1;
+            }
+        }
+    }
+
+    /// Get a random unsigned integer with even distribution between `start`
+    /// inclusive and `end` exclusive.
+    pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
+        const range = end - start;
+        const leftover = #max_int(u64) % range;
+        const upper_bound = #max_int(u64) - leftover;
+        var rand_val_array : [u8; #sizeof(u64)];
+
+        while (true) {
+            r.get_bytes_aligned(r, rand_val_array.ptr, rand_val_array.len);
+            const rand_val = *(rand_val_array.ptr as &u64);
+            if (rand_val < upper_bound) {
+                return start + (rand_val % range);
+            }
+        }
+    }
+
+    fn generate_numbers(r: &Rand) {
+        var i : #typeof(ARRAY_SIZE) = 0;
+        while (i < ARRAY_SIZE) {
+            const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);
+            const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);
+            r.array[i] = if ((y % 2) == 0) {
+                untempered
+            } else {
+                // y is odd
+                untempered ^ 0x9908b0df
+            };
+            i += 1;
+        }
+    }
+
+    // does not populate the remaining (count % 4) bytes
+    fn get_bytes_aligned(r: &Rand, buf: &u8, count: usize) -> usize {
+        var bytes_left = count;
+        var buf_ptr = buf;
+        while (bytes_left > 4) {
+            *(buf_ptr as &u32) = r.get();
+            bytes_left -= #sizeof(u32);
+            buf_ptr += #sizeof(u32);
+        }
+        return bytes_left;
+    }
+}
+
+/// Initialize random state with the given seed.
+pub fn rand_init(seed: u32) -> (out: Rand) {
+    out.index = 0;
+    out.array[0] = seed;
+    var i : #typeof(ARRAY_SIZE) = 1;
+    while (i < ARRAY_SIZE) {
+        const prev_value : u64 = out.array[i - 1];
+        out.array[i] = ((previous_value ^ (previous_value << 30)) * 0x6c078965 + i) as u32;
+        i += 1;
+    }
+}
+
+pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+    var rand = rand_init(13);
+    const answer = rand.range_u64(0, 100) + 1;
+    print_str("random number: ");
+    print_u64(answer);
+    print_str("\n");
+    return 0;
+}
std/std.zig
@@ -90,4 +90,3 @@ fn buf_print_u64(out_buf: &u8, x: u64) -> usize {
 
     return len;
 }
-