命令行版扫雷(vc08)

 

ContractedBlock.gif ExpandedBlockStart.gif 类似开发文档的物体
 
   
模拟鼠标各种按键

左键 翻开
右键 标雷
左右键 翻开周围
先判断当前点是否为已翻开的点

时间
地雷计数器
清屏


展开
大于8时不管
小于等于8时翻开本身
为0时翻开周围的
输出
同雷数图
雷区判断

判断游戏结束
剩下的是否和雷数相等
*标记出所有的雷
踩到雷了
动态数组


第一次操作时才开始布雷
布雷后制作雷数图
0无雷 9本身是雷 10已经翻开的
10 +X 表示 已经翻开的有数字的
20 +X 表示 标了雷区的 (29则为正确标注的)
20表示边界

雷数选择范围
*翻开标记为雷区的点时进行确认操作
*选择重新开始等
接着这盘游戏
仅悔一步
*保存游戏?
*作弊功能?




//
11.27
传值参数有很多的相似,可以进行封装:结构体,容器,数组

 

 

ContractedBlock.gif ExpandedBlockStart.gif main.cpp
 
   
#include < iostream >
#include
< vector >
#include
< string >
#include
" function.h "

using namespace std;

int main()
{
int hight;
int width; // 6*6开始
int bob;
while ( 1 ){
cout
<< " 请输入雷阵高度(6-99): " ;
cin
>> hight;
if (hight < 100 && hight > 5 ){
break ;
}
}
while ( 1 ){
cout
<< " 请输入雷阵宽度(6-99): " ;
cin
>> width;
if (width < 100 && width > 5 ){
break ;
}
}
while ( 1 ){
cout
<< " 请输入地雷数目(8- " << ( width * hight / 10 * 9 ) << " ): " ;
cin
>> bob;
if (bob <= (width * hight / 10 * 9 ) && bob > 7 ){
break ;
}
}



vector
< vector < int > > map( hight + 2 , vector < int > (width + 2 , 0 ) ); // 创建地图

#if 0
map[
0 ][ 0 ] = 9 ;
map[
0 ][width - 1 ] = 9 ;
map[hight
- 1 ][ 0 ] = 9 ;
map[hight
- 1 ][width - 1 ] = 9 ;
#endif


setGame(map, hight, width, bob);
playGame(map, hight, width, bob);
}

 

ContractedBlock.gif ExpandedBlockStart.gif mapset.cpp
 
   
#include " function.h "
#include
< ctime >
#include
< vector >
using namespace std;

void setBob(vector < vector < int >> & map, int bob , int r, int w)
// 开始随机布雷,并使得刚开始挖的点不为雷区
{
// 变量声明,确定map的高度和宽度等
vector < vector < int >> ::difference_type hight = map.end() - map.begin();
vector
< int > ::difference_type width = map[ 0 ].end() - map[ 0 ].begin();
vector
< vector < int >> ::size_type tmpH;
vector
< int > ::size_type tmpW;

// 开始随机布雷
srand(static_cast < int > (time( 0 )));
for ( int i = 0 ;i != bob; ++ i){
tmpH
= rand() % (hight - 2 ) + 1 ;
tmpW
= rand() % (width - 2 ) + 1 ;
if (map[tmpH][tmpW] == 9 ){
-- i;
}
else {
map[tmpH][tmpW]
= 9 ;
}
}

// 使刚开始挖的点不为雷区
if (map[r][w] == 9 ){
do {
tmpH
= rand() % (hight - 2 ) + 1 ;
tmpW
= rand() % (width - 2 ) + 1 ;
}
while (map[tmpH][tmpW] != 9 );
}
map[tmpH][tmpW]
= 9 ;
map[r][w]
= 0 ;

}

void setMap(vector < vector < int >> & map)
// 设置每格中显示的雷数
{
// 变量声明,确定map的高度和宽度等
vector < vector < int >> ::difference_type hight = map.end() - map.begin();
vector
< int > ::difference_type width = map[ 0 ].end() - map[ 0 ].begin();
for ( int i = 1 ;i != hight - 1 ; ++ i){
for ( int j = 1 ;j != width - 1 ; ++ j){
if (map[i][j] > 8 ){
++ map[i - 1 ][j - 1 ];
++ map[i - 1 ][j];
++ map[i - 1 ][j + 1 ];
++ map[i][j - 1 ];
++ map[i][j + 1 ];
++ map[i + 1 ][j - 1 ];
++ map[i + 1 ][j];
++ map[i + 1 ][j + 1 ];
}
}
}

for ( int i = 1 ;i != hight; ++ i){
for ( int j = 1 ;j != width; ++ j){
if (map[i][j] > 9 ){
map[i][j]
= 9 ;
}
}
}

// 设置边界的数值为20
for ( int i = 0 ;i != width; ++ i){
map[
0 ][i] = 20 ;
map[hight
- 1 ][i] = 20 ;
}
for ( int i = 1 ;i != hight; ++ i){
map[i][
0 ] = 20 ;
map[i][width
- 1 ] = 20 ;
}
}


int digBob(vector < vector < int >> & map , int r , int w)
// 挖雷,返回已经挖开点的总数
// -1表示挖到雷了
{
static int count = 0 ;
if (map[r][w] > 9 ){
return count; // 挖的点已经翻开,或为边界,或标为雷区
}
else if (map[r][w] == 9 ){
endGame(map,
0 , 0 );
return - 1 ;
}
else {
map[r][w]
+= 10 ;
++ count; // 挖点记数器

// 当前点的周围雷数为0则继续挖周围的点
if (map[r][w] == 10 ){
digBob(map,r
- 1 ,w - 1 );
digBob(map,r
- 1 ,w);
digBob(map,r
- 1 ,w + 1 );
digBob(map,r,w
- 1 );
digBob(map,r,w
+ 1 );
digBob(map,r
+ 1 ,w - 1 );
digBob(map,r
+ 1 ,w);
digBob(map,r
+ 1 ,w + 1 );
}

return count;
}
}

 

ContractedBlock.gif ExpandedBlockStart.gif command.cpp
 
   
#include " function.h "
#include
< iostream >
#include
< string >
#include
< vector >
using namespace std;
int getCmd( int & hight, int & width)
// 获取用户指令,返回坐标(通过引用)和操作类型
// 如输入错误则返回相应错误代码:
// -1:输入错误 -2:坐标越界
// hight及width的值可能会被修改
{
int temp; // 存放坐标

string cmd;
do {
cout
<< " 请输入指令: " ;
getline( cin,cmd);
}
while (cmd.empty());

int sizeCmd = cmd.size();
if (sizeCmd == 4 || sizeCmd == 5 ){ // 用户输入4或5个字符的可能性最大
// 检查输入是否正确
for ( int i = 0 ;i != 4 ; ++ i){
if (cmd[i] < 48 || cmd[i] > 57 ){
return - 1 ;
}
}
temp
= (cmd[ 0 ] - 48 ) * 10 + (cmd[ 1 ] - 48 );

// 检查输入坐标是否越界
if (temp <= hight){
hight
= temp;
}
else {
return - 2 ;
}
temp
= (cmd[ 2 ] - 48 ) * 10 + (cmd[ 3 ] - 48 );
if (temp <= width){
width
= temp;
}
else {
return - 2 ;
}

if (sizeCmd == 4 ){
return 1 ; // 默认返回值
}
else {
if (cmd[ 4 ] > 51 || cmd[ 4 ] < 49 ){
return - 1 ;
}
else {
return ( cmd[ 4 ] - 48 );
}
}
}
else if (sizeCmd == 1 ){
switch (cmd[ 0 ])
{
case ' ? ' :
case ' h ' :
case ' H ' :
return 4 ; // 帮助
break ;
case ' r ' :
case ' R ' :
return 5 ; // 重新开始
break ;
case ' e ' :
case ' E ' :
return 6 ; // 退出
break ;
default :
return - 1 ;
}
}
else {
return - 1 ;
}

}


void setGame(vector < vector < int >> & map, int hight, int width, int bob)
{
outpMethod();
setMap(map);
outpMap(map);

int hightGet;
int widthGet;

while ( 1 ){
hightGet
= hight;
widthGet
= width;
switch ( getCmd(hightGet, widthGet) ){
case - 1 :
cout
<< " 输入错误,请重新输入 " << endl;
break ;
case - 2 :
cout
<< " 坐标越界,请重新输入 " << endl;
break ;
case 1 :
setBob(map, bob, hightGet, widthGet);
setMap(map);
if ( digBob(map, hightGet, widthGet) == hight * width - bob){
endGame(map,
0 , 1 );
}
else {
outpGame(map,bob);
}
return ; // 退出函数
case 2 :
case 3 :
cout
<< " 游戏刚开始还是挖雷吧 " << endl;
break ;
case 4 :
outpHelp();
outpMethod();
outpMap(map);
break ;
case 5 :
// 还没想好怎么重新开始
break ;
case 6 :
exit(
0 );
break ;
default :
;
}
}

}

void playGame(vector < vector < int >> & map , int hight, int width, int bob)
{
int hightGet;
int widthGet;
int pointAmount = hight * width;

int digCount = 0 ;
int flatCount = 0 ;
bool flat = 1 ;

while ( flat ){
hightGet
= hight;
widthGet
= width;
switch ( getCmd(hightGet, widthGet) ){
case - 1 :
cout
<< " 输入错误,请重新输入 " << endl;
break ;
case - 2 :
cout
<< " 坐标越界,请重新输入 " << endl;
break ;
case 1 :
// 挖雷
digCount = digBob(map, hightGet, widthGet);
outpGame(map, bob
- flatCount);
if (digCount + bob == pointAmount){
flat
= 0 ;
endGame(map,
0 , 1 );
}
break ;
case 2 :
// 标记/取消标记 雷区
if (map[hightGet][widthGet] < 10 ){
map[hightGet][widthGet]
+= 20 ;
++ flatCount;
outpGame(map, bob
- flatCount);
}
else if (map[hightGet][widthGet] > 19
&& map[hightGet][widthGet] != 30 )
{
map[hightGet][widthGet]
-= 20 ;
-- flatCount;
outpGame(map, bob
- flatCount);
}
else {
cout
<< " 这个点已经被挖过了 " << endl;
}
break ;
case 3 :
// 翻开周围
if (map[hightGet][widthGet] < 11
|| map[hightGet][widthGet] > 18 )
{
cout
<< " 不能对该点进行此操作 " << endl;
break ;
}
else {
int ardigCount = 0 ;
if (map[hightGet - 1 ][widthGet - 1 ] > 20 ){
++ ardigCount;}
if (map[hightGet - 1 ][widthGet] > 20 ){
++ ardigCount;}
if (map[hightGet - 1 ][widthGet + 1 ] > 20 ){
++ ardigCount;}
if (map[hightGet][widthGet - 1 ] > 20 ){
++ ardigCount;}
if (map[hightGet][widthGet + 1 ] > 20 ){
++ ardigCount;}
if (map[hightGet + 1 ][widthGet - 1 ] > 20 ){
++ ardigCount;}
if (map[hightGet + 1 ][widthGet] > 20 ){
++ ardigCount;}
if (map[hightGet + 1 ][widthGet + 1 ] > 20 ){
++ ardigCount;}
if (ardigCount == map[hightGet][widthGet] - 10 ){
digBob(map, hightGet
- 1 , widthGet - 1 );
digBob(map, hightGet
- 1 , widthGet);
digBob(map, hightGet
- 1 , widthGet + 1 );
digBob(map, hightGet, widthGet
- 1 );
digBob(map, hightGet, widthGet
+ 1 );
digBob(map, hightGet
+ 1 , widthGet - 1 );
digBob(map, hightGet
+ 1 , widthGet);
digCount
= digBob(map, hightGet + 1 , widthGet + 1 );
outpGame(map, bob
- flatCount);
}
else {
cout
<< " 暂时不能对该点进行此操作 " << endl;
}
if (digCount + bob == pointAmount){
flat
= 0 ;
endGame(map,
0 , 1 );
}
}
break ;

case 4 :
outpHelp();
outpGame(map, bob
- flatCount);
break ;
case 5 :
// 还没想好怎么重新开始
break ;
case 6 :
exit(
0 );
break ;
default :
;
}
// switch语句
} // 里层while循环
}

void endGame(vector < vector < int >> & map, int bobLeft, int flat)
// 结束游戏.
// 1表示成功 0表示失败:
{
outpGame(map,bobLeft,
1 );
}

ContractedBlock.gif ExpandedBlockStart.gif output.cpp
 
   
#include " function.h "
#include
" windows.h "
#include
< cstdio >
#include
< ctime >
using namespace std;

// inline in function.h
void outpGame(vector < vector < int >> & map, int flat = 0 );

void outpHelp( )
// 输出操作提示
{
system(
" cls " ); // 清屏

printf(
" \
操作提示: xxyyt\n\
其中 xx表示第xx行,yy表示第yy列,t表示进行的操作\n\
1 :挖雷(不输入t值则默认此项) 2 ; 标记 / 取消标记 雷区 3 ; 翻开周围区域\n\
05061 \n\
请按任意键继续\
" ); // " \ "
getchar( );
system(
" cls " ); // 清屏
}
void outpMap(vector < vector < int >> & map, int flat)
// 输出图形,以及坐标
// flat默认为0
{
// 顶排输出横坐标
printf( " " );
int i = 1 ;
for ( int amount = map[ 0 ].end() - map[ 0 ].begin(); i <= amount; i += 2 ){
printf(
" %02d " ,i);
}
printf(
" \n " );
i
= 0 ;
for (vector < vector < int > > ::iterator iterL = map.begin();
iterL
!= map.end(); ++ iterL)
{
putchar(
' ' );
// 左排纵坐标
if ( ! (i % 2 ) ){
printf(
" %02d " ,i);
}
else {
printf(
" " );
}
for (vector < int > ::iterator iter = ( * iterL).begin();
iter
!= ( * iterL).end(); ++ iter)
{


#if 0
cout
<< setw( 3 ) << setfill( ' ' ) <<* iter;
#else
// 显示雷区
if (flat && * iter % 10 == 9 ){
printf(
" " );
}
// 未翻开
else if ( * iter < 10 ){
printf(
" " );
}
// 已翻开且周围无雷
else if ( * iter == 10 ){
printf(
" · " );
}
// 已翻开且周围有雷
else if ( * iter < 19 ){
printf(
" %d " , * iter - 10 );
}
// 边界
else if ( * iter == 20 ){
printf(
" · " );
}
// 标记为雷区
else {
printf(
" " );
}



#endif
}

// 右排纵坐标
if (i % 2 ){
printf(
" %02d " ,i);
}
++ i;
printf(
" \n " );
}
// 底排输出横坐标
printf( " " );
i
= 0 ;
for ( int amount = map[ 0 ].end() - map[ 0 ].begin(); i < amount; i += 2 ){
printf(
" %02d " ,i);
}
printf(
" \n " );
}


void outpState( int bobLeft)
// 输出当前状态:使用时间,剩余雷数
{
static unsigned long long timeBegin = time( 0 );
printf(
" 已用时间: %d秒\t\t " ,time( 0 ) - timeBegin);
printf(
" 剩下地雷: %d个\n " ,bobLeft);
printf(
" --------------------------------------------------------------------\n " );
}
void outpMethod()
{
printf(
" 1:挖雷(默认) 2:标记/取消标记雷区 3:翻开周围 ?:查看帮助 e:退出\n " );
printf(
" --------------------------------------------------------------------\n " );
}

 

 在这,碰到了一个比较郁闷的问题:如何清空输入流。如过当前的输入非法,那么当前流得不到释放,会影响下次的输入效果。且C++的流IO效率不是很高。

当时写这个程序的时候,还不会类,而且map的数据结构很有问题,效率低且占用内存大,等以后学习了更多的知识后,将进行修改。

转载于:https://www.cnblogs.com/h46incon/archive/2011/01/20/1939843.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值