1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > [游戏学习22] MFC 井字棋 双人对战

[游戏学习22] MFC 井字棋 双人对战

时间:2020-08-22 14:20:06

相关推荐

[游戏学习22] MFC 井字棋 双人对战

>_<:太多啦,感觉用英语说的太慢啦,没想到一年做的东西竟然这么多.....接下来要加速啦!

>_<:注意这里必须用MFC和前面的Win32不一样啦!

>_<:这也是第一次出现MFC游戏,其框架和逻辑的写法和Win32有很大的区别,建议先看一下MFC的基础再理解代码:

>_<:TicTac.h

1 #define EX 1 //该点左鼠标 2 #define OH 2 //该点右鼠标 3 4 class CMyApp : public CWinApp 5 { 6 public: 7virtual BOOL InitInstance (); 8 }; 9 10 class CMainWindow : public CWnd //不是继承CFrameWnd 因此需要在CMainWindow()自己定义窗口类了11 {12 protected:13static const CRect m_rcSquares[9]; // Grid coordinates14int m_nGameGrid[9]; // 9个格子的状态是否被下0没下;1左下了;2右下了15int m_nNextChar; // 下一个鼠标状态左or右 (EX or OH)16bool ptab[9][8]; //玩家的获胜的状态表17bool ctab[9][8]; //电脑的获胜的状态表18int win[2][8]; //每种状态表里的棋子数19 20int GetRectID (CPoint point);21void DrawBoard (CDC* pDC);22void DrawX (CDC* pDC, int nPos);23void DrawO (CDC* pDC, int nPos);24void CpDraw(CDC* pDC);25void InitGame();26void out();27void ResetGame ();28bool CheckForGameOver ();29int IsWinner ();30BOOL IsDraw ();31 32 public:33CMainWindow ();34 35 protected:36virtual void PostNcDestroy ();//在程序终止之前销毁CMainWindow对象37 38afx_msg void OnPaint ();39afx_msg void OnLButtonDown (UINT nFlags, CPoint point);40afx_msg void OnLButtonDblClk (UINT nFlags, CPoint point);41afx_msg void OnRButtonDown (UINT nFlags, CPoint point);42 43DECLARE_MESSAGE_MAP ()44 };

>_<:TicTac.cpp

1 #include <afxwin.h> 2 #include "TicTac.h" 3 #include <fstream> 4 #include <iostream> 5 #include<iomanip> 6 using namespace std; 7 CMyApp myApp; 8 /*ofstream Cout("out.txt"); 9 void CMainWindow::out(){ 10Cout<<"ptab[][]=:\n"; 11for(int i=0;i<9;i++){ 12 for(int j=0;j<8;j++) 13 Cout<<setw(3)<<ptab[i][j]<<' '; 14 Cout<<'\n'; 15} 16Cout<<"ctab[][]=:\n"; 17for(int i=0;i<9;i++){ 18 for(int j=0;j<8;j++) 19 Cout<<setw(3)<<ctab[i][j]<<' '; 20 Cout<<'\n'; 21} 22Cout<<"win[][]=:\n"; 23for(int i=0;i<2;i++){ 24 for(int j=0;j<8;j++) 25 Cout<<setw(3)<<win[i][j]<<' '; 26 Cout<<'\n'; 27} 28 }*/ 29 / 30 // CMyApp member functions 31 32 BOOL CMyApp::InitInstance () 33 { 34m_pMainWnd = new CMainWindow; 35m_pMainWnd->ShowWindow (m_nCmdShow); 36m_pMainWnd->UpdateWindow (); 37return TRUE; 38 } 39 40 / 41 // CMainWindow message map and member functions 42 43 BEGIN_MESSAGE_MAP (CMainWindow, CWnd) 44ON_WM_PAINT () 45ON_WM_LBUTTONDOWN () 46ON_WM_LBUTTONDBLCLK () 47ON_WM_RBUTTONDOWN () 48 END_MESSAGE_MAP () 49 50 //9个矩形区域用来判定鼠标是否点进某一区域 51 const CRect CMainWindow::m_rcSquares[9] = { 52CRect ( 16, 16, 112, 112), 53CRect (128, 16, 224, 112), 54CRect (240, 16, 336, 112), 55CRect ( 16, 128, 112, 224), 56CRect (128, 128, 224, 224), 57CRect (240, 128, 336, 224), 58CRect ( 16, 240, 112, 336), 59CRect (128, 240, 224, 336), 60CRect (240, 240, 336, 336) 61 }; 62 63 CMainWindow::CMainWindow () 64 { 65//初始化游戏 66InitGame(); 6768 6970//注册一个 WNDCLASS 窗口类. 71CString strWndClass = AfxRegisterWndClass ( 72 CS_DBLCLKS,// Class style(有双击时间发生的窗口类型) 73 AfxGetApp ()->LoadStandardCursor (IDC_ARROW), // Class cursor(加载一个系统光标,也可自己定义) 74 (HBRUSH) (COLOR_3DFACE + 1),// Background brush(每次::BeginPaint时用它清空客户区);COLOR_3DFACE+1是指定窗口具有与按钮对话框一致的背景色和其他一些3D属性;默认为灰亮色 75 AfxGetApp ()->LoadStandardIcon (IDI_WINLOGO) // Class icon(加载系统图标,也可自己定义) 76); 77 78//调用CWnd::CreateEx()创建主窗口 79//第一个参数表示0个或是多个WS_EX标志组合;2:AfxRegisterWndClass()返回的WNDCLASS名称; 80//3、标题;4、窗口样式 81CreateEx (0, strWndClass, _T ("井字棋"), 82 WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, //WS_THICKFRAME窗口可调大小属性(这里不用) 83 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, //初始位置和大小,这里用CW_USEDEFAULT让Windows拾取窗口和大小 84 NULL, NULL); 85 86//处理窗口位置和尺寸 87CRect rect (0, 0, 352, 352); //理想客户区窗口矩形形状 88CalcWindowRect (&rect); //根据分辨率、菜单...计算窗口矩形大小(必须在窗口创建后调用) 89 90SetWindowPos (NULL, 0, 0, rect.Width (), rect.Height (), 91 SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW); 92 } 93 94 //在程序结束之前销毁创建的CMainWindow对象 95 void CMainWindow::PostNcDestroy () 96 { 97delete this; 98 } 99 100 //OnPaint()响应每次重绘棋盘101 void CMainWindow::OnPaint ()102 {103CPaintDC dc (this);104DrawBoard (&dc); 105 }106 107 108 //单击鼠标左键响应109 void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)110 {111CClientDC dc (this);112 113//如果不该左键响应(即不该左键下,返回)114if (m_nNextChar != EX){115 return ;116}117 118//获得点击矩形区域编号119//如果没有点中或者已经被下棋了,返回120int nPos = GetRectID (point); 121if ((nPos == -1) || (m_nGameGrid[nPos] != 0)) 122 return;123 124//标记已下并改变下一个点击状态125m_nGameGrid[nPos] = EX;126m_nNextChar = OH;127 128//画上图并判断游戏是否结束129DrawX (&dc, nPos);130if(CheckForGameOver ())return;131 132//后续改变胜利表和各人、机各胜利组合的棋子数133for(int i=0;i<8;i++){134 if(ptab[nPos][i]){135 win[0][i]++;136 ctab[nPos][i]=false;137 win[1][i]=5;138 }139}140 141//电脑下棋142CpDraw(&dc);143if(CheckForGameOver ())return;144 }145 146 //单击鼠标右键响应(同左键)147 void CMainWindow::OnRButtonDown (UINT nFlags, CPoint point)148 {149if (m_nNextChar != OH)150 return;151 152int nPos = GetRectID (point);153if ((nPos == -1) || (m_nGameGrid[nPos] != 0))154 return;155 156m_nGameGrid[nPos] = OH;157m_nNextChar = EX;158 159CClientDC dc (this);160DrawO (&dc, nPos);161CheckForGameOver ();162 }163 164 //左键双击边框重新开始165 //dc.GetPixel (Point point)获取当前光标下像素颜色判断与黑色匹配166 void CMainWindow::OnLButtonDblClk (UINT nFlags, CPoint point)167 {168CClientDC dc (this);169if (dc.GetPixel (point) == RGB (0, 0, 0))170 ResetGame ();171 }172 173 //判定鼠标是否点进矩形某一区域,点进返回区域编号,没有返回-1174 //此处用了一个rect.PtInRect(Point point)函数帮助判定175 int CMainWindow::GetRectID (CPoint point)176 {177for (int i=0; i<9; i++) {178 if (m_rcSquares[i].PtInRect (point))179 return i;180}181return -1;182 }183 184 //画上棋盘并画上圈和叉185 void CMainWindow::DrawBoard (CDC* pDC)186 {187//画上棋盘188CPen pen (PS_SOLID, 16, RGB (0, 0, 0));189CPen* pOldPen = pDC->SelectObject (&pen);190 191pDC->MoveTo (120, 16);192pDC->LineTo (120, 336);193 194pDC->MoveTo (232, 16);195pDC->LineTo (232, 336);196 197pDC->MoveTo (16, 120);198pDC->LineTo (336, 120);199 200pDC->MoveTo (16, 232);201pDC->LineTo (336, 232);202 203//画上叉和圈204for (int i=0; i<9; i++) {205 if (m_nGameGrid[i] == EX)206 DrawX (pDC, i);207 else if (m_nGameGrid[i] == OH)208 DrawO (pDC, i);209}210pDC->SelectObject (pOldPen);211 }212 213 //画叉函数214 void CMainWindow::DrawX (CDC* pDC, int nPos)215 {216CPen pen (PS_SOLID, 16, RGB (255, 0, 0));//宽为16像素的红笔217CPen* pOldPen = pDC->SelectObject (&pen);218 219CRect rect = m_rcSquares[nPos];220rect.DeflateRect (16, 16);//把矩形每个方向都缩进16个像素作为线条边框221pDC->MoveTo (rect.left, rect.top);222pDC->LineTo (rect.right, rect.bottom);223pDC->MoveTo (rect.left, rect.bottom);224pDC->LineTo (rect.right, rect.top);225 226pDC->SelectObject (pOldPen);227 }228 229 //画圈函数230 void CMainWindow::DrawO (CDC* pDC, int nPos)231 {232CPen pen (PS_SOLID, 16, RGB (0, 0, 255));//宽为16像素的红笔233CPen* pOldPen = pDC->SelectObject (&pen);234pDC->SelectStockObject (NULL_BRUSH);//空画刷是为了防止画出的圆内部出现白色遮住背景235 236CRect rect = m_rcSquares[nPos];237rect.DeflateRect (16, 16);//把矩形每个方向都缩进16个像素作为圆的边框238pDC->Ellipse (rect);239 240pDC->SelectObject (pOldPen);241 }242 243 //电脑画图244 void CMainWindow::CpDraw(CDC* pDC)245 {246int grades[2][9];247int m,i,max=0;248int u;249 250for(m=0;m<9;m++)251{252 grades[0][m]=0;253 grades[1][m]=0;254 255 if(m_nGameGrid[m]==0)256 {257 for(i=0;i<8;i++)258 {259 //计算玩家在空棋格上的获胜分数260 if(ptab[m][i] && win[0][i]!=5)261 {262switch(win[0][i])263{264case 0:265 grades[0][m]+=1;266 break;267case 1:268 grades[0][m]+=2000;269 break;270case 2:271 grades[0][m]+=10000;272 break;273}274 }275 276 //计算计算机在空格上的获胜分数277 if(ctab[m][i] && win[1][i]!=5)278 {279 switch(win[1][i])280 {281case 0:282 grades[1][m]+=1;283 break;284case 1:285 grades[1][m]+=2001;286 break;287case 2:288 grades[1][m]+=10001;289 break;290 }291 }292 }293 294 if(max==0)u=m;295 296 if(grades[0][m]>max){297 max=grades[0][m];298 u=m; 299 }300 else if(grades[0][m]==max){301 if(grades[1][m]>grades[1][u])u=m;302 }303 304 if(grades[1][m]>max){305 max=grades[1][m];306 u=m; 307 }308 else if(grades[1][m]==max){309 if(grades[0][m]>grades[0][u])u=m;310 }311 }312}313 314//标记已下并改变下一个点击状态315m_nGameGrid[u]=OH;316m_nNextChar = EX;317 318//画上图319DrawO(pDC,u);320321//后续改变胜利表和各人、机各胜利组合的棋子数322for(i=0;i<8;i++){323 if(ctab[u][i]){324 win[1][i]++;325 ptab[u][i]=false;326 win[0][i]=5;327 }328}329 }330 331 //响应胜利结束的函数332 bool CMainWindow::CheckForGameOver ()333 {334int nWinner;335 336//通过调用IsWinner ()函数获取谁获胜;并用MessageBox输出胜利消息;响应OK后重开一局337//==Message(CString,_T(标题),类型)338if (nWinner = IsWinner ()) {339 CString string = (nWinner == EX) ?340 _T ("X wins!") : _T ("O wins!");341 MessageBox (string, _T ("Game Over"), MB_ICONEXCLAMATION | MB_OK);342 ResetGame ();343 return 1;344}345 346//通过IsDraw ()函数判断是否平局347else if (IsDraw ()) {348 MessageBox (_T ("It's a draw!"), _T ("Game Over"),349 MB_ICONEXCLAMATION | MB_OK);350 ResetGame ();351 return 1;352}353return 0;354 }355 356 //判断输赢EX左胜;OH右胜;0没有胜357 int CMainWindow::IsWinner ()358 {359//用静态数组存储获胜组合360static int nPattern[8][3] = {361 0, 1, 2,362 3, 4, 5,363 6, 7, 8,364 0, 3, 6,365 1, 4, 7,366 2, 5, 8,367 0, 4, 8,368 2, 4, 6369};370 371for (int i=0; i<8; i++) {372 if ((m_nGameGrid[nPattern[i][0]] == EX) &&373 (m_nGameGrid[nPattern[i][1]] == EX) &&374 (m_nGameGrid[nPattern[i][2]] == EX))375 return EX;376 377 if ((m_nGameGrid[nPattern[i][0]] == OH) &&378 (m_nGameGrid[nPattern[i][1]] == OH) &&379 (m_nGameGrid[nPattern[i][2]] == OH))380 return OH;381}382return 0;383 }384 385 //判断是否平局函数386 BOOL CMainWindow::IsDraw ()387 {388for (int i=0; i<9; i++) {389 if (m_nGameGrid[i] == 0)390 return FALSE;391}392return TRUE;393 }394 395 //初始化游戏396 void CMainWindow::InitGame()397 {398 399int i,k;400int count=0;401 402//设定玩家与计算机在各个获胜组合中的棋子数403for(i=0;i<8;i++)404{405 win[0][i]=0;406 win[1][i]=0;407}408 409//初始化棋盘状态410::ZeroMemory (m_nGameGrid,9*sizeof(int));411memset(ctab,0,sizeof(ctab));412memset(ptab,0,sizeof(ptab));413//设定水平方向的获胜组合414for(i=0;i<=6;i+=3)415{416 for(k=0;k<3;k++)//3个棋子1个获胜组合417 {418 ptab[i+k][count]=true;419 ctab[i+k][count]=true;420 }421 count++;422}423 424//设定垂直方向的获胜组合425for(k=0;k<3;k++)426{427 for(i=0;i<=6;i+=3)//3个棋子1个获胜组合428 {429 ptab[i+k][count]=true;430 ctab[i+k][count]=true;431 }432 count++;433}434 435 436//设定对角线方向上的获胜组合437for(i=2;i<=6;i+=2){438 ptab[i][count]=true;439 ctab[i][count]=true;440}count++;441for(i=0;i<=8;i+=4){442 ptab[i][count]=true;443 ctab[i][count]=true;444}445 446447srand(unsigned(time(NULL)));448 449m_nNextChar = EX;//玩家先走450 }451 //重新开始初始化452 void CMainWindow::ResetGame ()453 {454InitGame();455Invalidate (); //使控件的整个图面无效并导致重绘控件456 }

本文转自beautifulzzzz博客园博客,原文链接:/zjutlitao/p/3735215.html,如需转载请自行联系原作者

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。