简介:
C++文本模式下模拟经典的扫雷游戏,有简单的解答计算。

概要:
其中一处用到区域生长算法,其余的没有技术含量,纯属娱乐。

核心算法和数据结构:
见代码.

AI部分待续..
#include <iostream>
#include 
<fstream>
#include 
<cmath>
#include 
<ctime>
#include 
<vector>
#include 
<windows.h>

class CMyMine
{
public:
    CMyMine();
    
~CMyMine();
public:
    
void Run();
    
static int rand(void);
protected:
    
void InitGame(void);
    
void Show(void);
    
void GetNeighbor(int pos,int* nb);
    
bool CheckState();
public:
    
void DeMark(int x ,int y,bool isC = false);
    
void Mark(int x, int y,bool isC = false); //做标记
    void Mark(int pos,bool isC = false);
    
void DeMark(int pos,bool isC = false);
    
void WaitForInput();
    
void Open(int x , int y); //打开
    void Open(int pos);
    
int*  m_UserMark;
    
int*  m_AIMark;
protected:
    
void AI();
    
enum  GAMESTATE {START,OVER,WIN,PAUSE};
    
char      m_nHard;
    
enum GAMESTATE   m_eGameState;    
    
int   m_nWidth;
    
int   m_nHeight;
    
int   m_nMineNum;
    
bool  m_UsingAI;

    
int*  m_CoreMap;
    
int*  m_ViewMap;
    
int   m_nGamep[12]; //游戏参数
    char* m_graphs[4];  //图像
}
;



CMyMine::CMyMine()
{
   
//难度常数设置 
    m_nGamep[0= 10;
    m_nGamep[
1= 10;
    m_nGamep[
2= 10;
    m_nGamep[
3= 20;
    m_nGamep[
4= 15;
    m_nGamep[
5= 38;
    m_nGamep[
6= 30;
    m_nGamep[
7= 20;
    m_nGamep[
8= 100;
    m_nGamep[
9= 35;
    m_nGamep[
10= 25;
    m_nGamep[
11= 175;
    
//图形符号
    m_graphs[0]     = "#"//
    m_graphs[1]     = "@"//炸弹
    m_graphs[2]    = "#"//未打开
    m_graphs[3]     = "*"//标记


    
//??
    m_CoreMap = 0;
    m_ViewMap 
= 0;
    m_nHard   
= '\0';
    m_nWidth  
= 0;
    m_nHeight 
= 0;
    m_nMineNum
= 0;
    m_UsingAI 
= false;
    m_eGameState 
= OVER;
        
}


CMyMine::
~CMyMine()
{
    
if(m_CoreMap)
    
{
        delete[] m_CoreMap;
        m_CoreMap 
= 0;
    }

    
if(m_ViewMap)
    
{
        delete[] m_ViewMap;
        m_ViewMap 
= 0;
    }

}


void CMyMine::GetNeighbor(int pos, int* nb)
{  
    
//周围地雷的位置,如果不存在这个点,则赋值为-1
    nb[0= pos - m_nWidth - 1;
    nb[
1= pos - m_nWidth;
    nb[
2= pos - m_nWidth + 1;
    nb[
3= pos - 1;
    nb[
4= pos + 1;
    nb[
5= pos + m_nWidth - 1;
    nb[
6= pos + m_nWidth;
    nb[
7= pos + m_nWidth + 1;

    
if(pos == 0//左上角 
    {
        nb[
0= nb[1= nb[2=nb[3= nb[5= -1;
    }

    
else if(pos == m_nWidth - 1)  //右上角                
    {
        nb[
0= nb[1= nb[2=nb[4= nb[7= -1;
    }

    
else if(pos == m_nWidth*(m_nHeight-1))  //左下角
    {
        nb[
0= nb[3= nb[5=nb[6= nb[7= -1;
    }

    
else if(pos==m_nWidth*m_nHeight-1//右下角
    {
        nb[
2= nb[4= nb[5=nb[6= nb[7= -1;
    }

    
else if( pos < m_nWidth - 1  && pos > 0//第一排
    {
        nb[
0= nb[1= nb[2= -1;
    }

    
else if(pos > m_nWidth*(m_nHeight-1&& pos < m_nWidth*m_nHeight-1)//最后一排
    {
        nb[
5=nb[6= nb[7= -1;
    }

    
else if(pos % m_nWidth == 0)
    
{    
        nb[
0= nb[3= nb[5= -1;
    }

    
else if((pos+1)%m_nWidth == 0)
    
{
        nb[
2= nb[4= nb[7= -1;
    }

}


int CMyMine::rand(void)
{
   
static bool initlize = false;
   
static int randint[1000];
   
static int randIndex = 0;
   
if(!initlize || randIndex > 999 )
   
{
       initlize 
= true;
       srand((unsigned)time(NULL)); 
       
for(int i = 0; i < 1000; i++
           randint[i] 
= ::rand();
   }

   
return randint[randIndex++];
}



void CMyMine::Run(void)
{
    
using namespace std;
    
while(true)
    
{
        
char inputkey = 'a';
        
bool bExit = false;
        cout
<<"welcome to text mine game!"<<endl;
        cout
<<"please input a,b,c. to select:"<<endl;
        cout
<<"a,[start game]"<<endl;
        cout
<<"b,[game info]"<<endl;
        cout
<<"c,[exit]"<<endl;
        cin
>>inputkey;
        
switch(inputkey)
        
{
            
case 'a':
                
{
                  
//游戏状态控制:
                   InitGame();               
                   
while(!CheckState())
                   
{
                       Show();
                       WaitForInput();
                   }

                   Show();
                   
//bExit = true;
                   break;    
                }

            
case 'b':
                
{
                    cout
<<m_graphs[0]<<m_graphs[1]<<m_graphs[2]<<m_graphs[3]<<endl;
                    
break;
                }

            
case 'c':
                
{
                    bExit 
= true;
                    
break;
                }

            
default:
            cout
<<"input a,b,c to select!"<<endl<<endl<<endl<<endl;    
            
break;
        }

        
if(bExit)
            
break;
    }

}




void CMyMine::InitGame(void)
{
    
using namespace std;
    
do
    
{
        cout
<<"select diffculty:"<<endl;
        cout
<<"a easy,b normal,c hard,d crazy(a-d Only)"<<endl;
        cin
>>this->m_nHard;
    }
while(this->m_nHard<'a' && this->m_nHard >'d');
    
    m_nHard   
= (m_nHard-'a')*3;
    m_nWidth  
= m_nGamep[m_nHard];
    m_nHeight 
= m_nGamep[m_nHard+1];
    m_nMineNum 
= m_nGamep[m_nHard+2];
    
    
//分配空间
    m_CoreMap  = new int[m_nWidth*m_nHeight];
    m_ViewMap  
= new int[m_nWidth*m_nHeight];    
    m_UserMark 
= new int[m_nWidth*m_nHeight];
    m_AIMark   
= new int[m_nWidth*m_nHeight];
    
int i=0,j=0;
    
    
//生成地雷   9代表地雷!
    int k = 0;
    
while(k<m_nMineNum)
    
{
        
int  pindex = this->rand()%(m_nWidth*m_nHeight);
        m_CoreMap[pindex]  
= 9;      
        
for(i=0,k=0;i<m_nWidth*m_nHeight;i++)
        
{
            
if(m_CoreMap[i]==9
            
{
                k
++;
            }

        }

    }

    
for(i=0;i<m_nWidth*m_nHeight;i++)
    
{//地图生成
        if(m_CoreMap[i] != 9)
        
{
            m_CoreMap[i]  
=  0;
        }

        m_ViewMap[i]  
= -1;//未开采
        m_UserMark[i] =  0;//未标记
        m_AIMark[i]   =  0;//未标记
        int nb[8];
        
int minenum = 0;
        GetNeighbor(i,nb);
        
for(j=0;j<8;j++)
        
{
            
if(nb[j]<0 || nb[j]>= m_nWidth*m_nHeight) 
                
continue;
            
if(m_CoreMap[nb[j]] == 9
                minenum 
++;
        }

        
if(m_CoreMap[i]!=9
            m_CoreMap[i]
= minenum;
    }

    m_eGameState 
= START;
}



void CMyMine::Show(void)
{//如果已经显示
    using namespace std;
    
int i=0,j=0;
#ifdef _WIN32
    system(
"cls");
#else
    system(
"clear");
#endif
    
if(m_eGameState == START)
    
{    
    cout
<<endl;
    cout
<<endl;
    
for(i=0;i<=m_nHeight;i++)
        
{
            
if(i==0)
            
{
                
for(j=0;j<=m_nWidth;j++)
                
{
                    
if(j==0)
                    cout
<<"  ";
                    
else
                    
{
                        
if(j-1<10)
                        
{
                            cout
<<' ';
                        }

                        cout
<<j-1;
                    }
    
                }

                cout
<<endl;
                
continue;
            }

            
for(j=0;j<=m_nWidth;j++)
            
{
                
if(j==0)
                
{
                    cout
<<i-1;
                    
if(i-1<10)
                    
{
                        cout
<<' ';
                    }

                    
continue;
                }

                
if(m_ViewMap[(i-1)*m_nWidth+(j-1)] == -1)
                
{
                    
if(m_UserMark[(i-1)*m_nWidth+(j-1)]==1 || m_AIMark[(i-1)*m_nWidth+(j-1)]==1)
                    
{
                        cout
<<' '<<m_graphs[3];
                    }

                    
else
                    
{
                        cout
<<' '<<m_graphs[2];
                    }

                }

                
else 
                
{
                   
if(m_ViewMap[(i-1)*m_nWidth+(j-1)] == 0)    
                   
{
                       cout
<<' '<<' ';
                   }

                   
else
                   
{
                        
if(m_ViewMap[(i-1)*m_nWidth+(j-1)]>=0)
                        cout
<<' ';
                        cout
<<m_ViewMap[(i-1)*m_nWidth+(j-1)];
                   }

                }

            }
// for j
            cout<<endl;
        }
//for i
        cout<<endl;
    }

    
else if(m_eGameState == OVER)
    
{
        cout
<<"Game Over!\n"<<endl;
    }
//ifelse
    else if(m_eGameState == WIN)
    
{
        cout
<<"Congratulation!You Win!!\n"<<endl;
    }

}




bool  CMyMine::CheckState()
{
    
if(m_eGameState == START)
    
{
        
bool bsucceed = true;
        
//如果所有不是雷的区域都被开发出来,则胜利
        for(int i=0;i<m_nWidth*m_nHeight;i++)
        
{
            
if(m_CoreMap[i]!= 9 && m_ViewMap[i] == -1)
            
{
                bsucceed 
= false;
                
break;
            }

        }

        
if(bsucceed)
        
{
            m_eGameState 
= WIN;
        }

        
return bsucceed;
    }

    
return true;
}





void CMyMine::WaitForInput()
{
    
using namespace std;
    
while(true)
    
{
        
if(m_UsingAI)
        
{
            AI();
            Sleep(
1000);
            
break;
        }

        
char op = '0';
        
int  x  = 0;
        
int  y  = 0;
        cout
<<"wait for your input,your choice: \n\"o x y\" to open the unware place,\n\"m x y\" to mark a mine \n\"d x y\" delete a mark \n \"h\" to ask for Help \n \"a\" to using AI\n \"e\" to end game.."<<endl;
        cin
>>op;
        
if(op == 'o' || op == 'm')
            cin
>>x>>y;
        
if(op == 'o' || op == 'm' || op == 'd' ||op == 'h' ||op == 'e'||op == 'a')
        
{
            
if(!(x<0 ||x>m_nWidth || y<0 || y> m_nHeight))
            
{
                
switch(op)
                
{
                    
case 'o':
                        Open(x,y);
                        
break;
                    
case 'm':
                        Mark(x,y);
                        
break;
                    
case 'd':
                        DeMark(x,y);
                        
break;
                    
case 'h':
                        AI();
                        
break;
                    
case 'a':
                        m_UsingAI 
= true;
                        
break;
                    
case 'e':
                        m_eGameState 
= OVER;
                        
break;
                    
default:
                        
break;
                }

                
return;
            }

        }

    }

}



int main(void)
{
    CMyMine game;
    game.Run();
    
return 0;
}



void CMyMine::Open(int pos)
{
    
int y = pos/m_nWidth;
    
int x = pos%m_nWidth;
    Open(x,y);
}


void CMyMine::Open(int x, int y)
{
    
using namespace std;
    
int j=0,i =0;
    
int pid =0;
    
if(m_ViewMap[y*m_nWidth+x] != -1)
        
return
    
if(m_CoreMap[y*m_nWidth+x] == 9)
    
{
        m_eGameState 
= OVER;
        
return;
    }

    
else if(m_CoreMap[y*m_nWidth+x] >0 && m_CoreMap[y*m_nWidth+x] < 9)
    
{
        m_ViewMap[y
*m_nWidth+x] = m_CoreMap[y*m_nWidth+x];
        
return;
    }

    
else if(m_CoreMap[y*m_nWidth+x] == 0)
    
{//生长
        vector<int> barray;
        vector
<int> tarray;
       barray.push_back(y
*m_nWidth+x);
       pid 
= 0;
       
while(pid <= barray.size())
       
{
           
int nb[8];
           
int temp = barray[pid];
           GetNeighbor(temp,nb);
           pid 
= pid + 1;
           
for(j=0;j<8;j++
           
{
               
if(nb[j]<0 || nb[j] >= m_nWidth*m_nHeight) 
                   
continue;
               
if(m_CoreMap[nb[j]] == 0)
               
{    //考虑nb[j] 是不是在barray内,如果在需要考察nb[j]的邻居
                    bool isNotInbary = true;
                    
for(i = 0;i< barray.size();i++)
                    
{
                        
if(barray[i] == nb[j])
                        
{
                            isNotInbary 
= false;
                            
break;
                        }

                    }

                    
if(isNotInbary)
                    

                        barray.push_back(nb[j]);
                    }

               }

               
else if(m_CoreMap[nb[j]]>0 && m_CoreMap[nb[j]] < 9)
               
{
                    
bool isNotIntary = true;
                    
for(i = 0;i<tarray.size();i++)
                    
{
                        
if(tarray[i] == nb[j])
                        
{
                            isNotIntary 
= false;
                            
break;
                        }

                    }

                    
if(isNotIntary)
                    

                        tarray.push_back(nb[j]);
                    }
                    
               }

           }
//for
       }
//while
       for(i = 0;i<barray.size();i++)
       
{
            m_ViewMap[barray[i]] 
= m_CoreMap[barray[i]];
       }

       
for(i = 0;i<tarray.size();i++)
       
{
            m_ViewMap[tarray[i]] 
= m_CoreMap[tarray[i]];
       }
       
    }
//if
}


void CMyMine::Mark(int x, int y,bool isC)
{
    
if(isC)
    
{
        
if(m_AIMark[y*m_nWidth+x] != 1)
            m_AIMark[y
*m_nWidth+x] = 1;
    }

    
else
    
{
        
if(m_UserMark[y*m_nWidth+x] != 1)
            m_UserMark[y
*m_nWidth+x] = 1;
    }


}


void CMyMine::DeMark(int x, int y,bool isC)
{
    
if(isC)
    
{
        
if(m_AIMark[y*m_nWidth+x] == 1)
            m_AIMark[y
*m_nWidth+x] = 0;
    }

    
else
    
{
        
if(m_UserMark[y*m_nWidth+x] == 1)
            m_UserMark[y
*m_nWidth+x] = 0;
    }

}


void CMyMine::Mark(int pos,bool isC)
{
    
if(isC)
    
{
        
if(m_AIMark[pos] != 1)
            m_AIMark[pos] 
= 1;
    }

    
else
    
{
        
if(m_UserMark[pos] != 1)
            m_UserMark[pos] 
= 1;
    }

}


void CMyMine::DeMark(int pos,bool isC)
{
    
if(isC)
    
{
        
if(m_AIMark[pos] == 1)
            m_AIMark[pos] 
= 0;
    }

    
else
    
{
        
if(m_UserMark[pos] == 1)
            m_UserMark[pos] 
= 0;
    }

}


void CMyMine::AI()
{
    
using namespace std;
    
int i,j,k;
    
//只提供ViewMap函数
    
//状态参数
    int* lastView = NULL;
    
int* lastMark = NULL;
    lastView 
= new int[m_nWidth*m_nHeight];
    lastMark 
= new int[m_nWidth*m_nHeight];
    memcpy(lastView,m_ViewMap,
sizeof(int)*m_nWidth*m_nHeight);
    memcpy(lastMark,m_AIMark, 
sizeof(int)*m_nWidth*m_nHeight);

    vector
<int> UnknowPointPos; //周围有未知点的安全已知点
    vector<int>    CurUMineNum;    //当前未知炸弹的个数
    vector<int>    UnknowPointSet;    //未知点点集 格式为[size1 p11 p12 .. size2 p21 p22..]
    double* mP     = new double[m_nWidth*m_nHeight];//每一点更像mine的概率
    memset(mP,0,m_nWidth*m_nHeight*sizeof(double));  //初始化为0

    
//计算整体概率[未知mine的数目/未知点的个数] 
    double avgP = (double)m_nMineNum/(double)(m_nWidth*m_nHeight);//初始平均概率
    int       UnknownPoint = 0;
    
int    UnknownMine  = 0;
    
for(i = 0;i<m_nWidth*m_nHeight;i++)
    
{
            
if(m_AIMark[i] == 1)
                UnknownMine
--;
            
else if(m_ViewMap[i] == -1)
                UnknownPoint 
++;
    }

    avgP 
= (double)(m_nMineNum - UnknownMine)/(double)UnknownPoint; 
    
    
for(i = 0;i<m_nWidth*m_nHeight;i++)
    
{
        mP[i] 
=avgP; //给每个未知点赋值
    }

    
    
//将>=1 <9的数据并且其四周有未探索空间 计入向量 UnknowPointPos
    
//UnknowPointSet CurUMineNum
    for(i=0;i<m_nHeight;i++)
    
{
        
for(j=0;j<m_nWidth;j++)
        
{
            
if(m_ViewMap[i*m_nWidth+j]>0 && m_ViewMap[i*m_nWidth+j]<9)
            
{
                
int nb[8];
                GetNeighbor(i
*m_nWidth+j,nb);
                k 
= 0;
                
//邻域中是否有未探索的区域和已经发现的mine
                bool IsUse = false;
                
int  fakeUMine = 0;
                
while(k<8)
                
{
                    
if(nb[k]>-1)//此邻域存在
                    {
                        
if(m_ViewMap[nb[k]] == -1 && m_AIMark[nb[k]] == 1)
                        
{
                            fakeUMine
++;
                        }
                        
                        
else if(m_ViewMap[nb[k]] == -1)
                        
{
                            
if(IsUse == false)
                            
{
                                IsUse 
= true;
                                UnknowPointPos.push_back(i
*m_nWidth+j);
                                CurUMineNum.push_back(m_ViewMap[i
*m_nWidth+j]);
                                UnknowPointSet.push_back(
0);
                            }

                            
//先找到此邻域大小的位置
                            int tm = 1,offset = 0;
                            
while( tm<UnknowPointPos.size() )
                            
{//肯定是最尾巴上的点
                              offset +=  UnknowPointSet[offset]+1;
                              tm
++;
                            }

                            UnknowPointSet[offset]
++;
                            UnknowPointSet.push_back(nb[k]);
                        }

                    }

                    k
++;
                }
//while
                 if(IsUse)
                CurUMineNum[CurUMineNum.size()
-1-= fakeUMine;
            }
//if
        }
//for j
    }
//for i



    
//如果没有打开过 选取中间的点打开
    if(UnknowPointPos.size() == 0)
    
{
        
int x = (m_nWidth-1)/2;
        
int y = (m_nHeight-1)/2;
        Open(x,y);
    }


    
//计算单个集合的概率,把已经确认为空 或 已经确认为mine的挑选出来
    
//遍历UnknowPointPos中的所有点
    for(i=0;i<UnknowPointPos.size();i++)
    
{
        
//先找到此邻域大小的位置
        int tm = 0,offset = 0;
        
while( tm<i )
        
{//找到第i个点
          offset +=  UnknowPointSet[offset]+1;
          tm
++;
        }

        
double curp = (double)CurUMineNum[i]/(double)UnknowPointSet[offset];
    
        
for(j=0;j<UnknowPointSet[offset];j++)
        
{
            mP[UnknowPointSet[j
+1+offset]] = curp;
            
if(curp >= 0.999999)
            
{
                Mark(UnknowPointSet[j
+1+offset],true);
            }

            
else if(curp <= 0.000001)
            
{
                Open(UnknowPointSet[j
+1+offset]);
            }

        }

        
    }

    
    
//状态是否改变
    bool noChange = true
    
for(i = 0;i<m_nWidth*m_nHeight;i++)
    
{
        
if(!(m_AIMark[i] == lastMark[i] &&  m_ViewMap[i] == lastView[i]))
        
{
            noChange 
= false;
            
break;
        }

    }

    
    
//算单一概率已经解决不了!
    if(noChange)
    
{
        m_UsingAI 
= false;
        
//计算联合概率待加入
                
    }


    
//清理垃圾
    delete[] mP;
    delete[] lastMark;
    delete[] lastView;

}