您的位置:首页 > 其它

mfc 井字游戏程序分析,描述整个程序处理过程。

2016-03-02 18:37 288 查看
此文纯属个人分析!高手绕道!

源码如下:(代码这么长,晕倒!? 跳过代码看分析!)

头文件:(TicTac.h)
//#include<afxwin.h>
#define EX 1
#define OH 2
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};

class CMainWindow:public CWnd
{
protected:
static const CRect m_rcSquares[9];
int m_nGameGrid[9];
int m_nNextChar;
int GetRectID(CPoint point);
void DrawBoard(CDC* pDC);
void DrawX(CDC* pDC,int nPos);
void DrawO(CDC* pDC,int nPos);
void ResetGame();
void CheckForGameOver();
int IsWinner();
BOOL IsDraw();
public:
CMainWindow();
protected:
virtual void PostNcDestroy();

afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
afx_msg void OnRButtonDown(UINT nFlags,CPoint point);
afx_msg void OnLButtonDblClk(UINT nFlags,CPoint point);

DECLARE_MESSAGE_MAP()
};
源文件:(TicTac.cpp)
#include<afxwin.h>
#include"TicTac.h"
CMyApp myApp;
/////////////////CMyAPP member functions//////////////////////////
BOOL CMyApp::InitInstance()
{
m_pMainWnd=new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
/////////////CMainWindow message map and member functions/////////
BEGIN_MESSAGE_MAP(CMainWindow,CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_RBUTTONDOWN()
ON_WM_LBUTTONDBLCLK()
END_MESSAGE_MAP()

const CRect CMainWindow::m_rcSquares[9]={
CRect(16,16,112,112),
CRect(128,16,224,112),
CRect(240,16,336,112),
CRect(16,128,112,224),
CRect(128,128,224,224),
CRect(240,128,336,224),
CRect(16,240,112,336),
CRect(128,240,224,336),
CRect(240,240,336,336)
};
CMainWindow::CMainWindow(){
m_nNextChar=EX;
::ZeroMemory(m_nGameGrid,9*sizeof(int));
//Register a WNDCLASS.
CString strWndClass=AfxRegisterWndClass(
CS_DBLCLKS,
AfxGetApp()->LoadStandardCursor(IDC_ARROW),
(HBRUSH)(COLOR_3DFACE+1),
AfxGetApp()->LoadStandardIcon(IDI_WINLOGO)
);
//create a window
CreateEx(0,strWndClass,_T("Tic-Tac-Toe"),
WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION|WS_MINIMIZEBOX,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL);
//Size the window
CRect rect(0,0,352,352);
CalcWindowRect(&rect);
SetWindowPos(NULL,0,0,rect.Width(),rect.Height(),
SWP_NOZORDER|SWP_NOMOVE|SWP_NOREDRAW);
}
void CMainWindow::PostNcDestroy()
{
delete this;
}
void CMainWindow::OnPaint()
{
CPaintDC dc(this);
DrawBoard(&dc);
}
void CMainWindow::OnLButtonDown(UINT nFlags,CPoint point)
{
//do nothing if it's O's turn,if the click occured ouside the
//tic-tac-toe grid. or if a  nonempty square was clicked.
if(m_nNextChar!=EX)
return;
int nPos=GetRectID(point);
if((nPos==-1)||(m_nGameGrid[nPos]!=0))
return;
//add an X to the game grid and toggle m_nNextChar.
m_nGameGrid[nPos]=EX;
m_nNextChar=OH;
//Draw an X on the screen and see if either player has won.
CClientDC dc(this);
DrawX(&dc,nPos);
CheckForGameOver();
}
void CMainWindow::OnRButtonDown(UINT nFlags,CPoint point)
{
//do nothing if it's X's turn,if the click occurred outside the
//tic-tac-toe grid,or if a nonempty square was clicked.
if(m_nNextChar!=OH)
return;
int nPos=GetRectID(point);
if((nPos==-1)||(m_nGameGrid[nPos]!=0))
return;
//add an O to the game grid and toggle m_nNextChar.
m_nGameGrid[nPos]=OH;
m_nNextChar=EX;
//Draw an O on the screen and see if either player has won.
CClientDC dc(this);
DrawO(&dc,nPos);
CheckForGameOver();
}
void CMainWindow::OnLButtonDblClk(UINT nFlags,CPoint point)
{
//Reset the game if one of the thick black lines defining the
//game gird is double-clicked with the left mouse button.
CClientDC dc(this);
if(dc.GetPixel(point)==RGB(0,0,0))
ResetGame();
}
int CMainWindow::GetRectID(CPoint point)
{
//Hit-test each of the grid's nine squares and return a
//rectangle ID(0-8) if (point.x,point.y) lies inside a square.
for(int i=0;i<9;i++){
if(m_rcSquares[i].PtInRect(point))
return i;
}
return -1;
}
void CMainWindow::DrawBoard(CDC* pDC)
{
//Draw the lines that define the tic-tac-toe grid.
CPen pen(PS_SOLID,16,RGB(0,0,0));
CPen * pOldPen=pDC->SelectObject(&pen);//selects an object into the device context.
//draw the first perpendicular
pDC->MoveTo(120,16);//MoveTo(x,y):moves the current position to the point(x,y)
pDC->LineTo(120,336);//LineTo(x,y):draws a line from the current position up to,but not including,the point(x,y)

pDC->MoveTo(232,16);//second perpendicular
pDC->LineTo(232,336);

pDC->MoveTo(16,120);//first horizon
pDC->LineTo(336,120);

pDC->MoveTo(16,232);
pDC->LineTo(336,232);

//Draw the Xs ans Os.
for(int i=0;i<9;i++){
if(m_nGameGrid[i]==EX)
DrawX(pDC,i);
else if(m_nGameGrid[i]==OH)
DrawO(pDC,i);
}
pDC->SelectObject(pOldPen);
}
void CMainWindow::DrawX(CDC *pDC,int nPos)
{
CPen pen(PS_SOLID,16,RGB(255,0,0));
CPen *pOldPen=pDC->SelectObject(&pen);

CRect rect=m_rcSquares[nPos];
rect.DeflateRect(16,16);
pDC->MoveTo(rect.left,rect.top);
pDC->LineTo(rect.right,rect.bottom);
pDC->MoveTo(rect.left,rect.bottom);
pDC->LineTo(rect.right,rect.top);

pDC->SelectObject(pOldPen);
}
void CMainWindow::DrawO(CDC* pDC,int nPos)
{
CPen pen(PS_SOLID,16,RGB(0,0,255));
CPen *pOldPen=pDC->SelectObject(&pen);
pDC->SelectStockObject(NULL_BRUSH);

CRect rect=m_rcSquares[nPos];
rect.DeflateRect(16,16);//deflate(缩?小?) rect
pDC->Ellipse(rect);

pDC->SelectObject(pOldPen);
}
void CMainWindow::CheckForGameOver()
{
int nWinner;
//if the grid contains three cosecutive Xs orOs,declare a
//winner and start a new game.
if(nWinner=IsWinner()){
CString string=(nWinner==EX)?
_T("X wins!"):_T("O wins!");
MessageBox(string,_T("Game over"),MB_ICONEXCLAMATION|MB_OK);
ResetGame();
}
//if the grid is full,declare a draw and start a new game.
else if(IsDraw()){
MessageBox(_T("It's a draw!"),_T("Game Over!"),
MB_ICONEXCLAMATION|MB_OK);
ResetGame();
}
}
int CMainWindow::IsWinner()
{
static int nPattern[8][3]={
0,1,2,
3,4,5,
6,7,8,
0,3,6,
1,4,7,
2,5,8,
0,4,8,
2,4,6
};
for(int i=0;i<8;i++){
if((m_nGameGrid[nPattern[i][0]]==EX)&&
(m_nGameGrid[nPattern[i][1]]==EX)&&
(m_nGameGrid[nPattern[i][2]]==EX))
return EX;
if((m_nGameGrid[nPattern[i][0]]==OH)&&
(m_nGameGrid[nPattern[i][1]]==OH)&&
(m_nGameGrid[nPattern[i][2]]==OH))
return OH;
}
return 0;
}

BOOL CMainWindow::IsDraw()//draw(平?局?)
{
for(int i=0;i<9;i++)
{
if(m_nGameGrid[i]==0)
return FALSE;
}
return TRUE;
}
void CMainWindow::ResetGame()
{
m_nNextChar=EX;
::ZeroMemory(m_nGameGrid,9*sizeof(int));
Invalidate();
}


井字游戏:游戏窗口如下图,将窗口分成了9个矩形区,



左键单击画X,右键单击画O,X、O轮流画!出现三个连续的图形就是赢!或者画完所有矩形区没有输赢就是平局!(这是单人游戏还是双人游戏?例子而已)

先看程序中的数据:9个矩形和矩形状态

一个矩形三种状态:空白是0,画X是1(#define EX 1),画O是2(#define OH 2)。

代码中:存储9个矩形的数组m_rcSquares[9](全程都在用,设为全局变量)。

存储9个矩形的状态的数组m_nGameGrid[9]。用m_nNextChar标记该画哪个了?。(局部变量)

程序处理流程分析:其实就这么些事情,不过函数定义的多了,相互调用的就多了。

InitInstance功能:创建窗口类的对象,显示出来,画出来。(一成不变的三步策略!)

CMainWindow功能:窗口类的构造函数()

(On开头的程序都是消息处理响应函数):

OnPaint功能:绘制窗口里的游戏界面(井字网格)

OnLButtonDown:鼠标点哪个矩形上了?轮到画X了吗?画X!检查游戏状态(有人赢了?谁赢了?平局了?新开一局!)

OnRButtonDown:鼠标点哪个矩形上了?轮到画O了吗?画O!检查游戏状态(有人赢了?谁赢了?平局了?新开一局!)

OnLButtonDblClk:鼠标点到黑色网格了?新开一局!

(以下函数是自定义的函数,实现特定的功能):

GetRectID:判断画到哪个矩形里了?

DrawBoard:绘制出窗口里的游戏界面

DrawX:画X

DrawO:画O

ResetGame:新开一局!

CheckForGameOver:有人赢了?谁赢了?原来平局了! 来新开一局!

IsWinner:判断谁赢了!?

IsDraw:平局了!?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: