zoukankan      html  css  js  c++  java
  • 命令行版扫雷(vc08)

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

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

    时间
    地雷计数器
    清屏


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

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


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

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




    //
    11.27
    传值参数有很多的相似,可以进行封装:结构体,容器,数组
    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);
    }
    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;
    }
    }
    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);
    }

    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的数据结构很有问题,效率低且占用内存大,等以后学习了更多的知识后,将进行修改。

  • 相关阅读:
    [微软官方]SQLSERVER的兼容级别
    使用 OPENJSON 分析和转换 JSON 数据 (SQL Server)
    WPF 解决TreeViewItem上为IsMouseOver 时 父级Item也会 受影响
    依赖注入
    关于编译告警 C4819 的完整解决方案
    你想知道的 std::vector::push_back 和 std::vector::emplace_back
    如何使用 Dump 文件?
    关于 PDB 文件你需要知道什么?
    图解哈希表及其原理
    C++ 中的虚函数表及虚函数执行原理
  • 原文地址:https://www.cnblogs.com/h46incon/p/1939843.html
Copyright © 2011-2022 走看看