《牧场物语:矿石镇的伙伴们》是一款模拟经营类游戏,2003 年发布于 GBA 平台上,因此也简称 GBA 版矿石镇。笔者认为这款游戏是牧场物语系列最经典的一作,没有之一。2019 年该游戏的重置版发布在任天堂 Switch 平台上,但是笔者没有 Switch ,而且由于笔者没收到广告费,就不做宣传了 。
对GBA 版矿石镇熟悉的玩家应该都知道里面的猜数字大小游戏。这个游戏的大概流程是这样:首先,女神会询问玩家是否愿意玩这个游戏,如果愿意则进入游戏。游戏过程中,女神会告诉玩家一个数字,并要求玩家猜测下一个出现数字与当前数字的大小关系。玩家只能回答比当前数字大或者比当前数字小。回答完后,女神会告知新的数字。如果新的数字与前一数字相等,则玩家累计猜对次数不变,游戏继续。如果新的数字与前一数字不相等,且玩家猜测正确,则玩家累计猜对次数增加一次,游戏继续。如果新的数字与前一数字不相等,且玩家猜测错误,则显示玩家猜对次数,游戏结束。游戏中出现的所有数字均为大于等于 0 且小于等于 9 的整数。游戏过程中,玩家累计猜对的次数仅在前后两次数字不等且玩家猜错的情况下显示,其他情况不显示。
这个无聊的猜数游戏制作起来貌似比较简单,在不要求可视化界面的前提下像笔者这样的编程小白借助百度的帮助也能写出来的,只不过笔者写出来的游戏的画风跟原作差距有点大。下面笔者就简单分析一下写代码的步骤。
分步流程解析及代码实现
上文所述游戏流程可以分为两部分,第一部分是游戏意愿判断,第二部分是游戏具体流程。
游戏意愿判断
游戏意愿的流程简单来讲,就是先询问游戏意愿,如果答非所问就回到原点,一直答非所问就一直循环下去。如果回答否,直接退出循环。如果回答是,则开始游戏,在游戏结束的时候退出循环。那么如何通过代码实现这个流程呢?
笔者的思路是创造一个死循环,答非所问就 continue;
,回答是 no 就 break;
, 回答是 yes 就执行游戏流程,执行完毕后 break;
。笔者应用的代码类型是 C++ ,代码框架如下:
#include <iostream>
int main()
{
using namespace std;
char will;
for( ; ; ) // 建立死循环
{
cout << "Type y to start the game. Type n to exit." << endl;
cin >> will; // 输入意愿,y 为 yes,n 为 no
if(will == 'n') // 回答为 n,退出游戏
{
break;
}
else if(will != 'n' && will != 'y') // 答非所问,回到循环起点
{
cout << "Your answer has to be either n or y." << endl;
cout << "Press any key to continue." << endl;
cin.get();
continue;
}
// 这里准备书写具体游戏过程的代码,只有回答为 y 才能执行。
break;
}
}
具体游戏过程
笔者上面那段代码框架里预留了一个位置,准备写具体游戏流程代码。那这段代码该如何写呢?笔者先来梳理一下游戏具体过程的流程:先生成一个随机数,显示出来。再询问玩家下一个数字比当前数字大还是小。如果答非所问则再次询问。如果回答是大或小则生成下一个随机数。如果生成的新随机数与前一个相等,则再次询问玩家下一个数字与当前数字的关系。若新随机数与前一随机数不等,则判断这两个数字的大小关系,并判断玩家是否猜对。若玩家猜错,则停止。若玩家猜对,则继续游戏。代码仍是依旧死循环与分枝结构的组合,具体如下:
int n = 0;
srand((unsigned)time(0));
int randnum = rand() % 10;
int xran;
char sol;
for ( ; ; )
{
// 询问玩家的猜测;
cout << "The current number is " << randnum << endl;
cout << "The next number will be larger or smaller\?" << endl;
cout << "Enter s for smaller, or enter l for larger. ";
cout << "Notice that l is the lower case of letter L, not the number one. " << endl;
cin >> sol;
// 答非所问的处理
if (sol != 's' && sol != 'l')
{
cout << "Your answer has to be either s or l. ";
cout << "Notice that l is the lower case of L, not the number one. " << endl;
continue;
}
xran = rand() % 10; // 生成新随机数
if (xran == randnum) // 新随机数与前一随机数相等时,回到循环起点。
{
cout << "The new number is " << xran << ". ";
cout << "It is equal to the last number. " << endl;
}
else if (xran < randnum)
{
cout << "The new number is " << xran << ". ";
cout << "It is smaller than " << randnum << ". " << endl;
if (sol == 's')
{
cout << "Congratulations! your answer is correct." << endl;
randnum = xran;
n++;
// 猜对了,累积猜对数目 +1,xran 赋值给 randnum,继续循环。
}
else if (sol == 'l')
{
cout << "We are sorry but this time your answer is wrong. ";
cout << "You have made it right " << n << " times." << endl;
cout << "Game Over." << endl;
break;
// 猜错了,显示累积猜对数目,循环结束。
}
}
else if (xran > randnum)
{
cout << "The new number is " << xran << ". ";
cout << "It is larger than " << randnum << ". " << endl;
if (sol == 'l')
{
cout << "Congratulations! your answer is correct." << endl;
randnum = xran;
n++;
// 猜对了,累积猜对数目 +1,xran 赋值给 randnum,继续循环。
}
else if (sol == 's')
{
cout << "We are sorry but this time your answer is wrong. ";
cout << "You have made it right " << n << " times." << endl;
cout << "Game Over." << endl;
break;
// 猜错了,显示累积猜对数目,循环结束。
}
}
}
整体代码
把上文中的第二段代码嵌套到第一段代码中的循环里的对应位置,再做些小的改动,就可以得到完整的代码了。需要注意的是因为代码中用到了 rand()
函数、srand()
函数以及 time()
函数,所以头文件除了iostream
外还需要包含 cstdlib
以及ctime
。下面是整体代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
using namespace std;
cout << "In this game, your computer will come up with ";
cout << "an interger in the range of 0 to 9." << endl;
cout << "You will be asked to guess if the next number is ";
cout << "larger or smaller than the current number." << endl;
char will, sol;
int n = 0;
srand((unsigned)time(0));
int randnum = rand() % 10;
int xran;
for ( ; ; )
{
cout << "Are you willing to play the game\? ";
cout << "Type y to start the game. Type n to exit." << endl;
cin >> will;
cin.ignore(1024, '\n');
if(will == 'n')
{
break;
}
else if(will != 'n' && will != 'y')
{
cout << "Your answer has to be either n or y." << endl;
cout << "Press any key to continue." << endl;
cin.get();
continue;
}
for ( ; ; )
{
cout << "The current number is " << randnum << endl;
cout << "The next number will be larger or smaller\?" << endl;
cout << "Enter s for smaller, or enter l for larger. ";
cout << "Notice that l is the lower case of letter L, not the number one. " << endl;
cin >> sol;
cin.ignore(1024, '\n');
xran = rand() % 10;
if (sol != 's' && sol != 'l')
{
cout << "Your answer has to be either s or l. ";
cout << "Notice that l is the lower case of L, not the number one. " << endl;
cout << "Press any key to continue." << endl;
cin.get();
continue;
}
else if (xran == randnum)
{
cout << "The new number is " << xran << ". ";
cout << "It is equal to the last number. " << endl;
cout << "Press any key to continue. " << endl;
cin.get();
}
else if (xran < randnum)
{
cout << "The new number is " << xran << ". ";
cout << "It is smaller than " << randnum << ". " << endl;
if (sol == 's')
{
cout << "Congratulations! your answer is correct." << endl;
cout << "Press any key to continue." << endl;
cin.get();
randnum = xran;
n++;
}
else if (sol == 'l')
{
cout << "We are sorry but this time your answer is wrong. ";
cout << "You have made it right " << n << " times." << endl;
cout << "Game Over." << endl;
cin.get();
break;
}
}
else if (xran > randnum)
{
cout << "The new number is " << xran << ". ";
cout << "It is larger than " << randnum << ". " << endl;
if (sol == 'l')
{
cout << "Congratulations! your answer is correct." << endl;
cout << "Press any key to continue." << endl;
cin.get();
randnum = xran;
n++;
}
else if (sol == 's')
{
cout << "We are sorry but this time your answer is wrong. ";
cout << "You have made it right " << n << " times." << endl;
cout << "Game Over." << endl;
cin.get();
break;
}
}
}
break;
}
return 0;
}
最后,笔者点开用上面的代码编译生成的 .exe 文件玩了玩,画风是这样的:
当年计算机没有图形界面的时候的电脑游戏估计就是这个画风吧。