五子棋
五子棋是一种很受人们喜爱的游戏,它的规则简单,但玩法变化多端,富有趣味性,
适合人们消遣。这里我们就来设计一个五子棋游戏。
(一) (一) 人对人游戏
1. 1. 游戏实现
人对人游戏,其实只是对游戏规则的实现,我们只是利用五子棋游戏的规则来编程,
至于真正的游戏实现——计算机的“智能”算法,我们将在后面讲述。
五子棋的规则很简单:
1,判断是否能放下棋子(是否已经有了棋子);
2,判断是哪种颜色下棋;
3,判断是否已经结束(是谁赢?)。
这些规则,我们将用相应的函数来实现。
其它,我们还将介绍其它一些功能的实现。如鼠标的更换,工具栏和状态栏的编辑,
类与类之间的相互调用。
新建工程 3_1,选择单文档,在 Step 4 of 6 中先中 Windows Sockets 复选框。如下图:
图 3-1-1
2. 2. 资源编辑
由于我们这个程序出现的关于资源编辑的内容太多,我们具体介绍如下:
见下图 3-1-2,我们需要添加的有:
图 3-1-2
黑白位图 Bitmap 以表示棋盘上面的棋子:
IDB_BLACK
IDB_WHITE
黑白鼠标 Cursor 以替换当前鼠标:
IDC_CURSOR1 黑棋子
IDC_CURSOR2 白棋子
说明:
由于下棋时我们必须把鼠标热点设置在中间,点击下图(图 3-1-3)最右边按扭,
然后把鼠标移动到图像中你想设置为热点的地方,按下鼠标左键。
图 3-1-3
黑白图标 Icon 以显示在状态栏供以提示:
IDI_BLACK
IDI_WHITE
说明:
由于我们的图标支持 256 色,按下下图(图 3-1-4)最右边按扭,选择 Device
里面显示的选项。
图 3-1-4
菜单以供操作:
开始: ID_START
保存: ID_SAVE
打开: ID_OPEN
工具栏:
如上图所示。
说明:
工具栏一般都是根据菜单选项而产生的,它的 ID 一般都能从菜单的 ID 中找
到。
3. 3. 变量函数
首先,为了实现状态栏的应用,我们必须更改它的变量:
在 MainFrm.h 文件里面,把 CStatusBar m_wndStatusBar 为 public
接着是在 3_1View.h 文件里面添加变量函数:
//两个鼠标
HCURSOR hcursorwhite;
HCURSOR hcursorblack;
//棋盘数组
int wzq[19][19];
// colorwhite TRUE 时白棋下,否则黑棋下
bool colorwhite;
//棋子位图
CBitmap m_bmblack;
CBitmap m_bmwhite;
//保存文件
void Save();
//检查是否结束
void over(CPoint point);
//鼠标操作
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
//鼠标图形更换
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
//菜单的开始
afx_msg void OnStart();
//菜单的保存
afx_msg void OnSave();
//菜单的打开
afx_msg void OnOpen();
4. 4. 具体实现
棋盘大小设置:
由于我们的游戏的棋盘大小是一定的,不能改变大小的,是应该符合要求的。在如下
函数添加设置窗口大小的语句:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
//
cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST;
the CREATESTRUCT cs
//
cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;//;
//设置窗口大小:400*340
cs.cx=450;
cs.cy=500;
return TRUE;
}
初始化变量:
在构造函数里添加初始代码:
CMy3_1View::CMy3_1View()
{
// TODO: add construction code here
//Load 鼠标图像和棋子位图
hcursorblack=AfxGetApp()->LoadCursor(IDC_CURSOR1);
hcursorwhite=AfxGetApp()->LoadCursor(IDC_CURSOR2);
m_bmwhite.LoadBitmap(IDB_WHITE);
m_bmblack.LoadBitmap(IDB_BLACK);
//清理棋盘
//数组值为 0 表示没有棋子
for(int i=0;i<19;i++)
for(int j=0;j<19;j++)
wzq[i][j]=0;
//白棋先下
colorwhite=true;
}
画棋盘:
在 OnDraw(CDC* pDC)函数中画棋盘,由于在游戏过程中有可能重画棋盘,而那时棋盘
上面有棋子,所以,我们在这个函数里面必须有画棋子的语句。
我们用数组的做为 1 表示白棋,-1 表示黑棋。
void CMy3_1View::OnDraw(CDC* pDC)
{
CMy3_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//画背景
CBrush mybrush1;
mybrush1.CreateSolidBrush(RGB(192,192,192));
CRect myrect1(0,0,1200,800);
pDC->FillRect(myrect1,&mybrush1);
//画棋盘框线
CPen mypen;
CPen*myoldPen;
mypen.CreatePen(PS_SOLID,1,RGB(0,0,0));
myoldPen=pDC->SelectObject(&mypen);
for(int i=0;i<19;i++)
{
pDC->MoveTo(40,40+i*20);
pDC->LineTo(400,40+i*20);
pDC->MoveTo(40+i*20,40);
pDC->LineTo(40+i*20,400);
}
//重画时显示存在的棋子
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
for(int n=0;n<19;n++)
for(int m=0;m<19;m++)
if(wzq[n][m]==1)
{
//显示白棋
Dc.SelectObject(m_bmwhite);
pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
}
else if(wzq[n][m]==-1)
{
//显示黑棋
Dc.SelectObject(m_bmblack);
pDC->BitBlt(n*20+32,m*20+32,160,160,&Dc,0,0,SRCCOPY);
}
}
设置鼠标:
棋盘画好了,接下来就是下棋了。但鼠标并没有像我们上面说的那样变成白棋,加
函数如下:
BOOL CMy3_1View::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: Add your message handler code here and/or call default
if(nHitTest==HTCLIENT)
{
//白棋下,显示白棋鼠标
if(colorwhite)
{
//调用主框架里面的状态栏
CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CStatusBar*pStatus=&pFrm->m_wndStatusBar;
if(pStatus)
{
pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_WHITE));
pStatus->SetPaneText(0,"白棋下");
}
SetCursor(hcursorwhite);
}
//显示黑棋鼠标
else
{
SetCursor(hcursorblack);
CMainFrame*pFrm=(CMainFrame*)AfxGetApp()->m_pMainWnd;
CStatusBar*pStatus=&pFrm->m_wndStatusBar;
if(pStatus)
{
//显示图像
pStatus->GetStatusBarCtrl().SetIcon(0,AfxGetApp()->LoadIcon(IDI_BLACK));
//显示文字
pStatus->SetPaneText(0,"黑棋下");
}
}
return 1;
}
return CView::OnSetCursor(pWnd, nHitTest, message);
}
现在运行程序,怎样,鼠标变成白棋了,而且下面的状态栏也能够显示鼠标状态了,
真是一举两得。可是,又该怎样把棋子放在棋盘上呢?
下棋操作:
这 就 涉 及 到 OnLButtonDown(UINT nFlags, CPoint point) 和 OnLButtonUp(UINT
nFlags, CPoint point)两个函数了。要用哪一个或用两个?用 Down 函数时是在鼠标按下
时放下棋子,可是,要是我们按下后意识到按错了怎么办;那就改用 Up 函数,表示当
鼠标键松开时放下棋子。OK!
添加函数如下:
void CMy3_1View::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC=GetDC();
CDC Dc;
if(Dc.CreateCompatibleDC(pDC)==FALSE)
AfxMessageBox("Can't create DC");
//是否在棋盘内
if(point.x>30&&point.x<410&&point.y>30&&point.y<410)
{
int px=(point.x-30)/20;
int py=(point.y-30)/20;
//是否已经有棋子
if(colorwhite&&wzq[px][py]==0)
{
Dc.SelectObject(m_bmwhite);
pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
//表示存在白棋
wzq[px][py]=1;
//检查是否结束
over(point);
//换黑棋下
colorwhite=false;
{
Dc.SelectObject(m_bmblack);
pDC->BitBlt(px*20+32,py*20+32,160,160,&Dc,0,0,SRCCOPY);
wzq[px][py]=-1;
over(point);
colorwhite=true;
}
}
else if(wzq[px][py]==0)
}
CView::OnLButtonUp(nFlags, point);
}