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. 一个最简单的登录页面测试case

    具体需求: 有一个登陆页面, (假如上面有2个textbox, 一个提交按钮. 请针对这个页面设计30个以上的testcase.) 此题的考察目的:面试者是否熟悉各种测试方法,是否有丰富的Web测试经 ...

  2. Xcode 字体 设置-- Xcode family没有显示的字体

    前往文件夹 -> /Users/user/Library/Developer/Xcode/UserData/FontAndColorThemes/  (user改为自己的用户名) -----如果 ...

  3. Spark-1.0.1 的make-distribution.sh编译、SBT编译、Maven编译 三种编译方法

    fesh个人实践,欢迎经验交流!本文Blog地址:http://www.cnblogs.com/fesh/p/3775343.html 本文编译方法所支持的hadoop环境是Hadoop-2.2.0, ...

  4. Bridge(桥接)-对象结构型模式

    1.意图 将抽象部分与它的实现部分分离,使它们都可以独立地变化. 2.动机 在抽象类与它的实现之间起到桥梁作用,使它们可以独立地变化. 3.适用性 不希望在抽象和它的实现部分之间有一个固定的绑定关系. ...

  5. 使用max() 函数

    /********************************* 代码功能:使用串口输出a和b的最大值 使用函数:max(a,b); 创作时间:2016*11*04 作者邮箱:jikexianfe ...

  6. ImportError: No module named setuptools 解决方案

    shell中输入: wget http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz --no-che ...

  7. AIX 开机启动网络服务配置

    aix7 administrator An administrator notices that the ntp group subsystem is not starting up at boot ...

  8. jsp的9大对象

    1.requset对象 主要用于接受客户端通过HTTP协议传送给服务器端的数据     request.getProtocal()获得客户使用协议     request.getServletPath ...

  9. js学习-DOM之动态创建元素的三种方式、插入元素、onkeydown与onkeyup两个事件整理

    动态创建元素的三种方式: 第一种: Document.write(); <body> <input type="button" id="btn" ...

  10. C# Winform程序获取外网IP地址

    string strUrl = "http://www.ip138.com/ip2city.asp"; //获得IP的网址了 Uri uri = new Uri(strUrl); ...