TicTac.h

 #define EX 1            //该点左鼠标
#define OH 2 //该点右鼠标 class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
}; class CMainWindow : public CWnd //不是继承CFrameWnd 因此需要在CMainWindow()自己定义窗口类了
{
protected:
static const CRect m_rcSquares[]; // Grid coordinates
int m_nGameGrid[]; // 9个格子的状态是否被下0没下;1左下了;2右下了
int m_nNextChar; // 下一个鼠标状态左or右 (EX or OH)
bool ptab[][]; //玩家的获胜的状态表
bool ctab[][]; //电脑的获胜的状态表
int win[][]; //每种状态表里的棋子数 int GetRectID (CPoint point);
void DrawBoard (CDC* pDC);
void DrawX (CDC* pDC, int nPos);
void DrawO (CDC* pDC, int nPos);
void CpDraw(CDC* pDC);
void InitGame();
void out();
void ResetGame ();
bool CheckForGameOver ();
int IsWinner ();
BOOL IsDraw (); public:
CMainWindow (); protected:
virtual void PostNcDestroy ();//在程序终止之前销毁CMainWindow对象 afx_msg void OnPaint ();
afx_msg void OnLButtonDown (UINT nFlags, CPoint point);
afx_msg void OnLButtonDblClk (UINT nFlags, CPoint point);
afx_msg void OnRButtonDown (UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP ()
};

TicTac.cpp

 #include <afxwin.h>
#include "TicTac.h"
#include <fstream>
#include <iostream>
#include<iomanip>
using namespace std;
CMyApp myApp;
/*ofstream Cout("out.txt");
void CMainWindow::out(){
Cout<<"ptab[][]=:\n";
for(int i=0;i<9;i++){
for(int j=0;j<8;j++)
Cout<<setw(3)<<ptab[i][j]<<' ';
Cout<<'\n';
}
Cout<<"ctab[][]=:\n";
for(int i=0;i<9;i++){
for(int j=0;j<8;j++)
Cout<<setw(3)<<ctab[i][j]<<' ';
Cout<<'\n';
}
Cout<<"win[][]=:\n";
for(int i=0;i<2;i++){
for(int j=0;j<8;j++)
Cout<<setw(3)<<win[i][j]<<' ';
Cout<<'\n';
}
}*/
/////////////////////////////////////////////////////////////////////////
// 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_LBUTTONDBLCLK ()
ON_WM_RBUTTONDOWN ()
END_MESSAGE_MAP () //9个矩形区域用来判定鼠标是否点进某一区域
const CRect CMainWindow::m_rcSquares[] = {
CRect ( , , , ),
CRect (, , , ),
CRect (, , , ),
CRect ( , , , ),
CRect (, , , ),
CRect (, , , ),
CRect ( , , , ),
CRect (, , , ),
CRect (, , , )
}; CMainWindow::CMainWindow ()
{
//初始化游戏
InitGame(); //注册一个 WNDCLASS 窗口类.
CString strWndClass = AfxRegisterWndClass (
CS_DBLCLKS, // Class style(有双击时间发生的窗口类型)
AfxGetApp ()->LoadStandardCursor (IDC_ARROW), // Class cursor(加载一个系统光标,也可自己定义)
(HBRUSH) (COLOR_3DFACE + ), // Background brush(每次::BeginPaint时用它清空客户区);COLOR_3DFACE+1是指定窗口具有与按钮对话框一致的背景色和其他一些3D属性;默认为灰亮色
AfxGetApp ()->LoadStandardIcon (IDI_WINLOGO) // Class icon(加载系统图标,也可自己定义)
); //调用CWnd::CreateEx()创建主窗口
//第一个参数表示0个或是多个WS_EX标志组合;2:AfxRegisterWndClass()返回的WNDCLASS名称;
//3、标题;4、窗口样式
CreateEx (, strWndClass, _T ("井字棋"),
WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX, //WS_THICKFRAME窗口可调大小属性(这里不用)
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, //初始位置和大小,这里用CW_USEDEFAULT让Windows拾取窗口和大小
NULL, NULL); //处理窗口位置和尺寸
CRect rect (, , , ); //理想客户区窗口矩形形状
CalcWindowRect (&rect); //根据分辨率、菜单...计算窗口矩形大小(必须在窗口创建后调用) SetWindowPos (NULL, , , rect.Width (), rect.Height (),
SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
} //在程序结束之前销毁创建的CMainWindow对象
void CMainWindow::PostNcDestroy ()
{
delete this;
} //OnPaint()响应每次重绘棋盘
void CMainWindow::OnPaint ()
{
CPaintDC dc (this);
DrawBoard (&dc);
} //单击鼠标左键响应
void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)
{
CClientDC dc (this); //如果不该左键响应(即不该左键下,返回)
if (m_nNextChar != EX){
return ;
} //获得点击矩形区域编号
//如果没有点中或者已经被下棋了,返回
int nPos = GetRectID (point);
if ((nPos == -) || (m_nGameGrid[nPos] != ))
return; //标记已下并改变下一个点击状态
m_nGameGrid[nPos] = EX;
m_nNextChar = OH; //画上图并判断游戏是否结束
DrawX (&dc, nPos);
if(CheckForGameOver ())return; //后续改变胜利表和各人、机各胜利组合的棋子数
for(int i=;i<;i++){
if(ptab[nPos][i]){
win[][i]++;
ctab[nPos][i]=false;
win[][i]=;
}
} //电脑下棋
CpDraw(&dc);
if(CheckForGameOver ())return;
} //单击鼠标右键响应(同左键)
void CMainWindow::OnRButtonDown (UINT nFlags, CPoint point)
{
if (m_nNextChar != OH)
return; int nPos = GetRectID (point);
if ((nPos == -) || (m_nGameGrid[nPos] != ))
return; m_nGameGrid[nPos] = OH;
m_nNextChar = EX; CClientDC dc (this);
DrawO (&dc, nPos);
CheckForGameOver ();
} //左键双击边框重新开始
//dc.GetPixel (Point point)获取当前光标下像素颜色判断与黑色匹配
void CMainWindow::OnLButtonDblClk (UINT nFlags, CPoint point)
{
CClientDC dc (this);
if (dc.GetPixel (point) == RGB (, , ))
ResetGame ();
} //判定鼠标是否点进矩形某一区域,点进返回区域编号,没有返回-1
//此处用了一个rect.PtInRect(Point point)函数帮助判定
int CMainWindow::GetRectID (CPoint point)
{
for (int i=; i<; i++) {
if (m_rcSquares[i].PtInRect (point))
return i;
}
return -;
} //画上棋盘并画上圈和叉
void CMainWindow::DrawBoard (CDC* pDC)
{
//画上棋盘
CPen pen (PS_SOLID, , RGB (, , ));
CPen* pOldPen = pDC->SelectObject (&pen); pDC->MoveTo (, );
pDC->LineTo (, ); pDC->MoveTo (, );
pDC->LineTo (, ); pDC->MoveTo (, );
pDC->LineTo (, ); pDC->MoveTo (, );
pDC->LineTo (, ); //画上叉和圈
for (int i=; i<; 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, , RGB (, , ));//宽为16像素的红笔
CPen* pOldPen = pDC->SelectObject (&pen); CRect rect = m_rcSquares[nPos];
rect.DeflateRect (, );//把矩形每个方向都缩进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, , RGB (, , ));//宽为16像素的红笔
CPen* pOldPen = pDC->SelectObject (&pen);
pDC->SelectStockObject (NULL_BRUSH); //空画刷是为了防止画出的圆内部出现白色遮住背景 CRect rect = m_rcSquares[nPos];
rect.DeflateRect (, );//把矩形每个方向都缩进16个像素作为圆的边框
pDC->Ellipse (rect); pDC->SelectObject (pOldPen);
} //电脑画图
void CMainWindow::CpDraw(CDC* pDC)
{
int grades[][];
int m,i,max=;
int u; for(m=;m<;m++)
{
grades[][m]=;
grades[][m]=; if(m_nGameGrid[m]==)
{
for(i=;i<;i++)
{
//计算玩家在空棋格上的获胜分数
if(ptab[m][i] && win[][i]!=)
{
switch(win[][i])
{
case :
grades[][m]+=;
break;
case :
grades[][m]+=;
break;
case :
grades[][m]+=;
break;
}
} //计算计算机在空格上的获胜分数
if(ctab[m][i] && win[][i]!=)
{
switch(win[][i])
{
case :
grades[][m]+=;
break;
case :
grades[][m]+=;
break;
case :
grades[][m]+=;
break;
}
}
} if(max==)u=m; if(grades[][m]>max){
max=grades[][m];
u=m;
}
else if(grades[][m]==max){
if(grades[][m]>grades[][u])u=m;
} if(grades[][m]>max){
max=grades[][m];
u=m;
}
else if(grades[][m]==max){
if(grades[][m]>grades[][u])u=m;
}
}
} //标记已下并改变下一个点击状态
m_nGameGrid[u]=OH;
m_nNextChar = EX; //画上图
DrawO(pDC,u); //后续改变胜利表和各人、机各胜利组合的棋子数
for(i=;i<;i++){
if(ctab[u][i]){
win[][i]++;
ptab[u][i]=false;
win[][i]=;
}
}
} //响应胜利结束的函数
bool CMainWindow::CheckForGameOver ()
{
int nWinner; //通过调用IsWinner ()函数获取谁获胜;并用MessageBox输出胜利消息;响应OK后重开一局
//==Message(CString,_T(标题),类型)
if (nWinner = IsWinner ()) {
CString string = (nWinner == EX) ?
_T ("X wins!") : _T ("O wins!");
MessageBox (string, _T ("Game Over"), MB_ICONEXCLAMATION | MB_OK);
ResetGame ();
return ;
} //通过IsDraw ()函数判断是否平局
else if (IsDraw ()) {
MessageBox (_T ("It's a draw!"), _T ("Game Over"),
MB_ICONEXCLAMATION | MB_OK);
ResetGame ();
return ;
}
return ;
} //判断输赢EX左胜;OH右胜;0没有胜
int CMainWindow::IsWinner ()
{
//用静态数组存储获胜组合
static int nPattern[][] = {
, , ,
, , ,
, , ,
, , ,
, , ,
, , ,
, , ,
, ,
}; for (int i=; i<; i++) {
if ((m_nGameGrid[nPattern[i][]] == EX) &&
(m_nGameGrid[nPattern[i][]] == EX) &&
(m_nGameGrid[nPattern[i][]] == EX))
return EX; if ((m_nGameGrid[nPattern[i][]] == OH) &&
(m_nGameGrid[nPattern[i][]] == OH) &&
(m_nGameGrid[nPattern[i][]] == OH))
return OH;
}
return ;
} //判断是否平局函数
BOOL CMainWindow::IsDraw ()
{
for (int i=; i<; i++) {
if (m_nGameGrid[i] == )
return FALSE;
}
return TRUE;
} //初始化游戏
void CMainWindow::InitGame()
{ int i,k;
int count=; //设定玩家与计算机在各个获胜组合中的棋子数
for(i=;i<;i++)
{
win[][i]=;
win[][i]=;
} //初始化棋盘状态
::ZeroMemory (m_nGameGrid,*sizeof(int));
memset(ctab,,sizeof(ctab));
memset(ptab,,sizeof(ptab));
//设定水平方向的获胜组合
for(i=;i<=;i+=)
{
for(k=;k<;k++)//3个棋子1个获胜组合
{
ptab[i+k][count]=true;
ctab[i+k][count]=true;
}
count++;
} //设定垂直方向的获胜组合
for(k=;k<;k++)
{
for(i=;i<=;i+=)//3个棋子1个获胜组合
{
ptab[i+k][count]=true;
ctab[i+k][count]=true;
}
count++;
} //设定对角线方向上的获胜组合
for(i=;i<=;i+=){
ptab[i][count]=true;
ctab[i][count]=true;
}count++;
for(i=;i<=;i+=){
ptab[i][count]=true;
ctab[i][count]=true;
} srand(unsigned(time(NULL))); m_nNextChar = EX;//玩家先走
}
//重新开始初始化
void CMainWindow::ResetGame ()
{
InitGame();
Invalidate (); //使控件的整个图面无效并导致重绘控件
}

人机对战井字棋

[C++] 井字棋游戏源码的更多相关文章

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

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

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

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

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

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

  4. JavaFX 井字棋游戏

    利用JavaFX设计一个井字棋游戏,其中包括了能够与玩家对战的AI.AI的实现相比五子棋来说要简单得多,可以保证AI在后手情况下绝对不会输,具体实现如下: /* * To change this li ...

  5. Java井字棋游戏

    试着写了一个井字棋游戏,希望各位能给予一些宝贵的建议. 一.棋盘类 package 井字棋游戏; public class ChessBoard { private int number; Perso ...

  6. [LeetCode] 348. Design Tic-Tac-Toe 设计井字棋游戏

    Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...

  7. [LeetCode] Design Tic-Tac-Toe 设计井字棋游戏

    Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...

  8. Raptor井字棋游戏

    作为大学第一个小作品,记录一下,也给那些想接触到Raptor游戏的人一个小小的参考QAQ至于Raptor的语法和使用,可以参考一下他的帮助手册,看不懂英文的话可以复制放到翻译上看. 以上是主函数 以下 ...

  9. [Swift]LeetCode348. 设计井字棋游戏 $ Design Tic-Tac-Toe

    Design a Tic-tac-toe game that is played between two players on a n x n grid. You may assume the fol ...

随机推荐

  1. VC++ excel 2 operations

    LPDISPATCH lpDisp;   //lpdispatch,接口指针 // 设置为FALSE时,加上app.Quit(); // 否则EXCEL.EXE进程会一直存在,并且每操作一次就会多开一 ...

  2. java与微信企业号交互

    微信企业号接收消息(使用SpringMVC): http://blog.csdn.net/omsvip/article/details/39480577 微信企业号api: http://qydev. ...

  3. hdu 2196 computer

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  4. 快考试了,尽快写完HashTable。

    (1)Count Primes 质数(素数):在大于1 的自然数中,除了1和它本身之外,不能被任何其他整数整除. 解题思路:使用一个boolean类型的数组,从i(2) 开始循环,将小于N的i的倍数都 ...

  5. fastjson基本使用 (待大量完善)

    参考: http://blog.csdn.net/wx_962464/article/details/37612861 maven库下载 fastjson基本使用 import java.util.A ...

  6. Python随机森林算法的使用

    #coding:utf-8 # from python.Lib.packages.sklearn.tree import DecisionTreeClassifier # from python.Li ...

  7. TCP通讯socket自定义协议的实现

    转发(JAVA):http://blog.csdn.net/u010818425/article/details/53448817 一个简单的自定义通信协议(socket),http://blog.c ...

  8. .NET实现高效过滤敏感查找树算法(分词算法):

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. Select查询语句2

    一.模糊查询 1.语法结构 select*from table_name where column like '%context%' 在使用like运算符时如果不使用通配符“%”,则like的作用与= ...

  10. AngularJS学习--- 事件处理(Event Handlers) ng-click操作 step 10

    本文主要通过介绍ng-click方法来对angularjs中的事件处理方法做个了解. 1.切换目录 git checkout step- npm start 2.效果 点击右边的小图片,那么左边框中将 ...