欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C 猜猜猜????文字小游戏

程序员文章站 2022-05-18 21:12:46
前言 - 随机性 随机数生成 - https://zh.wikipedia.org/wiki/%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%94%9F%E6%88%90 没啥事情, 写了个猜猜猜(猜数字)小游戏. 遇到猜的部分, 那肯定会用到随机函数. 我们为了多平台行为一致, 就统 ......

前言 - 随机性

  随机数生成https://zh.wikipedia.org/wiki/%e9%9a%8f%e6%9c%ba%e6%95%b0%e7%94%9f%e6%88%90

  没啥事情, 写了个猜猜猜(猜数字)小游戏. 遇到猜的部分, 那肯定会用到随机函数. 我们为了多平台行为一致, 就统一

整合一个伪随机函数实现方案, 让随机更随机. 一开始看下接口设计 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("亲, 别

                    
                
(0)
打赏 C 猜猜猜????文字小游戏 微信扫一扫

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

C 猜猜猜????文字小游戏
验证码: C 猜猜猜????文字小游戏