黑白棋课程设计
绝世美人儿
832次浏览
2021年01月18日 14:41
最佳经验
本文由作者推荐
扇贝怎么清洗-草地夜行
中南林业科技大学
本科课程设计说明书
学生姓名:
杨明
学
号:
20134380
学
院:
理学院
专业年级:
2013
级信息与计算科学
课
程:
visual c++
面向对象与可视化程序设计
设计
(
论文
)
题目:
黑白棋
指导教师:
刘晖
2015
年
11
月
中
文
摘
要
黑白棋,也称反棋
(Rev ersi)
、奥赛罗棋
(Othello)
,苹果棋,翻转棋
是一个经典的策
略性游戏。
黑白棋是
19
世纪末英国人发明的。
直到上个世纪
70
年代一个日本人将其
发展,借用莎士比亚名剧奥赛罗
(Othello)
为这个游戏重新命名,也就是现在大家玩
的黑白棋。为何借用莎士比亚名剧呢?是因为奥赛罗是莎士比 亚一个名剧的男主角。
他是一个黑人,妻子是白人,因受小人挑拨,怀疑妻子不忠一直情海翻波,最终亲 手
把妻子杀死。后来真相大白,奥赛罗懊悔不已,自杀而死。黑白棋就是借用这个黑人
白人斗争 的故事而命名。
关键词
程序设计,
MFC
,
VC++
与面向对象,
引言
游戏通过相互翻转对方的棋子,最 后以棋盘上谁的棋子多来判断胜负。它的游戏
规则简单,因此上手很容易,但是它的变化又非常复杂。起 初,黑白棋在西方和日本
很流行,近年来,黑白棋正逐步为中国玩家所接受,并深受喜爱。
1
、
课程设计计划
黑白棋游戏设计所完成的 就是一个游戏软件系统。
我以前下过黑白棋,
对其有一定的
了解,但只是一个初级玩家 。要完成游戏的设计,首先要对黑白棋进行全面的了解,
然后进行需求分析,
对软件有一个总体 的设计,
之后进行详细设计,
并对各种细节及
可能的问题进行分析,最后进行编码调试 。
具体步骤如下:
第一步:查询黑白棋的下棋规则及其历史。
第二步:对于如何赢棋及下棋策略进行一定的了解。
第三步:
对于黑白棋游 戏软件的功能需求进行全面的分析,
其包括:
基本功能的需求
及拓展空能的需求。
第四步:进行总体的框架设计。
第五步:
对于总体设计中的各个子模 块,
进行详细设计,
并对可能出现的问题及难以
解决的地方进行标记,同时可查阅相关 的资料进行初步解决。
第六步:上机编码调试,对出现的问题有针对性的加以解决。不能自行 解决的问题,
查询相关资料或询问其他人
以上是总体的课程设计计划,具体的时间或问题的出现与解决以具体情而定。
对于可能出现的问题,如果有提前的预案就更好了。后期的调试阶段可能会出
现很 多问题,尽量压缩前一、两步的时间,为后期调试预留更多的时间。对后期调试
完成后不满意或还希望添 加更多功能,可以进行相应的修改。
2
、功能需求
2.1
开发背景
我国是棋文化的发祥地之一,
上古的尧时代,围棋就在我国诞生了!
在随后的几千年
长河里,
我国人民不断以自己的聪明才智创 造出深受人们喜爱的棋类游戏,
像中国象
棋,
五子棋,
军棋等等一直是在民间 很流行的棋类项目。
同时国外的棋类游戏也流传
到中国,比如国际象棋,跳棋等,逐渐在国内盛 行。可以说棋类游戏一直是中国人民
喜闻乐见的一种休闲方式,
由于棋类游戏都是比较注重智力 策略的,
所以从中也可以
折射出我国人民的智慧。
棋类游戏规则简单,对外部要求不高,人们可以随时随地进行对弈。但是,真
正能够精通棋类游 戏的人却不是很多,
主要是棋类游戏具有变化莫测的特点,
人们经
常得在棋局上深思熟 虑才能找到克敌制胜的办法。
因此,
各种棋类游戏都具有开发智
力的效能。
在 休闲中使自己得到真正的长进,
这或许就是其倍受人们青睐的原因所在!
黑白棋游戏,起源于古希腊,在日本和西方国家比较盛行,其独特的游戏规则,
对人类智慧进行 着不断地挑战和激励,
因此人们一直乐此不疲!
加上上世纪后期电脑
的普及,
使黑白棋在全球范围内风靡,
人们通过电脑可以轻松地实现人机对弈或者双
人对弈!
但是,黑白棋在我国开展的比较晚,流行范围还不够广,很多人对它的 规则还
不是很了解。
为了配合国内黑白棋的普及活动,
为广大的人民群众增添一种既能 休闲
又能益智的娱乐形式,使人们得到身心的全面发展,我们开发了这款
PC
版黑白棋 游
戏。
现阶段沉迷于网络游戏或者其他游戏的学生不少,
作为国家即将的建设者和接班
人决不能只是游戏中的高手,
我们只有去磨练自己的思维,
发挥创造性才能担当得起< br>如此重任,
所以我们更希望能将其在学生中加以推广,
让我们学生找到真正适合自己的游戏!
2.
2
基
本
功
能
1
)、实现人人对战与人机对战及难度的控制
2
)、记录双方棋子数
3
)、实现悔棋功能的
4
)、实现重新开始
2.
3
拓展功能及对项目期望能实现的东西
a
对能落子的点提示玩家
b
棋力可调,分初级,中级。
c
玩家遇到疑问,需要帮助时,给予一定的帮助
d
界面色彩友好,给人以良好的视觉冲击。
e
操作方便,容易上手。
3
、总体设计
3.1
系统模块
黑白棋对战
< br>绘
制
棋
盘
与
旗
子
并
显
示< br>
实
现
对
战
实
现
人
机
对
战
及
难
度
选
择
记
录
双
方
旗
子
能
够
悔
棋
能
够
提
供
游
戏
说
明
3.2
游戏业务处理流程图
否
当前位置能否落点
开始
初始化信息
显示游戏面板
玩家点击落子点
能
是
玩家是否无落子
更新数据并显示游
戏面板
换另一
方
下
棋
否
否
统计双方棋子数
游戏是否结束
是
结束
4
、详细设计
4.1
绘制棋盘与旗子并显示模块
(
1
)绘制背景
此模块写在
DrawImage
(
int
image[10][10],CDC
*pDC
)
函数中,
在OnDraw
(
CDC*pDC
)
中调用此函数即可。同时在
O nDraw
(
CDC*pDC
)函数中采用双缓冲技术,避免屏幕闪
烁。
代码如下:
void CMyView::DrawImage(int Image[10][10],CDC *pDC)//
画棋盘(包括棋子与棋
盘线)
{
int m=X+1;
int n=X;
CRect rc; //
添加背景
CBitmap bitmap;
tmap(IDB_BITMAP8);
CBrush brush;
PatternBrush(&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
显示黑棋数目
pDC->TextOut(30,8,buf);
char buf1[100];
sprintf(buf1,
白棋数目
:%3d
显示白棋数目
pDC->TextOut(236,8,buf1);
pDC->SelectObject(pOldFont);
m_Object();
(
3
)绘制棋子
for(int i=0;i
for(int j=0;j
rc1=CRect(30+nSize*i,30+nSi ze*j,30+nSize*(i+1),30+nSize*(j+1));
if(Image[i][j]==1) //Image[i][j]
为
1
绘制黑棋
{
CBitmap bitmap1;
tmap(IDB_BITMAP1);
CBrush brush1;
PatternBrush(&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;
tmap(IDB_BITMAP2);
CBrush brush2;
PatternBrush(&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
绘制刚落子的黑棋
{
}
else if(Image[i ][j]==-11)//Image[i][j]
为
-11
绘制刚落子的白棋
{
}
else if(Image[i][j]==2) //Image[i][j]
为
2
绘制能够落子的点
{
CBitmap bitmap6;
CBitmap bitmap4;
tmap(IDB_BITMAP4);
CBrush brush4;
CBitmap bitmap3;
tmap(IDB_BITMAP3);
CBrush brush3;
PatternBrush(&bitmap3);
CBrush *pOldBrush3 = pDC->SelectObject(&brush3);
pDC->FillRect(rc1,&brush3);
pDC->SelectObject(pOldBrush3);
//
Image[i][j]=1;
PatternBrush(&bitmap4);
CBrush *pOldBrush4 = pDC->SelectObject(&brush4);
pDC->FillRect(rc1,&brush4);
pDC->SelectObject(pOldBrush4);
}
}
tmap(IDB_BITMAP6);
CBrush brush6;
PatternBrush(&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;
tmap(IDB_BITMAP5);
CBrush brush5;
PatternBrush(&bitmap5);
CBrush *pOldBrush6 = pDC->SelectObject(&brush5);
pDC->FillRect(rc1,&brush5);
pDC->SelectObject(pOldBrush6);
(
4
)画棋盘线
此处采用
MoveTo
()与< br>LineTo
()函数,循环画线。
for(i=0;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]
中的每个点扫描,若为空,则向八个方向查
找,
看此点是否能落子,
若能够落子则记录此点的下标,
并记录落子后吃掉对方棋子< br>的位置下标,以便在玩家点击此点时,显示吃掉对方后的棋盘情况。
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
for(int j=0;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
m++;
flag++;
}while((Image[m][n]==mb1| |Image[m][n]==mb2)&&m
Image[i][j]
Image[i][j]
if((Image[m][n]==mw1||Imag e[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;
//
记
录
能
够
吃
掉
对
方
子
的
位
置
}while(b
/////////////
向右搜索
m=i;n=j;flag=0;
do
{
if(n
n++;
flag++;
}while((Image[m][n]= =mb1||Image[m][n]==mb2)&&n
{
record[i][j][i][j]=5; //
记录此点能够落子的点
b=i;d=j;
do
{ d=d+1;
Record[i][j][b][d]=6;
//
记
录
能
够
吃
掉
对
方
子
的
位
置
}while(d
//////////
向上搜索
m=i;n=j;flag=0;
Image[i][j]
do
{
if(m>0)
m--;
flag++;
}while((Image[m][n]==mb1||Ima ge[m][n]==mb2)&&m>0);
if((Image[m][n]==mw1||Im age[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;
//
记
录
能
够
吃
掉
对
方
子
的
位
置
}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)&&fl ag>1)
{
record[i][j][i][j]=5; //
记录此点能够落子的点
b=i;d=j;
do
{ d=d-1;
Record[i][j][b][d]=6;
//
记
录
能
够
吃
掉
对
方
子
的
位
置
Imag e[i][j]
}
//////////////
向左上搜索
m=i;n=j;flag=0;
do{
if(n>0&&m>0)
{n--;m--;}
flag++;
}while(d>n+1);
}while((Image[m][n]==mb1||I mage[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]
}
//////////////
向右下搜索
m=i;n=j;flag=0;
do{
if(n
flag++;
}while(d>n+1&&b>m+1);
}while(( Image[m][n]==mb1||Image[m][n]==mb2)&&m
if((Image[m][n]==m w1||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]
}
//////////////
向左下搜索
m=i;n=j;flag=0;
do{
if(n>0&&m
flag++;
}while(d
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]
}
//////////////
向右上搜索
m=i;n=j;flag=0;
do{
if(n
{m--;n++;}
}while(b
flag++;
}whi le((Image[m][n]==mb1||Image[m][n]==mb2)&&m>0&&n
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;
//
记
录
能
够
吃
掉
对
方
子
的
位
置
Imag e[i][j]
}
}
}
}
}while(b>m+1&&d
6
)人机大战初级代码如下:
void CMyView::Com_VS_Hum()//
人机大战初级
{
int max=-100,maxX=0,maxY=0;
bool value=false;
for(int i=0;i
for(int j=0;j
for(int k=0;k
for(int g=0;g
if(Record[i][j][k][g]==6)
{
MaxNu m[i][j]+=Record[i][j][k][g]/6;//
记录能落子的点
吃掉对 方的棋子数
}
for(i=0;i
for(int j=0;j
if(Value[i][j]==5&&Max Num[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
for(int j=0;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
for(int j=0;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
for(int j=0;j
if(Record[maxX][maxY][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
Pass=FALSE;
res=FindRe source(::AfxGetApp()->m_hInstance,MAKEINTRESOURCE( IDR_PUTST
ONE),
h Sound1=LoadResource(::AfxGetApp()->m_hInstance,res );
}
else
{
if(MessageBox(
没
处走
了
,
继
续
轮
你
走
!
提示
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);
IsFirst_White=!IsFirst_White;
}
for(i=0;i
for(int j=0;j
for(int k=0;k
for(int g=0;g
{Record[i][j][k][g]=0;MaxNum[i][j]=0;}
}
for(i=0;i
for(int j=0;j
if(Image[i][j]==2)
{ Image[i][j]=0;}
Pass=TRUE;
Search_EnablePoint(); //
电脑落子后,显示对手能落子的点
for(i=0;i
for(int j=0;j
for(int k=0;k
for(int g=0;g
{
}
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(p oint.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
for(int j=0;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) //
该白方落子,下白子
{
}
else
{
}
////////////
加按键音
Image[px][py]=11;
IsFirst_White=TRUE;
for(int i=0;i
for(int j=0;j
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=1;}
TurnCom=TRUE;
// CopyImage[i][j]=0;
Image[px][py]=-11;
CopyImage[px][py]=1;
IsFirst_White=FALSE;
for(int i=0;i
for(int j=0;j
if(Record[px][py][i][j]==6)
{CopyImage[i][j]=6;Image[i][j]=-1;}
r es=FindResource(::AfxGetApp()->m_hInstance,MAKEINT RESOURCE(IDR_PUTST
ONE),
}
else
hSound1=LoadResource(::AfxGetApp()->m_hInstanc e,res);
lpSound1=(LPSTR)LockResource(hSound1);
sndPlaySound(lpSound1,SND_ASYNC|SND_MEMORY);