在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);

}

你可能感兴趣的:(五子棋)