C 猜猜猜????文字小游戏
前言 - 随机性
没啥事情, 写了个猜猜猜(猜数字)小游戏. 遇到猜的部分, 那肯定会用到随机函数. 我们为了多平台行为一致, 就统一
整合一个伪随机函数实现方案, 让随机更随机. 一开始看下接口设计 rand.h
1 #ifndef _rand_h 2 #define _rand_h 3 4 #include <stdint.h> 5 #include <assert.h> 6 7 // 8 // 传承(抄袭)不灭(创新) rand 库 9 // 大体思路 10 // { r | r[n+1] = (a*r[n] + c) mod m 11 // , n >= 0 12 // , m = 0xffffffffffff = 2 ^ 48 13 // , a = 0x0005deece66d = 0x5deece66d, 14 // , c = 0x000b = 0xb 15 // } 16 // 17 struct rand { 18 uint32_t x0, x1, x2; 19 uint32_t a0, a1, a2; 20 uint32_t c; 21 }; 22 23 typedef struct rand rand_t[1]; 24 25 // 26 // rand_init - 随机函数对象初始化种子 27 // r : 随机函数对象 28 // seed : 种子数 29 // return : void 30 // 31 extern void rand_init(rand_t r, int64_t seed); 32 33 // 34 // rand_rand - 获取一个随机值 35 // r : 随机函数对象 36 // return : 返回 [0, int32_max] 随机数 37 // 38 extern int32_t rand_rand(rand_t r); 39 40 // 41 // r_rand - 得到 [0, int32_max] 随机数 42 // r_ranb - 得到 [0, int64_max] (int64 = big int32) 随机数 43 // r_rang - 得到 range [min, max] 随机数 44 // 45 extern int32_t r_rand(void); 46 47 extern int64_t r_ranb(void); 48 49 inline int32_t r_rang(int32_t min, int32_t max) { 50 assert(max >= min); 51 return r_rand() % (max - min + 1) + min; 52 } 53 54 #endif//_rand_h
rand.c
1 #include "rand.h" 2 3 #define x0 (0x330e) 4 #define x1 (0xabcd) 5 #define x2 (0x1234) 6 #define a0 (0xe66d) 7 #define a1 (0xdeec) 8 #define a2 (0x0005) 9 #define c (0x000b) 10 11 #define n (16) 12 #define mask ((1 << n) - 1) 13 #define low(x) ((uint32_t)(x) & mask) 14 #define high(x) low((x) >> n) 15 16 // 17 // rand_init - 随机函数对象初始化种子 18 // r : 随机函数对象 19 // seed : 种子数 20 // return : void 21 // 22 inline void 23 rand_init(rand_t r, int64_t seed) { 24 r->x0 = x0; r->x1 = low(seed); r->x2 = high(seed); 25 r->a0 = a0; r->a1 = a1; r->a2 = a2; 26 r->c = c; 27 } 28 29 #define carry(x, y) ((x + y) > mask) // 基于 16 位判断二者和是否进位 30 #define addrq(x, y, z) z = carry(x, y); x = low(x + y) 31 #define mul(m, x, y, z) m = (x) * (y); z##0 = low(m); z##1 = high(m) 32 33 inline void rand_next(rand_t r) { 34 uint32_t m, p0, p1, q0, q1, s0, s1, c0, c1; 35 36 mul(m, r->a0, r->x0, p); 37 addrq(p0, r->c, c0); 38 addrq(p1, c0, c1); 39 mul(m, r->a0, r->x1, q); 40 addrq(p1, q0, c0); 41 mul(m, r->a1, r->x0, s); 42 43 m = c0 + c1 + carry(p1, s0) + q1 + s1 44 + r->a0 * r->x2 + r->a1 * r->x1 + r->a2 * r->x0; 45 r->x2 = low(m); 46 r->x1 = low(p1 + s0); 47 r->x0 = low(p0); 48 } 49 50 // 51 // rand_rand - 获取一个随机值 52 // r : 随机函数对象 53 // return : 返回 [0, int32_max] 随机数 54 // 55 inline int32_t 56 rand_rand(rand_t r) { 57 rand_next(r); 58 return (r->x2 << (n - 1)) + (r->x1 >> 1); 59 } 60 61 // 62 // 想过 - 朵朵浪花, 也不曾看见云彩飘过 :0 63 // 64 static rand_t r_r = { { x0, x1, x2 , a0, a1, a2 , c } }; 65 66 // extern_run(r_init) 启动初始化 67 extern inline void r_init(int64_t seed) { 68 rand_init(r_r, seed); 69 } 70 71 inline int32_t 72 r_rand(void) { 73 return rand_rand(r_r); 74 } 75 76 inline int64_t 77 r_ranb(void) { 78 uint64_t x = ((r_rand() << n) ^ r_rand()) & int32_max; 79 uint64_t y = ((r_rand() << n) ^ r_rand()) & int32_max; 80 return ((x << 2 * n) | y) & int64_max; 81 }
算法层面网上资料很够(redis rand48 原理) . 我这里只聊聊工程实现方面, 可以看出来多线程并发发起 r_rand()
请求是不可控的(非线程安全, 你也不知道内部运行状态是啥). 但如果存在特殊业务需要可窥探随机序列时候,
rand_init 就可以运用上了, 来构建多线程情况下可控的随机函数对象.
对于 r_init 多数使用 time(null) 时间量初始化种子, 有没有人觉得不太可靠, 毕竟服务器时间也可以改. 有
没有想过让其更加混乱一点. 这里有个小想法, 提出来可供大家一块参略讨论讨论.
1 // 2 // extern_run - 函数包装宏, 声明并立即使用 3 // frun : 需要执行的函数名称 4 // ... : 可变参数, 保留 5 // 6 #define extern_run(frun, ...) \ 7 do { \ 8 extern void frun(); \ 9 frun (__va_args__); \ 10 } while(0) 11 12 // 此后 :) 随机与你无关 ~ 13 extern_run(rand_restrict);
17 // rand_nationalism - 民族主义, 国家是人民所共有, 各族平等, 团结一致 18 static void rand_nationalism(void) { 19 struct timespec s; 20 (void)timespec_get(&s, time_utc); 21 extern_run(r_init, s.tv_nsec + s.tv_sec); 22 for (int32_t i = bufsiz; i > 0 ; --i) { 23 (void)timespec_get(&s, time_utc); 24 extern_run(r_init, s.tv_nsec + i); 25 } 26 } 27 28 // rand_democracy - 民权主义, 政治是人民所共管, 选举权、罢免权、创制权和复决权 29 static void rand_democracy(void) { 30 int32_t x, y, z, w; 31 do { 32 x = r_rand(); 33 y = r_rand(); 34 z = r_rand(); 35 w = r_rand(); 36 } while (!(x > y && y > z && z > w && w > int16_max)); 37 } 38 39 // rand_livelihood - 民生主义, 利益是人民所共享, 让人像个人 40 static void rand_livelihood(void) { 41 for (int32_t i = r_rand(); i >= 0; --i) 42 r_rand(); 43 } 44 45 // rand_restrict - 三权制衡在随机函数初中运用 46 void rand_restrict(void) { 47 thread_async(rand_nationalism); 48 thread_async(rand_democracy); 49 thread_async(rand_livelihood); 50 }
传送门 核心是引入多线程互相竞争制约, 让随机函数你我不知, 模糊不清, 捉摸不透. 这里只是瞎弄一个思路.
大家有更好的想法可以在评论区和我一块交流.
正文 - 猜猜猜
是不是要开始扯闲篇. 那就用上面随机库写个猜猜猜游戏吧 ~
main.c
#include "rand.h" #include <time.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> // // extern_run - 函数包装宏, 声明并立即使用 // frun : 需要执行的函数名称 // ... : 可变参数, 保留 // #define extern_run(frun, ...) \ do { \ extern void frun(); \ frun (__va_args__); \ } while(0) // // guess_threshold_int - 猜数最多次数 // guess_temper_int - 遇到小脾气不再触发提示 // guess_max_int - 最大值区间 // #define guess_threshold_int (8) #define guess_temper_int (3) #define guess_max_int (8964) // guess 猜数字游戏对象 struct guess { int32_t max; // 数字区间上限 int32_t correct; // 正确数值 int32_t use; // 已经猜数次数 int32_t numbers[guess_threshold_int]; // 用户猜数数组 int32_t now; // 用户当前输入值 }; // guess_run 猜数字游戏开始 void guess_run(struct guess * restrict g); // guess_guess 猜数字开启猜猜猜 bool guess_guess(struct guess * restrict g); // guess_end 猜数字游戏结束总结 void guess_end(struct guess * restrict g); // threshold_input - 获取猜数字的范围 static int32_t threshold_input(int argc, char * argv[]) { int32_t max = guess_max_int; if (argc > 1) { int num = atoi(argv[1]); if (num <= 0) { printf("亲, 别
相关文章:
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
上一篇: Linux--shell交互输入与循环语句--06
下一篇: Linux 基础学习
发表评论