简单的五子棋-人人对战

1新建工程
项目->VC++->MFC->MFC应用程序->输入名称->单文档->Window套接字->完成


简单的五子棋-人人对战_第1张图片

简单的五子棋-人人对战_第2张图片

简单的五子棋-人人对战_第3张图片

2资源编辑
视图->其他窗口->资源试图
添加黑白位图以表示棋盘上面的棋子
IDB_BLACK
IDB_WHITE


简单的五子棋-人人对战_第4张图片

黑白鼠标Cursor以替换当前鼠标
IDC_CURSOR1
IDC_CURSOR2


简单的五子棋-人人对战_第5张图片

黑白图标Icon以显示在状态栏供以提示
IDI_BLACK
IDI_WHITE
3构造函数
//在MainFrm.h文件里面,将“// 控件条嵌入成员”前面的代码改为“public: CStatusBar m_wndStatusBar;”
//然后在五子棋测试View.h里面添加变量函数

//两个鼠标
HCURSOR hcursorwhite;
HCURSOR hcursorblack;
//棋盘数组
int wzq[19][19];
//colorwhite TRUE时baiqi下
bool colorwhite;
//棋子位图
CBitmap m_bmblack;
CBitmap m_bmwhite;

4棋盘大小设置
由于我们的棋盘大小是一定的,不能改变大小的,是应该符合要求的,在如下函数(MainFrm.cpp文件中)添加设置窗口大小的语句;

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CMDIFrameWndEx::PreCreateWindow(cs) )
        return FALSE;
    // TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式
    cs.dwExStyle = cs.dwExStyle|WS_EX_TOPMOST;
    cs.style = WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;
    //设置窗口的大小
    cs.cx = 450;
    cs.cy = 500;
    return TRUE;
}

5初始化变量
在构造函数(五子棋测试View.cpp文件中)里面添加初始代码

C五子棋测试View::C五子棋测试View()
{
    // TODO: 在此处添加构造代码
    //load鼠标图像和棋子位图
    hcursorblack = AfxGetApp()->LoadCursor(IDC_BLACK);
    hcursorwhite = AfxGetApp()->LoadCursor(IDC_WHITE);
    m_bmwhite.LoadBitmap(IDB_WHITE);
    m_bmblack.LoadBitmap(IDB_BLACK);
    //清理棋盘
    //数组值为0时表示没有棋子
    for (int i = 0; i < 19; i++)
    {
        for (int j = 0; j < 19; j++)
        {
            wzq[i][j] = 0;
        }
    }
    //白棋先下
    colorwhite = true;
}

6画棋盘
在OnDraw(CDC* pDC)函数中画棋盘,由于游戏中有可能重画棋盘,而那时棋盘上面有棋子,所以,我们在这个函数里面必须有画棋子的语句
数组的值为1表示白棋,-1表示黑棋

void C五子棋测试View::OnDraw(CDC* pDC)
{
    C五子棋测试Doc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;
    // TODO: 在此处为本机数据添加绘制代码
    CBrush mybrush1;
    mybrush1.CreateSolidBrush(RGB(192,192,192));
    CRect myrect1(0,0,1200,800);
    pDC->FillRect(myrect1,&mybrush1);
    //画棋盘框线
    CPen mypen;
    CPen* myoldPen;
    mypen.CreatePen(PS_SOLID,1,RGB(0,0,0));
    myoldPen = pDC->SelectObject(&mypen);
    for (int i = 0; i < 19; i++)
    {
        pDC->MoveTo(40,40+i*20);
        pDC->LineTo(400,40+i*20);
        pDC->MoveTo(40+i*20,40);
        pDC->LineTo(40+i*20,400);
    }
    //重画时显示的棋子
    CDC Dc;
    if (Dc.CreateCompatibleDC(pDC) == FALSE)
    {
        AfxMessageBox(_T("Can't creat DC"));
    }
    for (int n = 0; n < 19; n++)
    {
        for (int m = 0; m < 19; m++)
        {
            if (wzq[n][m] == 1)
            {
                //显示白棋
                Dc.SelectObject(m_bmwhite);
                pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
            }
            else if(wzq[n][m] == -1)
            {
                //显示黑棋
                Dc.SelectObject(m_bmblack);
                pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
            }
        }
    }
}

7设置鼠标
棋盘画好了,下来就是下棋,但是鼠标并没有像我们上面所说的那样变成白棋
添加消息函数:类视图-> C五子棋测试View ->右击->类向导->消息->WM_SETCURSOR->OnSetCursor


简单的五子棋-人人对战_第6张图片
BOOL C五子棋测试View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   if (nHitTest == HTCLIENT)
   {
       //白棋下,显示白棋鼠标
       if (colorwhite)
       {
           //调用主框架里面的状态栏
           CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;  
       CStatusBar*pStatus=&pFrm->m_wndStatusBar;
           if (pStatus)
           {
               pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDB_WHITE));
               pStatus->SetPaneText(0,_T("白棋下"));
           }
           SetCursor(hcursorwhite);
       }
       //显示黑棋鼠标
       else
       {
           SetCursor(hcursorblack);
           CMainFrame*pFrm = (CMainFrame*)AfxGetApp()->m_pMainWnd;
           CStatusBar*pStatus = &pFrm->m_wndStatusBar;
           if (pStatus)
           {
               //显示图像
               pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDB_WHITE));
               //显示文字
               pStatus->SetPaneText(0,_T("黑棋下"));
           }
       }
       return 1;
   }
   return CView::OnSetCursor(pWnd, nHitTest, message);
}

8下棋操作
这就涉及到OnLButtonDown(UINT nFlags,CPoint point)和OnLButtonUp(UINT nFlags,CPoint point)两个函数了,要用一个还是两个?用down函数是在鼠标按下时放下棋子,可是,要是我们按下后意识到按错了怎么办,那就改用up函数,表示当鼠标键松开时放下棋子
添加消息函数:类视图-> C五子棋测试View ->右击->类向导->消息->WM_LBUTTONUP->OnLButtonUp


简单的五子棋-人人对战_第7张图片
void C五子棋测试View::OnLButtonUp(UINT nFlags, CPoint point)
{
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   // TODO: 在此添加消息处理程序代码和/或调用默认值
   CDC*pDC = GetDC();
   CDC Dc;
   if (Dc.CreateCompatibleDC(pDC) == FALSE)
   
       AfxMessageBox(_T("Can't create DC"));
       //是否在棋盘内
       if (point.x > 30&&point.x < 410&&point.y > 30&&point.y <410)
       {
           int px = (point.x-30)/20;
           int py = (point.y-30)/20;
           //是否已经有棋子
           if (colorwhite&&wzq
               [px][py] == 0)
           {
               Dc.SelectObject(m_bmwhite);
               pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
               //表示白棋存在
               wzq[px][py] = 1;
               //检查是否结束
               over(point);
               //换黑棋下
               colorwhite = false;
           }
           else if(wzq[px][py] == 0)
           {
               Dc.SelectObject(m_bmblack);
               pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
               //表示黑棋存在
               wzq[px][py] = -1;
               //检查是否结束
               over(point);
               //换白棋下
               colorwhite = true;
           }
       
   }
   
   CView::OnLButtonUp(nFlags, point);
}

9是否结束
用over()函数判断是否结束,是则结束并重新开始,否则接着把鼠标变成对方棋子,表示对方下棋
Over()函数利用刚下棋的位置为中心,检查它各个方向上的连续五个棋子是否同色,是则结束并重新开始
利用连续五个相同的棋子的值相加,去过他们的绝对值为5,则说明是同色
添加函数:类视图-> C五子棋测试View ->右击->添加->添加函数


简单的五子棋-人人对战_第8张图片
void C五子棋测试View::over(CPoint point) {
   //获取鼠标指向数组位置,即中心位置 
   int x = (point.x - 30) / 20;  int y = (point.y - 30) / 20;
   //计算开始判断的坐标 xx,yy  
   int xx,yy; 
   if (x < 4)
       xx = 0;
   else        xx = x - 4; if (y < 4)
       yy = 0;
   else
       yy = y - 4;
   int i, j, a;
   //横向判断 
   for (i = xx; i < 15; i++)
   {
       a = 0;
       for (j = i; j < i + 5; j++)
       {
           a = a + wzq[j][y];
           //五个都是白棋 
           if (a == 5)
           {
               AfxMessageBox(_T("白棋胜!"));
               //重新开始 
               OnStart();
               return;
           }
           //五个都是黑棋 
           if (a == -5)
           {
               AfxMessageBox(_T("黑棋胜!"));
               OnStart();
               return;
           }
       }
   }
   //竖向判断 
   for (i = yy; i < 15; i++)
   {
       a = 0;
       for (j = i; j < i + 5; j++)
       {
           a = a + wzq[x][j];          
           if (a == 5)
           {
               AfxMessageBox(_T("白棋胜!"));
               OnStart();
               return;
           }
           if (a == -5)
           {
               AfxMessageBox(_T("黑棋胜!"));
               OnStart();
               return;
           }
       }
   }
   //向右下角 
//判断起点位置  
   if(x(18-x)) 
{
   if (x > 13)
   {
       yy = y - (18 - x);      
       xx = 18;
   }
   else
   {
       yy = y - 4;
       xx = x + 4;
   }
}
       else
       {
       if (y < 5)
       {
           xx = x + y;
           yy = 0;
       }
       else
       {
           yy = y - 4;
           xx = x + 4;
       }
       }
       over = 0;
       do
       {
           a = 0;
           for (i = 0; i < 5; i++)
           {
               if ((xx - i) >= 0 || (yy + i) < 19)
               {
                   a = a + wzq[xx - i][yy + i];         
                   if (a == 5)
                   {
                       AfxMessageBox(_T("白棋胜!"));
                       OnStart();
                       return;
                   }
                   if (a == -5)
                   {
                       AfxMessageBox(_T("黑棋胜!"));
                       OnStart();
                       return;
                   }
               }
               //到了边界       
               else            
                   over=1; 
           }
           xx -= 1;
           yy += 1;
       } while (over == 0);

}

10清理棋盘
Onstart()函数用来清理棋盘,从新初始化棋盘,为下一盘棋做准备
添加函数:类视图-> C五子棋测试View ->右击->添加->添加函数


简单的五子棋-人人对战_第9张图片
void C五子棋测试View::OnStart()
{
   //清理棋盘
   //数组值为0表示没有棋子
   for (int i = 0; i < 19; i++)
   {
       for (int j = 0; j < 19; j++)
       {
           wzq[i][j] = 0;
       }
       //白棋先下
       colorwhite = true;
       Invalidate();
   }
}

4、 运行调试与分析讨论
下面是小程序运行结果的主窗口,如图,包括棋盘和其他各个操作。开局是白色棋子先落棋,所以,鼠标呈现白色棋子样式。由于图片是截屏出来的,所以并未看到此效果。


简单的五子棋-人人对战_第10张图片

下图是游戏中的状态,当落下棋子后,会进入over函数中,判断是否可以结束。如果结束。则清空棋盘,重新开始。如果不结束,则把鼠标变成对方的棋子,表示对方下棋。如此循环下去,直到游戏结束


简单的五子棋-人人对战_第11张图片

下图是游戏结束的状态,当某一方棋子获胜后,会弹出一个窗口,显示某一方获胜。在分出胜负后,可以选择点击结束按钮,开始新的一局。

简单的五子棋-人人对战_第12张图片

出现的问题:在调试过程中曾出现过棋盘显示出来了,但是无法落棋子的bug。究其原因还是因为在void C五子棋测试View::OnLButtonUp(UINT nFlags, CPoint point)函数中的
if (point.x > 30&&point.x < 410&&point.y > 30&&point.y <410)判断语句中将point.y <410写成了point.y <40,导致落棋位置找不到,无法在棋盘上显示。
缺陷:第一是没有保存功能,第二是只有人人对战,第三是下棋时没有悔棋功能。

你可能感兴趣的:(简单的五子棋-人人对战)