C语言编写猜数字游戏及随机数生成方法

C语言编写猜数字游戏及随机数生成方法


前言

对于C语言初学者来说,当我们的翻开课本咕叽咕叽读完C语言概述后,就会紧接着面临C语言控制语句(顺序,选择和循环),然后不约而同都会面临用三大控制语句编写猜数字游戏的问题。这的确是一个比较容易编写的小游戏,但同时也是一个很好练习机会,不仅仅让我们充分利用所学知识完成对程序的编写,同时也引导我们思考如何用C语言生成随机数。


一、猜数字小游戏

内容:

首先我们要了解一下什么是猜数字。顾名思义,就是随机指定一个数字,然后让人猜数,通过反馈的信息(猜大了或者猜小了)来逐渐锁定最终值。

步骤:

定义好我们程序的目标后,我们就要开始对程序进行设计,要有一个明确的步骤。
1.首先我们需要提升游玩者体验,就应该有一个菜单。
2.其次游玩者可能需要循环往复玩这个游戏,我们就应该将游戏放入循环体内。
3.最后才是我们对于游戏具体的设计。在游戏具体设计内,我们需要让系统生成一个随机数,然后让游玩者输入一个数字,通过对二者的比较,反馈信息,以便让游玩者逐渐接近具体目标。

代码的实现:

#define _CRT_SECURE_NO_WARNINGS  //防止sancf报安全性错误
#include<time.h>//time()函数头文件
#include<stdlib.h>//rand(),srand()函数头文件
#include<stdio.h>//printf(),scanf()函数头文件
void menu()//进入游戏对菜单的打印
{
	printf("***************************\n");
	printf("******** 1. play **********\n");
	printf("******** 0. exit **********\n");
	printf("***************************\n");
}

int main()
{
	int input = 0;//定义一个变量input,存放用户输入的值
	do
	{		    //函数可以简单理解为对一段代码的封装。
		menu();//这是菜单的打印,利用函数可以避免主函数过于冗长
		printf("请选择(1/0):>");//让用户输入1开始玩游戏,0则退出游戏
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//游戏具体实现
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误\n");
		}
	} while (input);//0为假,非0为真,真则会重新进入循环体,假则会退出循环体
	return 0;
}

然后就是对游戏具体实现的思考,首先我们要生成一个随机数,现在的C编译器都提供了一个基于ANSI标准的伪随机数发生器函数,用来生成随机数,它们就是rand()和srand()函数。

void game()
{
	srand((unsigned int)time(NULL));//为rand()函数重新“播种”,使得rand()产生随机值(rand()产生的随机值我们称为“种子”)发生变化  (具体我们在第二节详细解释)
	int ret = rand()%100+1;//生成的随机值1-100
	int guess = 0;
	while (1)
	{
		printf("请猜数字:>");
		scanf("%d", &guess);
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("猜对了\n");
			break;
		}
	}
}

但实际上我们不太喜欢将rand()和srand()函数放得太近,因为这样子反复运行程序还是容易使得rand()函数产生相近的值,所以我们比较提倡将srand()函数放到主函数中,事实上每次用到rand()函数只需要srand()函数“播种”一次即可。接下来展示就是猜数字游戏所示全部代码:

#define _CRT_SECURE_NO_WARNINGS  //防止sancf报安全性错误
#include<time.h>//time()函数头文件
#include<stdlib.h>//rand(),srand()函数头文件
#include<stdio.h>//printf(),scanf()函数头文件
void game()
{
	int ret = rand()%100+1;//生成的随机值1-100
	int guess = 0;
	while (1)
	{
		printf("请猜数字:>");
		scanf("%d", &guess);
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}
		else
		{
			printf("猜对了\n");
			break;
		}
	}
}
void menu()//进入游戏对菜单的打印
{
	printf("***************************\n");
	printf("******** 1. play **********\n");
	printf("******** 0. exit **********\n");
	printf("***************************\n");
}

int main()
{
	int input = 0;//定义一个变量input,存放用户输入的值
	srand((unsigned int)time(NULL));//为rand()函数重新“播种”,使得rand()产生随机值(rand()产生的随机值我们称为“种子”)发生变化  (具体我们在第二节详细解释)
	do
	{		    //函数可以简单理解为对一段代码的封装。
		menu();//这是菜单的打印,利用函数可以避免主函数过于冗长
		printf("请选择(1/0):>");//让用户输入1开始玩游戏,0则退出游戏
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//游戏具体实现
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("输入错误\n");
		}
	} while (input);//0为假,非0为真,真则会重新进入循环体,假则会退出循环体
	return 0;
}

代码运行截图:
在这里插入图片描述

二、随机数生成的方法

接下来我们对刚刚展示的利用C语言生成随机数做一个具体解释。
现在的C编译器都提供了一个基于ANSI标准的伪随机数发生器函数,用来生成随机数,它们就是rand()和srand()函数。
然后我们用MSDN软件查看一下对于rand()和srand()函数的表述:

1.int rand( void )
Generates a pseudorandom number(生成伪随机数)

The rand function returns a pseudorandom integer in the range 0 to RAND_MAX(rand函数返回一个范围为0到RAND_MAX的伪随机整数)(C语言规定RAND_MAX值为32767)
此时我们编写一个代码尝试一下:

void main(void)
{
	int i;
	for (i = 0; i < 10; i++)
		printf("%d ", rand());
	printf("\n\n\n\n");
}

不难发现运行两次后,会重复出现一样的数字,这就违背了我们想要随机的本意。实际上,rand() 函数产生的随机数是伪随机数,是根据一个数值按照某个公式推算出来的,这个数值我们称之为“种子”,种子和随机数之间的关系是一种正态分布关系,种子在每次启动计算机时是随机的,但是一旦计算机启动以后它就不再变化了;也就是说,每次启动计算机以后,种子就是定值了,所以根据公式推算出来的结果(也就是生成的随机数)就是固定的。

在这里插入图片描述
返回MSDN软件继续查看关于rand()函数描述:
Use the srand function to seed the pseudorandom-number generator before calling rand.(在调用rand之前,使用srand函数为伪随机数生成器播种)

2.void srand( unsigned int seed )
Sets a random starting point.(设置随机起点)

而要让 srand()函数随机播种,我们则必须让参数是一个随机值,这就产生悖论。所以前辈们在实际开发中,就用时间作为参数,只要每次播种的时间不同,那么生成的种子就不同,最终的随机数也就不同。而要得到时间则又引出了另一个函数time()函数

3.time_t time( time_t *timer )
Gets the system time.(获取系统时间。)

time()函数返回类型为time_t,time_t 实际在C语言中被定义为长整型,而srand()函数参数为unsigned int(无符号整形),所以要强制类型转换,而且不需要为time()函数设置参数,故用空指针NULL代替。

最后我们得到srand()函数设置随机数起点写法

srand( (unsigned int)time( NULL ) );

最后我们试验一下:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void main(void)
{
	int i;
	srand((unsigned int)time(NULL));
	for (i = 0; i < 10; i++)
		printf("  %6d\n", rand());
}

在这里插入图片描述
在这里插入图片描述

总结

希望能够对你有所帮助,因为我也是第一次尝试写技术性博客,如有问题,烦请指正,谢谢你的阅览。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是用 C 语言编写 RSA 算法的完整代码,其中 pqnedk 为随机数生成: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <openssl/bn.h> #include <gmp.h> void generate_pq(mpz_t p, mpz_t q, int bits) { BN_CTX *ctx = BN_CTX_new(); BIGNUM *bn_p = BN_new(); BIGNUM *bn_q = BN_new(); BN_generate_prime_ex(bn_p, bits, 1, NULL, NULL, NULL); BN_generate_prime_ex(bn_q, bits, 1, NULL, NULL, NULL); mpz_set_str(p, BN_bn2dec(bn_p), 10); mpz_set_str(q, BN_bn2dec(bn_q), 10); BN_free(bn_p); BN_free(bn_q); BN_CTX_free(ctx); } void compute_n_phi(mpz_t n, mpz_t phi, mpz_t p, mpz_t q) { mpz_mul(n, p, q); mpz_t p_minus_one, q_minus_one; mpz_init(p_minus_one); mpz_init(q_minus_one); mpz_sub_ui(p_minus_one, p, 1); mpz_sub_ui(q_minus_one, q, 1); mpz_mul(phi, p_minus_one, q_minus_one); mpz_clear(p_minus_one); mpz_clear(q_minus_one); } void choose_e(mpz_t e, mpz_t phi) { mpz_set_ui(e, 65537); while (mpz_gcd(e, phi) != 1) { mpz_add_ui(e, e, 2); } } void compute_d(mpz_t d, mpz_t e, mpz_t phi) { mpz_t x, y; mpz_init(x); mpz_init(y); mpz_gcdext(d, x, y, e, phi); if (mpz_sgn(d) < 0) { mpz_add(d, d, phi); } mpz_clear(x); mpz_clear(y); } void encrypt(mpz_t c, mpz_t m, mpz_t n, mpz_t e) { mpz_powm(c, m, e, n); } void decrypt(mpz_t m, mpz_t c, mpz_t n, mpz_t d) { mpz_powm(m, c, d, n); } int main() { mpz_t p, q, n, phi, e, d, m, c; mpz_inits(p, q, n, phi, e, d, m, c, NULL); int bits = 1024; // RSA key size generate_pq(p, q, bits); compute_n_phi(n, phi, p, q); choose_e(e, phi); compute_d(d, e, phi); gmp_printf("p = %Zd\n", p); gmp_printf("q = %Zd\n", q); gmp_printf("n = %Zd\n", n); gmp_printf("phi = %Zd\n", phi); gmp_printf("e = %Zd\n", e); gmp_printf("d = %Zd\n", d); srand(time(NULL)); // seed random number generator mpz_urandomb(m, rand(), bits-1); encrypt(c, m, n, e); decrypt(m, c, n, d); gmp_printf("m = %Zd\n", m); gmp_printf("c = %Zd\n", c); mpz_clears(p, q, n, phi, e, d, m, c, NULL); return 0; } ``` 在以上代码中,我使用了 OpenSSL 中的 BN 库来生成随机数和计算大数,同时也使用了 GMP 库来进行大数运算。为了保证随机数的真正随机性,我使用了 time 函数来初始化随机数生成器。 需要注意的是,由于 RSA 算法的密钥长度通常较长,因此运算时间会比较长,尤其是在加密和解密过程中。因此,在实际应用中,为了提高效率,通常会采用一些优化方法,如使用中国剩余定理、快速模幂算法等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值