黑白棋课程设计

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

中南林业科技大学
本科课程设计说明书
学生姓名:杨明学号:********
学院:理学院
专业年级: 2013级信息与计算科学
课程: visual c++面向对象与可视化程序设计设计(论文)题目:黑白棋
指导教师:**
2015年11月
中文摘要
黑白棋,也称反棋(Reversi)、奥赛罗棋(Othello),苹果棋,翻转棋是一个经典的策略性游戏。

黑白棋是19世纪末英国人发明的。

直到上个世纪70年代一个日本人将其发展,借用莎士比亚名剧奥赛罗(Othello)为这个游戏重新命名,也就是现在大家玩的黑白棋。

为何借用莎士比亚名剧呢?是因为奥赛罗是莎士比亚一个名剧的男主角。

他是一个黑人,妻子是白人,因受小人挑拨,怀疑妻子不忠一直情海翻波,最终亲手把妻子杀死。

后来真相大白,奥赛罗懊悔不已,自杀而死。

黑白棋就是借用这个黑人白人斗争的故事而命名。

关键词程序设计,MFC,VC++与面向对象,
引言
游戏通过相互翻转对方的棋子,最后以棋盘上谁的棋子多来判断胜负。

它的游戏规则简单,因此上手很容易,但是它的变化又非常复杂。

起初,黑白棋在西方和日本很流行,近年来,黑白棋正逐步为中国玩家所接受,并深受喜爱。

1、课程设计计划
黑白棋游戏设计所完成的就是一个游戏软件系统。

我以前下过黑白棋,对其有一定的了解,但只是一个初级玩家。

要完成游戏的设计,首先要对黑白棋进行全面的了解,然后进行需求分析,对软件有一个总体的设计,之后进行详细设计,并对各种细节及可能的问题进行分析,最后进行编码调试。

具体步骤如下:
第一步:查询黑白棋的下棋规则及其历史。

第二步:对于如何赢棋及下棋策略进行一定的了解。

第三步:对于黑白棋游戏软件的功能需求进行全面的分析,其包括:基本功能的需求及拓展空能的需求。

第四步:进行总体的框架设计。

第五步:对于总体设计中的各个子模块,进行详细设计,并对可能出现的问题及难以解决的地方进行标记,同时可查阅相关的资料进行初步解决。

第六步:上机编码调试,对出现的问题有针对性的加以解决。

不能自行解决的问题,查询相关资料或询问其他人
以上是总体的课程设计计划,具体的时间或问题的出现与解决以具体情而定。

对于可能出现的问题,如果有提前的预案就更好了。

后期的调试阶段可能会出现很多问题,尽量压缩前一、两步的时间,为后期调试预留更多的时间。

对后期调试完成后不满意或还希望添加更多功能,可以进行相应的修改。

2、功能需求
2.1开发背景
我国是棋文化的发祥地之一,上古的尧时代,围棋就在我国诞生了!在随后的几千年长河里,我国人民不断以自己的聪明才智创造出深受人们喜爱的棋类游戏,像中国象棋,五子棋,军棋等等一直是在民间很流行的棋类项目。

同时国外的棋类游戏也流传到中国,比如国际象棋,跳棋等,逐渐在国内盛行。

可以说棋类游戏一直是中国人民喜闻乐见的一种休闲方式,由于棋类游戏都是比较注重智力策略的,所以从中也可以折射出我国人民的智慧。

棋类游戏规则简单,对外部要求不高,人们可以随时随地进行对弈。

但是,真正能够精通棋类游戏的人却不是很多,主要是棋类游戏具有变化莫测的特点,人们经常得在棋局上深思熟虑才能找到克敌制胜的办法。

因此,各种棋类游戏都具有开发智力的效能。

在休闲中使自己得到真正的长进,这或许就是其倍受人们青睐的原因所在!
黑白棋游戏,起源于古希腊,在日本和西方国家比较盛行,其独特的游戏规则,对人类智慧进行着不断地挑战和激励,因此人们一直乐此不疲!加上上世纪后期电脑的普及,使黑白棋在全球范围内风靡,人们通过电脑可以轻松地实现人机对弈或者双人对弈!
但是,黑白棋在我国开展的比较晚,流行范围还不够广,很多人对它的规则还不是很了解。

为了配合国内黑白棋的普及活动,为广大的人民群众增添一种既能休闲又能益智的娱乐形式,使人们得到身心的全面发展,我们开发了这款PC版黑白棋游戏。

现阶段沉迷于网络游戏或者其他游戏的学生不少,作为国家即将的建设者和接班人决不能只是游戏中的高手,我们只有去磨练自己的思维,发挥创造性才能担当得起如此重任,所以我们更希望能将其在学生中加以推广,让我们学生找到真正适合自己的游戏!
2.2基本功能
1)、实现人人对战与人机对战及难度的控制
2)、记录双方棋子数
3)、实现悔棋功能的
4)、实现重新开始
2.3拓展功能及对项目期望能实现的东西
a 对能落子的点提示玩家
b 棋力可调,分初级,中级。

c 玩家遇到疑问,需要帮助时,给予一定的帮助
d 界面色彩友好,给人以良好的视觉冲击。

e 操作方便,容易上手。

3、总体设计
3.1系统模块
3.2游戏业务处理流程图
4、详细设计
4.1绘制棋盘与旗子并显示模块
(1)绘制背景
此模块写在DrawImage(int image[10][10],CDC *pDC)函数中,在OnDraw(CDC*pDC)中调用此函数即可。

同时在OnDraw(CDC*pDC)函数中采用双缓冲技术,避免屏幕闪烁。

代码如下:
void CMyView::DrawImage(int Image[10][10],CDC *pDC)//画棋盘(包括棋子与棋盘线)
{
int m=X+1;
int n=X;
CRect rc; //添加背景
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP8);
CBrush brush;
brush.CreatePatternBrush(&bitmap);
CBrush *pOldBrush = pDC->SelectObject(&brush);
GetClientRect(&rc);
pDC->FillRect(rc,&brush);
pDC->SelectObject(pOldBrush);
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
(2)显示黑白棋数目
char buf[100];
sprintf(buf,"黑棋数目:%3d ",BlackNum); //显示黑棋数目
pDC->TextOut(30,8,buf);
char buf1[100];
sprintf(buf1,"白棋数目:%3d ",WhiteNum); //显示白棋数目
pDC->TextOut(236,8,buf1);
pDC->SelectObject(pOldFont);
m_Font.DeleteObject();
(3)绘制棋子
for(int i=0;i<n;i++) //绘制棋子
for(int j=0;j<n;j++)
{
rc1=CRect(30+nSize*i,30+nSize*j,30+nSize*(i+1),30+nSize*(j+1));
if(Image[i][j]==1) //Image[i][j]为1绘制黑棋
{
CBitmap bitmap1;
Bitmap1.LoadBitmap(IDB_BITMAP1);
CBrush brush1;
brush2.CreatePatternBrush(&bitmap1);
CBrush *pOldBrush1 = pDC->SelectObject(&brush1);
pDC->FillRect(rc1,&brush1);
pDC->SelectObject(pOldBrush1);
}
else if(Image[i][j]==-1)//Image[i][j]为-1绘制白棋
{
CBitmap bitmap2;
Bitmap2.LoadBitmap(IDB_BITMAP2);
CBrush brush2;
brush1.CreatePatternBrush(&bitmap2);
CBrush *pOldBrush2 = pDC->SelectObject(&brush2);
//pDC->Ellipse(rc1);
pDC->FillRect(rc1,&brush2);
pDC->SelectObject(pOldBrush2);
}
else if(Image[i][j]==11)//Image[i][j]为11绘制刚落子的黑棋
{
CBitmap bitmap3;
bitmap3.LoadBitmap(IDB_BITMAP3);
CBrush brush3;
brush3.CreatePatternBrush(&bitmap3);
CBrush *pOldBrush3 = pDC->SelectObject(&brush3);
pDC->FillRect(rc1,&brush3);
pDC->SelectObject(pOldBrush3);
// Image[i][j]=1;
}
else if(Image[i][j]==-11)//Image[i][j]为-11绘制刚落子的白棋
{
CBitmap bitmap4;
bitmap4.LoadBitmap(IDB_BITMAP4);
CBrush brush4;
brush4.CreatePatternBrush(&bitmap4);
CBrush *pOldBrush4 = pDC->SelectObject(&brush4);
pDC->FillRect(rc1,&brush4);
pDC->SelectObject(pOldBrush4);
}
else if(Image[i][j]==2) //Image[i][j]为2绘制能够落子的点
{
CBitmap bitmap6;
bitmap6.LoadBitmap(IDB_BITMAP6);
CBrush brush6;
brush6.CreatePatternBrush(&bitmap6);
CBrush *pOldBrush5 = pDC->SelectObject(&brush6);
pDC->FillRect(rc1,&brush6);
pDC->SelectObject(pOldBrush5);
}
else if(Image[i][j]==0) ////Image[i][j]为0绘制刚空白
{
CBitmap bitmap5;
bitmap5.LoadBitmap(IDB_BITMAP5);
CBrush brush5;
brush5.CreatePatternBrush(&bitmap5);
CBrush *pOldBrush6 = pDC->SelectObject(&brush5);
pDC->FillRect(rc1,&brush5);
pDC->SelectObject(pOldBrush6);
}
}
(4)画棋盘线
此处采用MoveTo()与LineTo()函数,循环画线。

for(i=0;i<m;i++)//画棋盘线
{
pDC->MoveTo(30,30+i*30);
pDC->LineTo(m*30,30+i*30);
pDC->MoveTo(30+i*30,30);
pDC->LineTo(30+i*30,m*30);
}
(5)查找能落子的点模块
此模块写在Search_Enable(int image[10][10],BOOL IsFirst_white)函数中。

采用二重循环对二维数组image[10][10]中的每个点扫描,若为空,则向八个方向查找,看此点是否能落子,若能够落子则记录此点的下标,并记录落子后吃掉对方棋子的位置下标,以便在玩家点击此点时,显示吃掉对方后的棋盘情况。

void CMyView::Search_EnablePoint()//搜索能落子的点
{
int m,n,flag,b,d,t=0;
int Border=X-1;
int mw1=0,mw2=0;
int mb1=0,mb2=0;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(IsFirst_White)
{mw1=-1;mw2=-11;mb1=1;mb2=11; }
else
{mw1=1;mw2=11;mb1=-1;mb2=-11;}
if(Image[i][j]==0) //若此处为空格则向八个方向搜索
{
//////////向下搜索
m=i;n=j;flag=0;
do
{
if(m<Border)
m++;
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&m<Border);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点Image[i][j]
b=i;d=j;
do
{ b=b+1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(b<m-1);
}
/////////////向右搜索
m=i;n=j;flag=0;
do
{
if(n<Border)
n++;
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&n<Border);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ d=d+1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(d<n-1);
}
//////////向上搜索
m=i;n=j;flag=0;
do
{
if(m>0)
m--;
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&m>0);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ b=b-1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(b>m+1);
}
///////////// 向左搜索
m=i;n=j;flag=0;
do
{
if(n>0)
n--;
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&n>0);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ d=d-1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(d>n+1);
}
//////////////向左上搜索
m=i;n=j;flag=0;
do{
if(n>0&&m>0)
{n--;m--;}
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&m>0&&n>0);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ b=b-1;d=d-1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(d>n+1&&b>m+1);
}
//////////////向右下搜索
m=i;n=j;flag=0;
do{
if(n<Border&&m<Border)
{m++;n++;}
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&m<Border&&n<Border);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ b=b+1;d=d+1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(d<n-1&&b<m-1);
}
//////////////向左下搜索
m=i;n=j;flag=0;
do{
if(n>0&&m<Border)
{m++;n--;}
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&n>0&&m<Border);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ b=b+1;d=d-1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(b<m-1&&d>n+1);
}
//////////////向右上搜索
m=i;n=j;flag=0;
do{
if(n<Border&&m>0)
{m--;n++;}
flag++;
}while((Image[m][n]==mb1||Image[m][n]==mb2)&&m>0&&n<Border);
if((Image[m][n]==mw1||Image[m][n]==mw2)&&flag>1)
{
record[i][j][i][j]=5; //记录此点能够落子的点
b=i;d=j;
do
{ b=b-1;d=d+1;
Record[i][j][b][d]=6; //记录能够吃掉对方子的位置Image[i][j]
}while(b>m+1&&d<n-1);
}
}
}
}
(6)人机大战初级代码如下:
void CMyView::Com_VS_Hum()//人机大战初级
{
int max=-100,maxX=0,maxY=0;
bool value=false;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record[i][j][k][g]==6)
{
MaxNum[i][j]+=Record[i][j][k][g]/6;//记录能落子的点吃掉对方的棋子数
}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(Value[i][j]==5&&MaxNum[i][j]>0)//若能下在四个角之一就立即落子
{maxX=i;maxY=j;break;value=true;}
if(MaxNum[i][j]>max) //搜索能落子点吃掉对方棋子最多的点下
{
max=MaxNum[i][j];
maxX=i;
maxY=j;
}
if(value)
break;
}
if(Image[maxX][maxY]==2) //若干点能落子子下
{
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(Image[i][j]==-11)
Image[i][j]=-1;
if(Image[i][j]==11)
Image[i][j]=1;
}
if(IsFirst_White) //若电脑执白,则落白子
{
Image[maxX][maxY]=-11;
IsFirst_White=FALSE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[maxX][maxY][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=-1;}
Pass=FALSE;
}
else //若电脑执黑,则落黑子
{
Image[maxX][maxY]=11;
IsFirst_White=TRUE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[maxX][maxY][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
Pass=FALSE;
}
/////////////////加按键音
res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_PUTST ONE),"WAVE");
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
}
else
{
if(MessageBox("没处走了,继续轮你走!","提示",MB_YESNO)==IDYES)
IsFirst_White=!IsFirst_White;
}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record[i][j][k][g]==6)
{Record[i][j][k][g]=0;MaxNum[i][j]=0;}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Image[i][j]==2)
{ Image[i][j]=0;}
Pass=TRUE;
Search_EnablePoint(); //电脑落子后,显示对手能落子的点
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record[i][j][k][g]==5)
{
Image[i][j]=2;
Pass=FALSE;
record[i][j][k][g]=0;
}
Invalidate(FALSE);
IsGameOver();
}
void CMyView::OnHumVsCom()
{
// TODO: Add your command handler code here
Rank=2;
}
void CMyView::OnHumVsHum()
{
// TODO: Add your command handler code here
// if(IsVsCom==TRUE)
// KillTimer(1);
Rank=0;
}
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call defaul
if(!ComShow)
{
if(IsStart) //若开始后点击才能落子
{
if(point.x>30&&point.x<(X+1)*30&&point.y>30&&point.y<(X+1)*30) //鼠标点击是否在指定区域
{
px=(point.x-30)/30; //将点击的点转化为Image的下标
py=(point.y-30)/30;
if(Image[px][py]==2) //若此点能落子,则落子
{
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(Image[i][j]==-11)
Image[i][j]=-1;
if(Image[i][j]==11)
Image[i][j]=1;
CopyImage[i][j]=0;
}
if(IsFirst_White) //该白方落子,下白子
{
// CopyImage[i][j]=0;
Image[px][py]=-11;
CopyImage[px][py]=1;
IsFirst_White=FALSE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=-1;}
}
else
{
Image[px][py]=11;
IsFirst_White=TRUE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
TurnCom=TRUE;
}
////////////加按键音
res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_PUTST ONE),"WAVE");
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
}
else
{
////////////若没有在能落子点点击,叫error音
// IsFirst_White=!IsFirst_White;
res3=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_ERRO R),"WAVE");
hSound4=LoadResource(::AfxGetApp()->m_hInstance,res3);
lpSound4=(LPSTR)LockResource(hSound4);
sndPlaySound(lpSound4,SND_ASYNC|SND_MEMORY);
}
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
{if(Record[i][j][k][g]==6)
Record[i][j][k][g]=0;
}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Image[i][j]==2)
{
Image[i][j]=0;
// Pass=TRUE;
}
Invalidate(FALSE);
}
IsGameOver(); //落子后,判断游戏是否结束
Pass=TRUE;
Search_EnablePoint(); //显示另一方能落子点
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record[i][j][k][g]==5)
{
Image[i][j]=2;
Pass=FALSE;
record[i][j][k][g]=0;
}
}
}
CView::OnLButtonDown(nFlags, point);
}
void CMyView::OnStart() //游戏开始
{
// TODO: Add your command handler code here
BlackNum=WhiteNum=2;
OnRestart();
Search_EnablePoint(); //显示将要下棋方,能够落子的点for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record[i][j][k][g]==5)
{
Image[i][j]=2;
record[i][j][k][g]=0;
Pass=FALSE;
}
IsStart=TRUE;
}
BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) //设置鼠标形状
{
// TODO: Add your message handler code here and/or call default
CPoint point;
::GetCursorPos(&point);
ScreenToClient(&point);
if(IsStart)
if(point.x>30&&point.x<30*(X+1)&&point.y>30&&point.y<30*(X+1))
{
if(IsFirst_White) //该白方下,显示白棋鼠标形状
{
SetCursor(m_White);
}
else //该黑方下,显示黑棋鼠标形状
{
SetCursor(m_Black);
}
return true;
}
else
{ SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
return true;
}
return CView::OnSetCursor(pWnd, nHitTest, message);
}
(7)人机大战中级代码如下:
void CMyView::Com_VS_Hum1()//人机大战(中级)
{
int Max=-10,I=0,J=0;
int Num=0;
int Weight[10][10];
int Depth=8;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
image[i][j]=Image[i][j];//将当期局面复制给image[i][j]
if(Image[i][j]==0||Image[i][j]==2)
Num++;
}
if(Num<9)
Depth=Num;
for(int m=0;m<X;m++)
for(int n=0;n<X;n++)
{
if(image[m][n]==2)
{
image[m][n]=-1;
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record[i][j][k][g]==6)
{image[i][j]=-1;}
Weight[m][n]=MinMax(image,Depth,!IsFirst_White,m,n); //对每个能落子的点求权值(极大极小搜索)
if(Weight[m][n]>Max) //求权值最大的点
{
I=m;J=n;
}
image[m][n]=2;
}
}
if(Image[I][J]==2) //在权值最大的点落子
{
if(IsFirst_White)
{
Image[I][J]=-11;
IsFirst_White=FALSE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[I][J][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=-1;}
Pass=FALSE;
}
else
{
Image[I][J]=11;
IsFirst_White=TRUE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[I][J][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
Pass=FALSE;
}
/////////////////加按键音
res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_PUTST ONE),"WAVE");
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
}
// else
// {
// if(MessageBox("没处走了,继续轮你走!","提示",MB_YESNO)==IDYES)
// IsFirst_White=!IsFirst_White;
// }
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record[i][j][k][g]==6)
{Record[i][j][k][g]=0;MaxNum[i][j]=0;}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Image[i][j]==2)
{ Image[i][j]=0;}
Search_EnablePoint();
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record[i][j][k][g]==5)
{
Image[i][j]=2;
Pass=FALSE;
record[i][j][k][g]=0;
}
Invalidate(FALSE);
IsGameOver();
if(Pass==TRUE)
{
// if(MessageBox("没处走了,继续轮你走!请在棋盘上按左键!","提示",MB_YESNO)==IDYES)
if(IsFirst_White)
IsFirst_White=FALSE;
else
IsFirst_White=FALSE;
Pass=FALSE;
}
Pass=TRUE;
}
void CMyView::PointValue(int image[10][10])//动态改变棋盘值
{
if(image[0][0]==1)
Value[0][1]=Value[1][0]=Value[1][1]=15;
if(image[0][9]==1)
Value[0][8]=Value[1][8]=Value[1][9]=15;
if(image[9][0]==1)
Value[9][1]=Value[8][1]=Value[8][0]=15;
if(image[9][9]==1)
Value[9][8]=Value[8][9]=Value[8][8]=15;
////////////////
if(image[0][0]==-1)
Value1[0][1]=Value1[1][0]=Value1[1][1]=-15;
if(image[0][9]==-1)
Value1[0][8]=Value1[1][8]=Value1[1][9]=-15;
if(image[9][0]==-1)
Value1[9][1]=Value1[8][1]=Value1[8][0]=-15;
if(image[9][9]==-1)
Value1[9][8]=Value1[8][9]=Value1[8][8]=-15;
}
int CMyView::Evaluate(int m,int n,int image[10][10],int IsWhite)//估值函数对叶节点估值
{
int bestvalue;
int num=0,num1=0;
BOOL IS=!IsWhite;
Search_Enable(image,IsWhite);
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record1[i][j][k][g]==5)
{num++;
record1[i][j][k][g]=0;}
PointValue(image);
if(IsWhite)
bestvalue=num+Value[m][n]*4;
else
bestvalue=-num+Value1[m][n]*4;
return bestvalue;
}
int CMyView::MinMax(int image[10][10],int depth,BOOL IsWhite,int m,int n)//极大极小搜索
{
int value,bestvalue;
if(depth<=0) //若为叶节点返回估值
{
return Evaluate(m,n,image,!IsWhite);
}
if(IsWhite)
bestvalue=-10000;
else
bestvalue=10000;
Search_Enable(image,IsWhite);//搜索能落子的点
for(int a=0;a<X;a++)
for(int b=0;b<X;b++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record1[a][b][k][g]==5)//对每个能落子的点落子(此落子在虚拟的棋盘image[10][10]上)
{
record1[a][b][k][g]=0;
if(IsWhite) //电脑下
{
image[a][b]=-1; //此点落子
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record1[i][j][k][g]==6) {image[i][j]=-1;Record1[i][j][k][g]=0;}
value=MinMax(image,depth-1,!IsWhite,m,n);//递归调用MinMax()函数搜索 if(value>bestvalue) //极大点取极大值
bestvalue=value;
}
else//对方下
{
image[a][b]=1;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(Record1[i][j][k][g]==6)
{image[i][j]=1;Record1[i][j][k][g]=0;}
value=MinMax(image,depth-1,!IsWhite,m,n);//递归调用MinMax ()函数搜索
if(value<bestvalue) //极小点取极小值
bestvalue=value;
}
}
return bestvalue;//返回最佳值
}
void CMyView::OnHumVsCom1() //人机对战(中级)
{
// TODO: Add your command handler code here
Rank=1;
}
(8)点击鼠标左键落子模块
此处为人人对战或人机大战中玩家用鼠标点击棋盘,OnLButtonDown()函数相应鼠标左键按下事件,完成落子。

void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call defaul
if(!ComShow)
{
if(IsStart) //若开始后点击才能落子
{
if(point.x>30&&point.x<(X+1)*30&&point.y>30&&point.y<(X+1)*30) //鼠标点击是否在指定区域
{
px=(point.x-30)/30; //将点击的点转化为Image的下标
py=(point.y-30)/30;
if(Image[px][py]==2) //若此点能落子,则落子
{
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(Image[i][j]==-11)
Image[i][j]=-1;
if(Image[i][j]==11)
Image[i][j]=1;
CopyImage[i][j]=0;
}
if(IsFirst_White) //该白方落子,下白子
{
// CopyImage[i][j]=0;
Image[px][py]=-11;
CopyImage[px][py]=1;
IsFirst_White=FALSE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=-1;}
}
else
{
Image[px][py]=11;
IsFirst_White=TRUE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
TurnCom=TRUE;
}
////////////加按键音
res=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_PUTST ONE),"WAVE");
hSound1=LoadResource(::AfxGetApp()->m_hInstance,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
}
else
{
////////////若没有在能落子点点击,叫error音
// IsFirst_White=!IsFirst_White;
res3=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_ERRO R),"WAVE");
hSound4=LoadResource(::AfxGetApp()->m_hInstance,res3);
lpSound4=(LPSTR)LockResource(hSound4);
sndPlaySound(lpSound4,SND_ASYNC|SND_MEMORY);
}
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
{if(Record[i][j][k][g]==6)
Record[i][j][k][g]=0;
}
for(i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Image[i][j]==2)
{
Image[i][j]=0;
// Pass=TRUE;
}
Invalidate(FALSE);
}
IsGameOver(); //落子后,判断游戏是否结束
Pass=TRUE;
Search_EnablePoint(); //显示另一方能落子点
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
for(int k=0;k<X;k++)
for(int g=0;g<X;g++)
if(record[i][j][k][g]==5)
{
Image[i][j]=2;
Pass=FALSE;
record[i][j][k][g]=0;
}
}
}
CView::OnLButtonDown(nFlags, point);
}
(9)悔棋
void CMyView::OnUpdatePreStep(CCmdUI* pCmdUI) //悔棋灰显{
// TODO: Add your command update UI handler code here int blacknum=0,whitenum=0;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
if(Image[i][j]==1||Image[i][j]==11)
blacknum++;
else if(Image[i][j]==-1||Image[i][j]==-11)
whitenum++;
if(blacknum>2||whitenum>2)
pCmdUI->Enable(m_bEnable2);
else
pCmdUI->Enable(m_bEnable1);
}
void CMyView::OnComputerShow()
{
// TODO: Add your command handler code here
ComShow=TRUE;
OnStart();
if(IsStart) //若开始后点击才能落子
{
SetTimer(1,1500,NULL);
}
}
(10)重新初始化
void CMyView::ReInit() //重新初始化(以便再来一局)
{
IsFirst_White=FALSE;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{Image[i][j]=0;CopyImage[i][j]=0;}
int m=X/2;
int n=Y/2;
Image[m-1][n-1]=1;Image[m][n]=1;
Image[m-1][n]=-1;Image[m][n-1]=-1;
for(i=0;i<10;i++)
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
for(int d=0;d<10;d++)
{Record[i][j][k][d]=0;record[i][j][k][d]=0;}
if(Rank==1||Rank==2)
for(i=0;i<10;i++)
for(int j=0;j<10;j++)
MaxNum[i][j]=0;
Invalidate(FALSE);
}
(11)判断游戏是否结束
此模块写在IsGameOver()函数中,黑白棋判断游戏结束为:当棋盘摆满棋子时,哪一方的棋子多,则那一方获胜,棋子一样多为平局,或是中途以防被全部吃掉,则另一方胜。

void CMyView::IsGameOver()//判断游戏是否结束
{
int sum=0,sum1=0,Fullflag=0;
for(int i=0;i<X;i++)
for(int j=0;j<X;j++)
{
if(Image[i][j]==1||Image[i][j]==11)
{sum++;Fullflag++;} //记录黑子个数及总的棋子数
else if(Image[i][j]==-1||Image[i][j]==-11)
{sum1++;Fullflag++;} //记录白子个数及总的棋子数
}
BlackNum=sum;
WhiteNum=sum1;
if(sum>sum1&&Fullflag==X*Y||sum1==0) //黑方胜利
{
Isgameover=TRUE;
res1=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_WIN) ,"WAVE");
hSound2=LoadResource(::AfxGetApp()->m_hInstance,res1);
lpSound2=(LPSTR)LockResource(hSound2);
sndPlaySound(lpSound2,SND_ASYNC|SND_MEMORY);
/////////////////
if(MessageBox("黑方胜!还想来一局吗?","提示",MB_YESNO)==IDYES)
OnStart();
else
exit(0);
}
else if(sum<sum1&&Fullflag==X*Y||sum==0) //白方胜利
{
Isgameover=TRUE;
res2=FindResource(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_LOSE ),"WAVE");
hSound3=LoadResource(::AfxGetApp()->m_hInstance,res2);
lpSound3=(LPSTR)LockResource(hSound3);
sndPlaySound(lpSound3,SND_ASYNC|SND_MEMORY);
if(MessageBox("白方方胜!还想来一局吗?","提示
",MB_YESNO)==IDYES)
OnStart();
else
exit(0);
}
else if(sum==sum1&&Fullflag==X*Y) //平局
{
Isgameover=TRUE;
if(MessageBox("平局!还想来一局吗?","提示",MB_YESNO)==IDYES)
OnStart();
else
exit(0);
}
}
(12)计算机演示
void CMyView::OnTimer(UINT nIDEvent) //计算机演示
{
// TODO: Add your message handler code here and/or call default if(nIDEvent==1)
{
if(!Isgameover)
Com_VS_Hum();
else
{ KillTimer(1);Isgameover=FALSE;ComShow=FALSE;} }
CView::OnTimer(nIDEvent);
}
(13)游戏说明
void CMyView::OnHelp() //游戏说明
{
// TODO: Add your command handler code here
CHelp helpdlg;
helpdlg.DoModal();
}
(14)测试与实现
结论/讨论
软件的优点:界面友好、有良好的视觉感,能实现人机对战、操作简单、有提示音及用鼠标形状提示该哪一方下棋,有游戏说明。

软件的缺点:人机对战中,电脑的智力不高,悔棋只能悔一步,没有游戏保存等功能
参考文献:
1 朱福喜.人工智能基础教程[第二版].北京:清华大学出版社,2011.6.
2 郑莉,董渊,张瑞丰.C++语言程序设计.第3版.北京:清华大学出版.2003
3 钱能.C++程序设计教程.第二版.北京:清华大学出版社.2005
4 郑莉.C++语言程序设计案例教程.第一版.北京:清华大学出版社.2005
5 韦朴,陈泰生. Visual C++通用范例开发金典.北京:电子工业出版社.2008
6 揣锦华.面向对象程序设计与VC++实践.西安电子科技大学出版社,2005
7 张建宏,汤练兵,马德骏.计算机程序设计基础-C语言程序设计.科学出版社,2006
8 陈清华.Visual C++课程设计案例精选与编程指导.东南大学出版社,2004。

相关文档
最新文档