九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

在Jeff Prosise井字棋的基础上做的一个五子棋

Jeff Prosise井字棋的基础上做的一个五子棋,全手工代码输入,利用MFC实现,因为尚不知如何手工添加按钮,

所以暂时重新开始游戏的方式为双击标题栏。可以到http://groups.google.com/group/jiutianfile下载编译好的文件和Visual Studio.net 2005工程源代码。

源代码gobangSrc.rar,编译好的文件gobangRel.rar

头文件gobang.h

class CMyApp : public CWinApp

{

public:

      virtual BOOL InitInstance();

};

 

class CMainWindow : public CFrameWnd

{

protected:

      enum gridState { Unputed, PutedO, PutedX};     //enum格子的个状态

      enum Turn {OTurn,XTurn};  //enum轮到谁下的状态

      enum winnerLast {NoOne,OWin,XWin};      //enum有没有胜利者的状态

      Turn m_nextTurn; //下轮执棋者

      const static int nClientSize = 700; //客户区大小,可改变

      const static int nGridNum = 20;         //格数,可改变

      int m_countStep;  //目前所下步数

      void DrawBoard(CDC &dc); //画棋盘

      CRect m_rcGrid[nGridNum][nGridNum];     //棋盘的每个格子的矩形范围

      gridState m_stateGrid[nGridNum][nGridNum];   //棋盘每个格子的状态

      void DrawO(CDC &dc,int i,int j);      //O

      void DrawX(CDC &dc,int i,int j); //X

      void ResetGame();     //重新开始游戏

      void CheckForGameOver(Turn thisTurn,int i,int j); //查找需不需要结束游戏

      BOOL IsWinner(Turn thisTurn,int i,int j);      //是否有胜利者

      BOOL IsDraw();   //是否平局

 

public:

      CMainWindow();

protected:

      afx_msg void OnPaint();

      afx_msg void OnLButtonDown(UINT nFlags,CPoint point);

      afx_msg void OnNcLButtonDblClk(UINT nHitTest,CPoint point);

      afx_msg void OnRButtonDown(UINT nFlags,CPoint point);

      afx_msg BOOL OnSetCursor(CWnd *pWnd,UINT nHitTest, UINT message);

      DECLARE_MESSAGE_MAP()

};

 

 

主体文件gobang.cpp

#include <afxwin.h>

#include <cmath>

#include <memory>

#include "resource.h"

#include "gobang.h"

 

CMyApp myApp;

//

//CMyApp的成员函数

//

BOOL CMyApp::InitInstance()

{

      m_pMainWnd = new CMainWindow;

      m_pMainWnd->ShowWindow(m_nCmdShow);

      m_pMainWnd->UpdateWindow();

      return TRUE;

}

//

//CMainWindow的消息映射和成员函数定义

//

BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)

      ON_WM_PAINT()

      ON_WM_LBUTTONDOWN()

      ON_WM_NCLBUTTONDBLCLK()

      ON_WM_RBUTTONDOWN()

      ON_WM_SETCURSOR()

END_MESSAGE_MAP()

 

 

CMainWindow::CMainWindow()

{

      //执圆形的先下棋,光标为圆型,并定下窗口固定宽度

      CString wndClassStr = ::AfxRegisterWndClass(CS_DBLCLKS,

           ::AfxGetApp()->LoadCursor(IDC_round));

      Create(wndClassStr,_T("五子棋by九天雁翎       (双击标题栏重新开始游戏)"),

           WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX);

      CRect rect(0,0,nClientSize+2,nClientSize+2);

      CalcWindowRect(&rect);

      SetWindowPos(NULL,0,0,rect.Width(),rect.Height(),

           SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);

     

      //初始化自定义的成员变量

      m_nextTurn = OTurn;

      m_countStep = 0;

     

      ::ZeroMemory(m_rcGrid,nGridNum * nGridNum * sizeof(CRect));

      ::ZeroMemory(m_stateGrid,nGridNum * nGridNum * sizeof(gridState));

     

 

 

 

}

 

void CMainWindow::OnPaint()

{

      CPaintDC dc(this);

      DrawBoard(dc);

}

 

void CMainWindow::DrawBoard(CDC &dc)

{

      CRect rect;

      GetClientRect(&rect);

 

      //画背景

      CBrush brush(RGB(128,128,128));

      dc.FillRect(rect,&brush);

 

//开始画纵横线,利用rect大小来画线,一是代码重用度高,二是以前做好了

//效率稍微低点,不过将来要是改变客户区大小或用可缩放窗口就可以不改了

     

      //定义画线的画笔并选中

      CPen pen(PS_SOLID,2,RGB(0,0,0));

      CPen *pOldPen = dc.SelectObject(&pen);

 

      //求方格宽高

      int nGridWidth = nClientSize / nGridNum  ; 

      int nGridHeight = nClientSize / nGridNum ;

     

 

      //计算每个方格矩形范围

      for(int i = 0; i < nGridNum; ++i)

           for(int j = 0; j < nGridNum; ++j)

           {

                 m_rcGrid[i][j] = CRect(rect.left + (nGridWidth * j),

                                                rect.top + (nGridHeight * i),

                                                rect.left + nGridWidth +(nGridWidth * j),

                                                rect.top + nGridHeight + (nGridHeight * i));

           }

 

 

      for(int i = 0; i <= nGridNum; ++i)   //画横线

      {

           int y = (nGridHeight * i) + rect.top;

           dc.MoveTo(rect.left,y);

           dc.LineTo(rect.right,y);

      }

 

      for(int i = 0; i <= nGridNum; ++i)   //画竖线

      {

           int x = (nGridWidth * i) + rect.left;

           dc.MoveTo(x,rect.top);

           dc.LineTo(x,rect.bottom);

      }

 

      //画下已经下好的棋

 

      for(int i=0; i<nGridNum; ++i)

           for(int j=0; j<nGridNum; ++j)

           {

                 if(m_stateGrid[i][j] == Unputed)

                 {

                      continue;

                 }

                 else if(m_stateGrid[i][j] == PutedO)

                 {

                      DrawO(dc,i,j);

                 }

                 else if(m_stateGrid[i][j] == PutedX)

                 {

                      DrawX(dc,i,j);

                 }

           }

 

}

 

//左键下O

void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point)

{

      //若本轮不属O,即不响应

      if(m_nextTurn != OTurn)

           return;

      for(int i = 0; i<nGridNum; ++i)

           for(int j = 0; j<nGridNum; ++j)

           {

                 if(m_rcGrid[i][j].PtInRect(point) && m_stateGrid[i][j] == Unputed)

                 {

                      CClientDC dc(this);

                      m_nextTurn = XTurn;

                      m_stateGrid[i][j] = PutedO;

                      DrawO(dc,i,j);

                      ++m_countStep;

                      CheckForGameOver(OTurn,i,j);

                 }

           }

}

 

//右键下X

void CMainWindow::OnRButtonDown(UINT nFlags,CPoint point)

{

      //若本轮不属X,即不响应

      if(m_nextTurn != XTurn)

           return;

      for(int i = 0; i<nGridNum; ++i)

           for(int j = 0; j<nGridNum; ++j)

           {

                 if(m_rcGrid[i][j].PtInRect(point) && m_stateGrid[i][j] == Unputed)

                 {

                      CClientDC dc(this);

                      m_nextTurn = OTurn;

                      m_stateGrid[i][j] = PutedX;

                      DrawX(dc,i,j);

                      CheckForGameOver(XTurn,i,j);

                 }

           }

}

 

 

void CMainWindow::DrawO(CDC &dc, int i, int j)

{

      CRect rect(m_rcGrid[i][j]);

      rect.DeflateRect(5,5);

      dc.SelectStockObject(NULL_BRUSH);

      CPen pen(PS_SOLID,4,RGB(128,64,64));

      CPen *pOldPen = dc.SelectObject(&pen);

      dc.Ellipse(rect);

      dc.SelectObject(pOldPen);

}

 

void CMainWindow::DrawX(CDC &dc, int i, int j)

{

      CRect rect(m_rcGrid[i][j]);

      rect.DeflateRect(5,5);

      CPen pen(PS_SOLID,4,RGB(128,64,64));

      CPen *pOldPen = dc.SelectObject(&pen);

      dc.MoveTo(rect.left,rect.top);

      dc.LineTo(rect.right,rect.bottom);

      dc.MoveTo(rect.right,rect.top);

      dc.LineTo(rect.left,rect.bottom);

      dc.SelectObject(pOldPen);

 

}

 

void CMainWindow::CheckForGameOver(Turn thisTurn,int i,int j)

{

      if(IsWinner(thisTurn,i,j))

      {

           if(thisTurn == OTurn)

           {

                 CString string;

                 string.Format(_T("GOOD! O Wins in %d steps."),m_countStep);

                 MessageBox(string,_T("Game Over!"));

                 ResetGame();

           }

           else if(thisTurn == XTurn)

           {

                 CString string;

                 string.Format(_T("GOOD! X Wins in %d steps."),m_countStep);

                 MessageBox(string,_T("Game Over!"));

                 ResetGame();

           }

          

      }

      else if(IsDraw())

      {

           MessageBox(_T("OK,It's draw."),_T("Draw Game!"));

           ResetGame();

      }

 

}

 

//此为本软件最主要的部分,即检测是否有五个棋连在一起

//以横纵和两条对角线的方向分别检测,感觉比较笨

//暂时不知道有没有更好的办法,望来信赐教

BOOL CMainWindow::IsWinner(Turn thisTurn,int i,int j)

{

      int count = 1;

      gridState checkFor; //状态对比值

      if(thisTurn == OTurn)

           checkFor = PutedO;

      else if(thisTurn == XTurn)

           checkFor = PutedX;

 

      //横方向检测

      for(int m=1; m<5; ++m)

      {

           if(j - m > 0 && m_stateGrid[i][j-m] == checkFor)

                 ++count;

           else

                 break;

      }

      for(int m=1; m<5; ++m)

      {

           if(j + m < nGridNum && m_stateGrid[i][j+m] == checkFor)

                 ++count;

           else

                 break;

      }

      if(count >=5)

           return TRUE;

      count = 1;

 

      //竖方向检测

      for(int m=1; m<5; ++m)

      {

           if(i-m>0 && m_stateGrid[i-m][j] == checkFor)

                 ++count;

           else

                 break;

      }

      for(int m=1; m<5; ++m)

      {

           if(i+m<nGridNum && m_stateGrid[i+m][j] == checkFor)

                 ++count;

           else

                 break;

      }

      if(count >=5)

           return TRUE;

      count = 1;

 

      //左上至右下方向检测

      for(int m=1; m<5; ++m)

      {

           if(i-m>0 && j-m>0 && m_stateGrid[i-m][j-m] == checkFor)

                 ++count;

           else

                 break;

      }

      for(int m=1; m<5; ++m)

      {

           if(i+m<nGridNum && j+m<nGridNum && m_stateGrid[i+m][j+m] == checkFor)

                 ++count;

           else

                 break;

      }

      if(count >=5)

           return TRUE;

      count = 1;

 

      //右上至左下方向检测

      for(int m=1; m<5; ++m)

      {

           if(i-m>0 && j+m<nGridNum && m_stateGrid[i-m][j+m] == checkFor)

                 ++count;

           else

                 break;

      }

      for(int m=1; m<5; ++m)

      {

           if(i+m<nGridNum && j-m>0 && m_stateGrid[i+m][j-m] == checkFor)

                 ++count;

           else

                 break;

      }

      if(count >=5)

           return TRUE;

      return FALSE;

}

 

BOOL CMainWindow::OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message)

{

      if(nHitTest == HTCLIENT)

      {

           if(m_nextTurn == OTurn)

           {

                 ::SetCursor(::AfxGetApp()->LoadCursor(IDC_round));

                 return TRUE;

           }

           else if(m_nextTurn == XTurn)

           {

                 ::SetCursor(::AfxGetApp()->LoadCursor(IDC_cross));

                 return TRUE;

           }

      }

      return CFrameWnd::OnSetCursor(pWnd,nHitTest,message);

}

 

//当都下满了,即为平局

BOOL CMainWindow::IsDraw()

{

      int i,j;

      for(i=0; i<nGridNum; ++i)

           for(j=0; j<nGridNum; ++j)

           {

                 if(m_stateGrid[i][j]==Unputed)

                      break;

           }

      if(i==nGridNum && j==nGridNum)

           return TRUE;

      else

           return FALSE;

}

 

void CMainWindow::ResetGame()

{

      m_nextTurn = OTurn;

      m_countStep = 0;

      ::ZeroMemory(m_stateGrid,nGridNum * nGridNum * sizeof(gridState));

      Invalidate();

}

 

void CMainWindow::OnNcLButtonDblClk(UINT nHitTest, CPoint point)

{

      if(nHitTest == HTCAPTION)

      {

           ResetGame();

      }

 

      return CFrameWnd::OnNcLButtonDblClk(nHitTest,point);

}

 

分类:  我的程序 
标签: 

Posted By 九天雁翎 at 九天雁翎的博客 on 2007年10月30日

前一篇: Windows 下利用MFC实现的中国象棋棋盘绘制程序 后一篇: 多鼠标技术的应用,请有多个鼠标的兄弟帮我测试一下