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

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

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

>_<:TicTac.h

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

[游戏学习22] MFC 井字棋 双人对战的更多相关文章

  1. 井字棋游戏升级版 - TopTicTacToe项目 简介

    一.游戏简介 井字棋是一款世界闻名的游戏,不用我说,你一定知道它的游戏规则. 这款游戏简单易学,玩起来很有意思,不过已经证明出这款游戏如果两个玩家都足够聪明的话, 是很容易无法分出胜负的,即我们得到的 ...

  2. 强化学习实战 | 表格型Q-Learning玩井字棋(四)游戏时间

    在 强化学习实战 | 表格型Q-Learning玩井字棋(三)优化,优化 中,我们经过优化和训练,得到了一个还不错的Q表格,这一节我们将用pygame实现一个有人机对战,机机对战和作弊功能的井字棋游戏 ...

  3. 强化学习实战 | 自定义Gym环境之井字棋

    在文章 强化学习实战 | 自定义Gym环境 中 ,我们了解了一个简单的环境应该如何定义,并使用 print 简单地呈现了环境.在本文中,我们将学习自定义一个稍微复杂一点的环境--井字棋.回想一下井字棋 ...

  4. python 游戏(井字棋)

    1. 游戏思路和流程图 实现功能,现实生活中的井字棋玩法 游戏流程图 2. 使用模块和游戏提示 import random def game_info(): print('欢迎来到井字棋游戏') pr ...

  5. C++井字棋游戏,DOS界面版

    据说有一个能保证不败的算法.明天看看先再写个PVC版的. 正题.今天无聊写了个井字棋游戏,顺便逐渐让自己习惯良好的代码风格,放上来给新手学习学习. jzq2.cpp /* N字棋游戏PVP版,DOS版 ...

  6. 井字棋小游戏(C语言)

    最近沉迷于<NetHack>.<DCSS>等字符游戏,对其很感兴趣,于是用C语言写了个字符界面的井字棋小游戏.欢迎大家指教. 编写时遇到了一些问题,我原先准备用循环,直到读取到 ...

  7. 强化学习实战 | 表格型Q-Learning玩井字棋(一)

    在 强化学习实战 | 自定义Gym环境之井子棋 中,我们构建了一个井字棋环境,并进行了测试.接下来我们可以使用各种强化学习方法训练agent出棋,其中比较简单的是Q学习,Q即Q(S, a),是状态动作 ...

  8. 强化学习实战 | 表格型Q-Learning玩井字棋(二)

    在 强化学习实战 | 表格型Q-Learning玩井字棋(一)中,我们构建了以Game() 和 Agent() 类为基础的框架,本篇我们要让agent不断对弈,维护Q表格,提升棋力.那么我们先来盘算一 ...

  9. [CareerCup] 17.2 Tic Tac Toe 井字棋游戏

    17.2 Design an algorithm to figure out if someone has won a game oftic-tac-toe. 这道题让我们判断玩家是否能赢井字棋游戏, ...

随机推荐

  1. 无法连接到已配置的开发web服务器

    http://jingyan.baidu.com/article/29697b91099847ab20de3c8b.html 这是防火墙造成的,将防火墙关闭即可

  2. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  3. 实现MFC菜单画笔画圆,并且打钩

    这个是用最简单的方法,移动客户区,圆会不见,所以下一篇我还要改进. 首先新建一个MFC单文件,在资源那里的菜单下,建立画笔,可以弹出红画笔,蓝画笔和绿画笔,,给出ID_RED,ID_BLUE,ID_G ...

  4. Echarts tooltip文字没有左对齐

    tooltip : { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type : 'shadow' // 默认为直线,可选为:'line' | ...

  5. 【python3】collections系列介绍

    文章来源:http://www.jb51.net/article/48771.htm (http://www.cnblogs.com/wushank/p/5122786.html) 修改人:天马流行拳 ...

  6. Fedora20安装fcitx输入法

    Fedora20安装fcitx输入法 Fedora20默认安装的是ibus输入法,总有一些原因让我们选择fcitx输入法: ibus出词顺序有bug 在输入人名的时候,有些名字输入两三次后还是不会出现 ...

  7. stm32 MDK5软件仿真之查看io口输出

    软件MDK5 stm32的pack     打开MDK,添加工程 一.首先找到Project的Options选项,里面的Debug选为Use Simulator,也就是选择软件仿真. 然后再Logic ...

  8. C#版SQLHelper.cs类

    using System; using System.Data; using System.Xml; using System.Data.SqlClient; using System.Collect ...

  9. Scrum会议10.19

    Scrum会议 组名称:好好学习 项目名称:记账本 参会成员:林莉(Master)胡丽娜 宫丽君 汪东涵 时间:2016.10.19 已完成内容: 1.完成新项目的查找,查找学姐的代码和项目. 2.理 ...

  10. python py生成为pyc文件

    生成单个pyc文件 python就是个好东西,它提供了内置的类库来实现把py文件编译为pyc文件,这个模块就是 py_compile 模块. 使用方法非常简单,如下所示,直接在idle中,就可以把一个 ...