当前课程知识点:C++语言程序设计基础 > 第3章 函数 > 函数调用 > 例3-6
函数调用例3-6
每个骰子有六面,点数分别为1、2、3、4、5、6。游戏者在程序开始时输入一个无符号整数,作为产生随机数的种子。
每轮投两次骰子,第一轮如果和数为7或11则为胜,游戏结束;和数为2、3或12则为负,游戏结束;和数为其它值则将此值作为自己的点数,继续第二轮、第三轮...直到某轮的和数等于点数则取胜,若在此前出现和数为7则为负。
l 函数原型:int rand(void);
l 所需头文件:<cstdlib>
l 功能和返回值:求出并返回一个伪随机数
l void srand(unsigned int seed);
l 参数:seed产生随机数的种子
l 所需头文件:<cstdlib>
l 功能:为使rand()产生一序列伪随机整数而设置起始点。使用1作为seed参数,可以重新初化rand()。
大家好
欢迎继续学习C++语言程序设计
这一节我们讲一个好玩的例子
一个投骰子的游戏
俗称色子 大家都见过
那么这个投骰子的游戏呢
规则有一点复杂
那么关键怎么分解这样的功能
怎么去实现它每一个部分功能呢
实际上我们可以思考
如果我把投骰子的过程
单独实现
或者说有人替我实现了
那剩下的事是不是就好办了呢
大家可以想想这个问题
还有怎么去模拟
这个投骰子的过程呢
你投一次骰子
落下来以后
上面的那个数它是个随机的
那么这就是一个
典刑的随机数的问题
在程序中怎么样去模拟
生成随机数
在C++中是有这样的函数的
接下来我会给大家介绍
随机数的函数
以及如何来模拟
这个投骰子的游戏
好 现在我们来看
这个投骰子游戏的规则
这个规则还是很好玩的
每一个骰子有六面
点数分别是1 2 3 4 5 6
这个大家是熟悉的
那游戏者在程序开始的时候
先输入一个无符号整数
作为什么呢
作为产生随机数的种子
那么这个要求呢
大家可能还不太理解
我们先放下
等一会就知道了
好 现在看游戏规则
每一轮投两次骰子
第一轮如果和数为7或者11
那么玩家就胜了 游戏结束
如果和数是2 3 或者12
那么玩家就输了 游戏也结束
如果既不赢又不输
那怎么办呢
好 把这个和数存下来
存下这个和数的值
作为这个玩家他自己的点数
那么继续第二轮
第三轮等等等等
一直继续玩
直到什么时候分出胜负呢
如果某一轮的和数
等于了刚才存下的点数
那么这个玩家赢了 游戏结束
如果还没到赢呢
就先遇到什么呢
先遇到和数是7的情况
那这个玩家他就输了
游戏也结束
我相信
你现在可能觉得哎呀
这个怎么这么麻烦呢
这个到底怎么写这个程序
从什么地方下手
其实它的关键问题在什么地方
在于你老想着
我怎么去模拟那个投骰子
这个问题一旦解决了
你会发现问题逻辑非常简单
所以我们分解一下功能
专门写一个函数
用来模拟投骰子的过程
它能模拟投骰子
并且计算出和数
并且把这个和数
返回给调用者
这样的话我们的主函数逻辑
只要专注于玩游戏就行了
有一个假设自动机器
一个独立的函数
是帮我们做投骰子的
好 那么现在还有一个问题
投骰子怎么模拟
这就需要随机数生成函数
在C++的标准库里面
是有一个rand函数了
这个rand是专门用来
产生随机数的
产生什么随机数呢
叫做伪随机数
也就是假的随机数
为什么说它是尾随机数呢
大家可以编个程序试一试
我建议大家课后去试试
很简单
你就写一个循环
多次调用这个rand函数
那你就会看到
每次调用rand函数
它就产生一个整数
每次调用它产生一个整数
然后你调用很多次
比如你循环一百次 一千次
你会发现 看起来
它产生的随机数都是均匀分布的
真的是看起来随机的
没有什么规律的
那不就很好吗
好 你记下你一次运行的结果
你把你的程序再运行一遍
你会发现它产生的随机数序列
是一模一样的
那么这样的随机数
就叫做伪随机数 假的嘛
每次运行产生同样的序列
那这个怎么能当游戏去玩呢
因为在游戏这样的程序中
是大量的需要产生随机数的
好
那么C++的解决途径是什么呢
有一个办法
它还要一个
叫做随机数种子的东西
这就是我们题目要求
一开始说的
在程序运行开始
让用户输入一个整数
作为产生随机数的种子
在C++中
专门有一个函数叫srand
是种那个种子的函数
我们在这里也给出了
srand函数的原型
以及它的参数
它需要的头文件
那么这个srand函数
它的功能就是专门为了rand
产生一个随机数序列
去设置种子的
设置整数的一个起始点
那么默认情况下呢
它种子都是一样的
所以随机数序列是一样的
我们只要每一次运行的时候
给一个不同的种子
它就可以产生不同的随机数序列
下面我们来看一下这个源代码
在这个投骰子游戏的程序中呢
我们先将投骰子的模拟过程
抛开一边
假设已经有这么一个函数
可以为我们调用了
rollDice这个函数
这个函数模拟
每次投两下骰子
并且计算那个和数返回
如果这个函数已经存在了
有了
那么主函数就专注于
游戏的逻辑就可以了
我们现在先来看这个主函数
好 在主函数中呢
我们首先要输入随机数的种子
然后将这个种子传递给rand
因为rand是一个伪随机数的函数
那么用srand种一下种子
这样每一次种子不同
它产生的随机数序列也就会不同
然后我们会用
这个switch case语句
来处理第一次玩游戏的这个逻辑
第一次玩游戏的时候
投骰子以后
如果这个和数是7或者11
玩家就胜了
所以大家看
这两个case标号共用了一组语句
case7和case11
这是两个标号
共用 将status设成WIN状态
设成赢
然后break 共用这个语句
那么如果是和数为2
3 12 那就输了
所以case2 case3 case12
这三个标号
又共用另外一组语句
就是把status设为LOSE
他输了
然后break退出switch case结构
如果是其他情况呢
那么就是不赢不输
这种情况下需要把它的和数
记下来作为自己的点数
所以我们看
在default这个分支里面
这个状态设成游戏中PLAYING
然后这个sum存到mypoint里面
作为游戏玩家的点数
好 那这样第一轮就算结束了
也许胜了 也许负了
也许未分胜负
接下来
我们就要进行后续的游戏了
判断这个状态是输是赢
还是继续呀
只要这个状态还是游戏中
我们看这个while后面
status只要等于PLAYING
那么就继续游戏
这个游戏过程
都在这个while循环体里面了
好 去调用rollDice函数
模拟一次投骰子
并且返回了这个和数
判断一下
这个和数如果等于我的点数
等于myPoint
那么就将WIN设置到status里面
赢了
如果这个和数是7
那么还没来得及赢 他就输了
已经和数是7了
那就将status设成LOSE
就输了
那么我们看
赢了或者输了
status都会被改变
如果既没有赢也没有输
status就还是原来的状态
还是PLAYING状态
所以转回到循环头上去
这个while就要判断
当前status是不是
依旧为PLAYING
如果它已经不等于PLAYING了
就说明游戏结束了
不管输赢反正结束了
退出这个游戏
好 那么循环往复
只要没分出输赢就继续游戏
当某个时刻如果退出while循环
一定是分出输赢了
所以在while循环之后呢
就要判断
为什么退出来
看这个status是WIN 是吗
如果等于WIN 就说明赢了
输出赢
否则呢 那一定是输了
不赢不输不会退出游戏的
所以如果不是WIN的话
那就是输出玩家输了
这个逻辑大家看是不是很简单
其实投骰子的游戏规则很清楚
主函数的逻辑也非常简单
那么现在是时候
要解决什么的问题呢
要解决
如何模拟投骰子的过程的问题了
现在我们来看
这个简单的函数
非常短 就这么几行
怎么模拟呢
调用rand函数
产生一个随机数
但是这个随机数
是整个整数取值范围之内
随机得到的一个数
而我们需要的投骰子的
在上面那个面的那个数
它是1到6之间的
怎么让
一个在整个整数范围之内的数
处于1到6之间呢
这个技巧就是除以6取余数
如果除以6取余数
这个数会是0到5
那怎么办呢
我们再加上1
它不就移动到1到6这个位置了吗
所以连续做两次这样的操作
就模拟投了两次骰子
然后把它们的数加起来
就得到这个和数
在这里呢
输出一下这个和数
然后将这个和数return
返回给调用者
那么这道题由于把功能分解开了
所以各自实现起来
逻辑都非常简单
很轻松就可以实现了
那么这里是某一次玩的时候
玩家得到的这么一个结果
-导学
--第1章导学
-计算机系统简介
--计算机系统简介
--计算机系统简介 测试题
-计算机语言和程序设计方法的发展
--计算机语言和程序设计方法的发展 测试题
-面向对象的基本概念
--面向对象的基本概念 测试题
-程序的开发过程
--程序的开发过程
--程序的开发过程 测试题
-信息的表示和储存
--计算机的数字系统
--数据的编码表示
--信息的表示和储存 测试题
-实验指导
-导学
--第二章导学
-C++语言概述
--C++语言概述 测试题
-基本数据类型、常量、变量
--程序举例
--基本数据类型、常量、变量 测试题
-运算与表达式
--运算与表达式 测试题
-实验二:简单程序设计(上)
-数据的输入和输出
--数据的输入和输出
--数据的输入和输出 测试题
-选择结构
--if语句
--switch语句
--选择结构 测试题
-循环结构
--for语句
--循环结构 测试题
-自定义类型
--自定义类型
--自定义类型
-第2章小结
--第二章小结
-实验二:C++简单程序设计(下)
-导学
--导学
-函数定义
--函数定义
--函数定义 测试题
-函数调用
--例3-2
--例3-3
--例3-4
--例3-5
--例3-6
--函数调用 测试题
-嵌套与递归
--例3-9
--例3-10
--嵌套与递归 测试题
-函数的参数传递
--函数的参数传递
--函数的参数传递 测试题
-引用类型
--引用类型 测试题
-含有可变参数的函数
--含有可变参数的函数 测试题
-内联函数
--内联函数 测试题
-constexpr函数
--CONSTEXPR函数课后习题
-带默认参数值的函数
--带默认参数值的函数 测试题
-函数重载
--函数重载 测试题
-C++系统函数
--C++系统函数习题
-第3章小结
--第三章小结
-实验三(上)函数的应用
-实验三(下)函数的应用
-导学
--导学
-面向对象程序的基本特点
--面向对象程序的基本特点 测试题
-类和对象
--类和对象的定义
--类和对象 测试题
-构造函数
--构造函数基本概念
--委托构造函数
--复制构造函数
--构造函数 测试题
-析构函数
--析构函数
--析构函数 测试题
-类的组合
--类的组合
--类的组合程序举例
--前向引用声明
--类的组合 测试题
-UML简介
--UML简介
--UML简介课后习题
-结构体与联合体
--结构体与联合体 测试题
-枚举类
--枚举类
--枚举类 测试题
-第4章小结
--第四章小结
-实验四(上)
--实验四(上)
-实验四(下)
--实验四(下)
-导学
--导学
-标识符的作用域与可见性
--标识符的作用域与可见性 测试题
-对象的生存期
--对象的生存期
--对象的生存期 测试题
-类的静态成员
--类的静态成员 测试题
-类的友元
--类的友元 测试题
-共享数据的保护
--共享数据的保护 测试题
-多文件结构和预编译命令
--多文件结构和预编译命令 测试题
-第5章小结
--小结
-实验五
--实验五
-导学
--导学
-数组的定义与初始化
--数组的定义与使用
--一维数组应用举例
--数组的定义与初始化 测试题
-数组作为函数的参数
--数组作为函数的参数 测试题
-对象数组
--对象数组
--对象数组 测试题
-基于范围的for循环
-指针的定义和运算
--指针的定义和运算 测试题
-综合实例
--综合实例
-实验六(上)
--实验六上
-指针与数组
--指针数组
--指针与数组 测试题
-指针与函数
--指针类型的函数
--指向函数的指针
--指针与函数 测试题
-对象指针
--对象指针
--对象指针 测试题
-动态内存分配
--动态内存分配 测试题
-智能指针
--智能指针
-vector对象
--vector对象
--vector对象 测试题
-对象复制与移动
--移动构造
--对象复制与移动 测试题
-字符串
--C风格字符串
--string类
--字符串 测试题
-第6章小结
--第六章小结
-综合实例
--综合实例
-实验六(下)
--实验六(下)