C Primer Plus 第12章 12.5 掷骰子

原创
2016/12/13 06:23
阅读数 82

掷骰子最普遍的形式是用两个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.您可以很容易地修改程序来像显示总体结果那样显示个别结果,或者建一个掷双骰子赌博模拟器。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部