掷骰子最普遍的形式是用两个6面骰子。
计算机可以设计一种具有任意面数的骰子,先从6面开始,再进行扩展。
我们想得到从1到6之间的一个随机数。然而,rand()产生的是从0到RAND_MAX范围内的整数;RAND_MAX在stdlib.h中定义,它通常是INT_MAX。因此,需要做一些调整。下面是一种方法:
1、把随机数对6取模,将产生从0到5的整数。
2、加1.新数将为从1到6范围内的整数。
3、为了方便扩展,将步骤1中的数字6用骰子面数来代替。
下面的代码实现了这些想法:
#include <stdlib.h> /*为rand()函数提供原型*/
int rollem(int sides)
{
int roll;
roll = rand()%sides + 1;
return roll;
}
进一步,我们想实现这样的功能:它允许掷任意个骰子,并且返回点数总和。程序清单12.11实现了这样的功能。
/*diceroll.c --掷骰子的模拟程序*/
#include "diceroll.h"
#include <stdio.h>
#include <stdlib.h> /*为rand()函数提供类库*/
int roll_count = 0; /*外部链接*/
static int rollem(int sides) /*这个文件的私有函数*/
{
int roll;
roll=rand()%sides+1;
++roll_count; /*计数函数调用*/
return roll;
}
int roll_n_dice (int dice,int sides)
{
int d;
int total = 0;
if(sides<2)
{
printf("Need at least 2 sides.\n");
return -2;
}
if(dice<1)
{
printf("Need at least 1 die.\n");
return -1;
}
for(d=0;d<dice;d++)
total += rollem(sides);
return total;
}
这个文件中加入了一些新东西。首先,它把rollem()变成由该文件私有的函数,这个函数用于辅助roll_n_dice();其次,为了举例说明外部链接如何工作,文件声明了一个外部变量roll_count,这个变量跟踪记录函数rollem()的调用次数。例子本身有一点不妥,但它显示了外部变量的如何工作的。
再次,文件包含下面的语句:
#include "diceroll.h"
如果使用诸如rand()的标准库函数,您需要在程序中包含标准头文件(对rand()来说是stdlib.h),而不是声明函数,因为头文件中已经包含了正确的声明。我们将效仿这一做法,提供一个头文件diceroll.h以供函数roll_n_dice()使用。将文件名置于双引号而非尖括号中, 是为了指示编译器在本地寻找文件,而不是到编译器存放标准头文件的标准位置去寻找文件。“在本地寻找”的意义取决于具体的C实现。一些常见解释是将头文件与源代码文件放在同一个目录或文件夹中。程序清单12.12显示了该头文件的内容。
程序清单12.12 diceroll.h文件
//diceroll.h
extern int roll_count;
int roll_n_dice(int dice,int sides);
这个头文件中包含函数原型声明一和个extern声明。因为文件diceroll.c包含了这一头文件,它也就实际上包含了roll_count的两个声明:
extern int roll_count; //来自头文件
int roll_count = 0; //来自源代码文件
这是可以的,一个变量只可以有一个定义声明,但使用extern的声明是一个引用声明,这样的声明想用多少就可以用多少。
使用roll_n_dice()的程序也应该包含这一头文件。这样做不仅仅提供roll_n_dice()原型,还使得roll_count对程序可用。程序清单12.13证明了这些。
//manydice.c --多次掷骰子的模拟程序
//与diceroll.c一起编译
#include<stdio.h>
#include<stdlib.h> //为srand()提供原型
#include<time.h> //为time()提供原型
#include"dicerlll.h" //为roll_n_dice()和roll-count提供原型
int main(void)
{
int dice ,roll;
int sides;
srand((unsigned int )time(0)); //随机化种子
printf("Enter the number of sides per die,0 to stop.\n");
while(scanf("%d",&sides)==1 && sides>0)
{
printf("How many dice?\n");
scanf("%d",&dice);
roll = roll_n_dice(dice,sides);
printf("You have rolled a %d using %d %d-sided dice.\n",roll,dice,sides);
printf("How many sides?Enter 0 to stop.\n);
}
printf("The rollem() function was called %d times.\n",roll_count); /*使用外部变量*/
printf("Good Fortune To You!\n");
return 0;
}
将程序清单12.13与包含程序清单12.11的文件一起编译。为了简化问题,把程序清单12.11、12.12和12.13放在同一文件中或同一目录下。运行最后得到的程序,输出应该像下面这样:
Enter the number of sides per die,0 to stop.
6
How many dice?
2
You have rolled a 12 using 2 6-sided dece.
How many sides?Enter 0 to stop.
6
How many dice?
2
You have rolled a 4 using 2 6-sided dice.
How many sides?Enter 0 to stop.
6
How many dice?
2
You have rolled a 5 using 2 6-sided dice.
How many sides?Enter 0 to stop.
0
The rollem() funcation was called 6 times.
GOOD FORRUNE TO YOU!
因为程序使用srand()来随机确定随机数种子,所以大多数情况下,即使有相同的输入也不可能得到相同的输出。注意,manydice.c中的main()确实可以访问diceroll.c中定义的变量roll_count。
可以使用多种方式使用roll_n_dice()。对于sides为2的情形,程序模仿掷硬币,面朝上为2,背朝上为1.您可以很容易地修改程序来像显示总体结果那样显示个别结果,或者建一个掷双骰子赌博模拟器。
来源:oschina
链接:https://my.oschina.net/u/2754880/blog/804818