您的位置:首页 > 编程语言 > C语言/C++

【C++探索之旅】第一部分第十一课:小游戏,猜单词

2016-03-14 16:21 363 查看


内容简介

1、第一部分[b]第十[b]一课:小游戏,猜单词[/b][b][b][b][b][/b][/b][/b][/b][/b]2、第一部分第十二课预告:指针一出,谁与争锋

小练习

上一课《【C++探索之旅】第一部分第十课:文件读写,海阔凭鱼跃》中我们学习了读写文件的知识。
第一部分的课程也快接近尾声了,下一课我们会学习很重要的指针的知识。之后,我们就进入第二部分:面向对象编程了。哈哈哈,激动不?

目前为止,我们也学了不少内容:编译基本原理,IDE,变量,函数,条件语句,循环语句,引用,数组,文件读写,等等。你应该为自己感到自豪。

俗语说得好:实践是最好的老师。我们学了那么多知识点,却还没有综合地来应用一下,怎么行呢?

这一课我们就用一个小游戏来锻炼吧。

游戏规则很简单:我们输入一个单词,然后把单词里的字母打乱,显示给用户看,让用户猜这个单词是什么。

准备工作和建议这个小游戏看似简单,但对于初学者的话还是有点难度的,因为需要用到我们前几课的一些知识点,例如:

变量

string(字符串)

函数

控制流程,条件语句

数组

如果有知识点生疏了,可以在编写这个游戏前回去复习。

[猜数字]游戏的主旨

我们要写的小游戏的流程是这样:

玩家1输入一个单词

程序将单词打乱

玩家2尝试从打乱的单词猜出原始的单词是什么

下面是一个玩此游戏的一轮的例子:

输入一个单词
MYSTERY

原先的单词是什么 ? MSYRETY
RYTEMSY
猜错了!

原先的单词是什么 ? MSYRETY
SERMYTY
猜错了!

原先的单词是什么 ? MSYRETY
MYSTERY
猜对了! 好棒!


分析以上流程:

在这一轮中,玩家1选择输入MYSTERY(英语"神秘,秘密"的意思)作为要猜的单词给玩家2来猜。

程序将MYSTERY这个单词的字母顺序打乱,然后请玩家2来猜打乱前的原始单词是什么。

玩家2尝试猜测,他猜了3次才猜中:
RYTEMSY:显示"猜错了!"

SERMYTY:还是没猜对

MYSTERY:终于猜对了,祝贺!

当然了,在上面演示的一轮游戏的例子中,玩家2可以看到玩家1输入的原始单词,暂时先这样。到这课最后的改进部分我们会说怎么避免。当然了,聪慧如你也许早就想到好几个办法了。

开始前的一些建议

当我们让一个初学编程的朋友放手一搏,第一次自己写一个比较完整的程序时,是有难度的。

小编也是过来人,以前还没入门编程时感受颇深:看书,照着书上例子敲代码,好像都懂啊。可是一上手自己写比较复杂的代码,就愣住了,不知该从何下手。

"从哪里开始写呢?","我该做什么呢?","我该用什么呢?",等等,都是初学的症候。不过谁都得过了这一阶段,才能体验到美好的入门感觉。

因此,绝对不要对自己灰心!编程么,就是用一种新的思路来解决问题,只要你经过了编程思想的锤炼,你会发现其他很多事情都会显得简单了。

不过,善良如小编,还是不希望你自己过于迷失。毕竟只要稍加提示,你的思路就会更开阔啦。当然了,也许不必提示,你已经把程序写出来了吧。

找到头绪

这个程序的编写其实只有三步:

输入原始单词;

打乱单词的字母顺序;

做循环:请求玩家2输入猜测的单词。只要玩家2没猜到单词,循环就继续进行。

其实以上的三个步骤是相对独立的,因此,与其一开始就很头大地想要一下子把整个程序写出来,为什么不把程序分成三个部分一点点写出来呢?

列出代码的大纲

一开始,肯定是先写main函数啦,毕竟是程序的入口嘛。我们可以先把程序写成这样:

int main()
{
//1 : 请求用户输入单词

//2 : 打乱输入的单词

//3 : 请求用户猜单词

return 0;
}


我们要做的,只是分别用代码实现注释里的这三步而已。看吧,写代码之前先思考,然后做好规划,对于写出条理分明的代码何等重要。

不过我建议大家先实现第1步,接着实现第3步,最后实现最难的第2步。

如何打乱单词呢?

打乱单词的这一步是最难的。需要学习一些基础知识:

抽取随机数

为了做到单词的打乱是随机的,我们需要随机地抽取单词中的字母,那怎么达成这个目的呢?臣妾做不到啊。

不要紧,我们来学习随机数的生成。

首先,须要引入两个头文件:ctime和cstdlib,因为我们要用到这两个头文件中的函数。

然后,我们需要调用函数srand(time(0))来初始化随机数的"种子"(seed)。

然后,一旦"种子"准备好了,就可以用rand函数来生成随机数了,例如:randomNb = rand() % 5; (5就限定了生成的随机数是介于0到4之间)。

srand其实是seed random的缩写,seed在英语中是“种子”的意思。

补充一些摘自百度百科的概念:
========================

【srand
和rand配合使用产生伪随机数序列。rand函数在产生随机数前,需要系统提供的生成伪随机数序列的种子,rand根据这个种子的值产生一系列随机数。
如果系统提供的种子没有变化,每次调用rand函数生成的伪随机数序列都是一样的。srand(unsigned
seed)通过参数seed改变系统提供的种子值,从而可以使得每次调用rand函数生成的伪随机数序列不同,从而实现真正意义上的“随机”。通常可以利
用系统时间来改变系统的种子值,即srand(time(NULL)),可以为rand函数提供不同的种子值,进而产生不同的随机数序列】

【所谓的“伪随机数”指的并不是假的随机数,这里的“伪”是有规律的意思。其实绝对的随机数只是一种理想状态的随机数,计算机只能生成相对的随机数即伪随机
数。计算机生成的伪随机数既是随机的又是有规律的 ——
一部份遵守一定的规律,一部份则不遵守任何规律。比如“世上没有两片形状完全相同的树叶”,这正点到了事物的特性 ——
规律性;但是每种树的叶子都有近似的形状,这正是事物的共性 ——
规律性。从这个角度讲,我们就可以接受这样的事实了:计算机只能产生伪随机数而不是绝对的随机数。】

【通过time()函数来获得计算机系统当前的日历时间(Calendar
Time),处理日期时间的函数都是以本函数的返回值为基础进行运算。其原型为:time_t time(time_t * t);
如果你已经声明了参数t,你可以从参数t返回现在的日历时间,同时也可以通过返回值返回现在的日历时间,即从一个时间点(例如:1970年1月1日0时0
分0秒)到现在此时的秒数。如果参数为空(NULL或0),函数将只通过返回值返回现在的日历时间。】
========================


果我们在使用rand函数前没有用srand函数制定seed的值,或者虽然用了srand函数,但是给它的参数是一个常量,比如srand(1),那么
每次程序运行rand产生的数字都是一样的。只有用例如time()函数来给一个每次都不一样的seed值,才能使得rand的返回值不一样,才能做到
“随机”。

srand函数只需要在rand函数前面调用一次就够了,也只能调用一次,之后你想要调用rand函数几次都无所谓,但是每个程序中不能用两次srand函数,切记。

下面演示一个程序,它会随机生成一个整数,是介于0到4之间的:

#include <iostream>
#include <ctime> // 必须的头文件
#include <cstdlib> // 必须的头文件

using namespace std;

int main()
{
int randomNb(0);

srand(time(0));

randomNb = rand() % 5;

return 0;
}


随机抽取单词中的字母

随机生成一个数字是很不错啊,但是我们的程序是要随机挑选单词里的一个字母呢!

那还不是一样的原理。

我们要随机抽取单词中的字母,只要用下标就可以了。还记得之前的课里提到string很类似数组吗?因此,只要 数组名[下标] 的形式,下标随机就可以了。例如secretWord[2]就是单词的第三个字母。

一旦我们知道如何生成随机数了,那么只要规定生成的随机数的范围就可以啦,范围就是:0~单词中字母数减1

例如:

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

int main()
{
string secretWord("MYSTERY");

srand(time(0));

int position = rand() % secretWord.size();

cout << "随机抽取的字母是: " << secretWord[position];

return 0;
}


从字符串中删除一个字符

那么我们如何构建新的打乱的单词呢?

我们可以用一个循环,从原始单词中每次随机抽取一个字符,然后添加到新的打乱的单词中。

为了避免重复处理同一个字母,我们须要每次将抽取的字母从原始单词中删去。这样,到最后,原始单词的所有字母就会都"跑到"打乱的单词中了。为了从字符串中删除字符,我们可以使用erase这个方法:

secretWord.erase(4, 1);  // 删除原始单词中的第五个字母


erase函数有两个参数:

第一个参数表明从哪个字母开始删除:上例中是4,就表明是从第五个元素开始删除。毕竟数组是从0开始作为第一个下标的嘛。

第二个参数表明删除几个字符:上例中是1,因此只删除从第五个字符开始的1个字符,也就是只删除第五个字符。

创建函数

这一整个程序其实并没有那么复杂,不一定要创建新的函数。但是适时地使用函数绝对是好习惯。在我们的程序中,第二步的主要工作就可以交给一个自己创建的函数来做。

这样,我们就可以在main函数中调用这个函数,如下:

mixedWord = mixLetters(secretWord);


我们将原始的单词secretWord作为函数的参数传递给它,而函数的返回值则赋给打乱的单词mixedWord。

好了,提示就到这里了。
少年,放手一搏吧!

答案

相信你花了一些时间来思考,并且写了程序。第一次你不一定都知道怎么写,但是没关系,重点是思考和尝试的过程。如果不思考直接来看答案,或尝试了一下就放弃,那编程可是学不好的哦。

上面我们已经提过,此游戏的代码可以分为三个部分来实现。第1步和第3步相对容易,只有第2步有些难度。

放上小编自己写的版本。当然了,你可以写得比我更好。我这个版本还是很基础的。

翠花,上代码:
=========================
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>

using namespace std;

//用于打乱单词的函数
string mixLetters(string word)
{
string mixedWord;
int position(0);

//只要还没有抽完单词里的所有字母,就继续while循环
while (word.size() != 0)
{
//在单词中随机选择一个字母
position = rand() % word.size();

//将此字母添加到新的单词mixedWord中,也就是我们最后得到的打乱的单词
mixedWord += word[position];

//将此字母从字符串中删去
//为了不重复处理同一个字母
word.erase(position, 1);
}

//返回打乱后的单词
return mixedWord;
}

int main()
{
string secretWord, mixedWord, userEnteredWord;

//初始化伪随机数的种子
srand(time(0));

//1 : 请求玩家1输入原始单词
cout << "输入一个单词" << endl;
cin >> secretWord;

//2 : 用函数mixLetters将玩家1输入的原始单词打乱顺序
mixedWord = mixLetters(secretWord);

//3 : 请求玩家2猜单词
do
{
cout << endl << "原先的单词是什么 ? " << mixedWord << endl;

cin >> userEnteredWord;

if (userEnteredWord == secretWord)
{
cout << "猜对了! 好棒!" << endl;
}
else
{
cout << "猜错了!" << endl;
}
} while (userEnteredWord != secretWord);//只要没猜对,就再进入while循环
return 0;
}


=========================

不要惊讶于此代码的短小。也许只是你没想到,看了代码才发现,啊,原来这么简单,原来可以这么写。

下面对程序做分步解释吧:

第一步:输入单词

这一步是最简单的。cout来输出一行提示消息。cin来获取用户输入,存放到secretWord变量中。

第二步:打乱单词

这一步是用一个函数mixLetters来实现的。

while (word.size() != 0)
{
position = rand() % word.size();
mixedWord += word[position];
word.erase(position, 1);
}


每一次进入while循环体中,我们都随机挑选单词中的一个字母,然后将其放入新的打乱的单词mixedWord中。最后将这个字母从原始的单词中删去。

一旦处理完原始单词中所有的字母(也就是原始的单词为空了),我们就跳出循环,函数会返回打乱后的单词。

第三步:问用户秘密单词是什么

这一步我们将使用一个do... while循环,以保证我们给用户至少一次猜单词的机会。

用cin来获取用户的输入,然后与secretWord这个原始的单词做比较,一旦两者一致,则获胜;否则就继续循环。

}while (userEnteredWord != secretWord); //只要没猜对,就再进入while循环


每次都显示一条消息:假如没猜对,则显示"猜错了";假如猜到了,则显示"猜对了!好棒!"

改进游戏

好了,我们的程序写完了,不过始终可以改进。我们给出一些改进的建议:

在用户1输入单词之后,想办法"隐藏"单词,不让用户2看到:可以使用加多个空行(endl);也可以有其他办法。

使用户可以一直玩:目前我们的游戏一轮就结束了。你可以在每一轮结束后显示一行信息:"您还想继续新一轮游戏吗?(y/n)"。如果用户输入y,回车,则继续新的一轮;如果用户输入n,回车,则退出游戏。

设置猜测次数上限:比如设置5次作为猜测的机会上限,那么如果用户5次没猜中单词的话,游戏也失败。

计算玩家的平均分:每一轮的游戏所获分数,可以设置比如1次就猜中的得10分,2次才猜中的9分,依次类推。然后把玩家所得总分除以所玩轮数,就是平均分啦

用一个文件储存不少单词,好像字典一样,然后从中随机选择
: 这样你就可以一个人玩了,不需要别人给你出题了。你的程序会从文件中随机选中一个单词,将其打乱,然后你自己来猜。下面是一个字典的例子:

FEATURE
MOTHER
ANSWER
CLOSE
GARAGE
DELETE
ENGINEER
ZERO
YESTERDAY
TOGETHER
JUICE
LAUGH

OFTEN
PEOPLE

KNOWLEDGE

当然,你可以自己填充英语单词,或者去网上下载那种英文字典的txt文件,里面有几万,几十万,甚至几百万个单词,从中选择的话就有猜单词的乐趣和难度啦。

要读取文件中的单词,你可以用我们上一课学到的知识点:读写文件。

如果你自己还想到其他改进的点子,也可以去实现。你会发现通过这个游戏,自己进步了很多。
欢迎把改进后的游戏的代码发给小编噢~

第一部分第十二课预告

今天的课就到这里,一起加油吧!下一课我们学习:指针一出,谁与争锋
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ 程序员 猜单词