转载请标明是引用于 http://blog.csdn.net/chenyujing1234
前段时间在CSDN的资源里载得五子棋VC的源码,由于忘了链接地址,这里没有标明出处,请作者谅解。
但我也把在VS2005上编译通过且加入清楚的注释的源码放到了下面链接,请下载:
http://www.rayfile.com/zh-cn/files/9ae2f74a-8927-11e1-9e3d-0015c55db73d/
一、界面简介
1、 界面框架设计
整个游戏的界面是建立的单文档的基础上。
很多小游戏不是建立在对话框的基础上,而是在单文档或是自己创建窗口的基础上。
因为它们自动提供了菜单栏和状态栏,方便进行游戏设置和控件。
(1)函数LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
进行处理的,如最大化、最小化、鼠标左键按下
(2) CWuziqiView类的响应消息。
通过它的有如:左键单击、右键单击、右键双击
绘制界面的地方是在
void CWuziqiView::OnDraw(CDC* pDC)
{
}
这里不做介绍,大家可以自行去看.
2、 逻辑类设计
由于五子棋游戏中的角色不多只有白棋子、黑棋子: chess
再加上棋盘: Overall
二、 算法分析
主要的算法集中在OnLButtonDown函数里,下面贴出此段代码:
void CWuziqiView::OnLButtonDown(UINT nFlags, CPoint point)
{
float temp;int com;
int x,y;
CRect rectClient;
GetClientRect(rectClient);
// 精确定位棋子位置 x位置
temp=point.x*15;
temp=temp/rectClient.right;
com=temp;
if(temp - com > 0.5)
x = temp+1;
else
x =temp;
// 精确定位棋子位置 y位置
temp=point.y*15;
temp=temp/rectClient.bottom;
com = temp;
if(temp - com > 0.5)
y = temp + 1;
else
y = temp;
// 没有连接,直接更新数据
if(connect == 0)
{
// 判断是不是所点位置没有放棋子
if(all.allqipan[x][y] == 0)
{
MessageBeep(MB_OK);
if(who == 1) // 此时是黑棋
{
// 黑棋自己做标记
black.keydown(x, y, who);
// 全局棋盘做标记
all.allqipan[x][y] = 1;
// 双四且禁手
if(all.shuangsi(x,y)==1 && whohasjinshou == 1)
{
Invalidate();
resultwin lost;
lost.m_Who.Format("黑棋输!有2种4个棋子一条线!");
lost.DoModal();
OnRuleRestart();
return;
}
// 判断当前的位置是不是五子长连
int win = all.winchanglian(x, y);
if(win == 1) // 刚好有5个棋子颜色一样,则黑棋胜
{
Invalidate();
resultwin win;
win.m_Who.Format("黑棋胜!");
win.DoModal();
OnRuleRestart();
return;
}
if(win == 0 && whohasjinshou==1) // 少于5个棋子颜色一样,且自己是禁手了,黑棋输
{
Invalidate();
resultwin lost;
lost.m_Who.Format("黑棋输!long!");
lost.DoModal();
OnRuleRestart();
return;
}
// 双三且是禁手
if(all.shuangsan(x,y) == 1&& whohasjinshou == 1)
{
Invalidate();
resultwin fail;
fail.m_Who.Format("黑棋输!double 3!");
fail.DoModal();
OnRuleRestart();
return;
}
}
以下是游戏的规则:
//以下是规则判断,双三,双四都使禁手
//活三定义:再下一步成为活四
//活四定义:有多于一种的方法成为五颗
//冲四定义:只有一步能够成为五颗
//同时形成两个以上的活三,冲四,或者长连就是禁手
它们对应的函数如下:
1、判断是不是双冲四
// 判断是不是双冲四
// 冲四定义:只有一步能够成为五颗
// 返回值:
// 1 是双冲四
// 0 不是双冲四
int Overall::shuangsi(int x, int y)
{
int nCountx,nCounty,nColor,nCount,recordx,recordy;
nCount=0;
nColor = allqipan[x][y];
/*=================================横的方向======================================*/
// 横向判断,先向左
for(nCountx = x; allqipan[nCountx][y] == nColor && nCountx>=0; nCountx--);
// 如果下往左边走,边缘的位置上是空的
if(nCountx >= 0 && allqipan[nCountx][y] == 0)
{
// 那么就把此位置填充为当前的颜色,再判断是不是能连五
allqipan[nCountx][y] = nColor;
if(winchanglian(nCountx,y) == 1) // 能够连五
{
// 记录此位置及个数
nCount++;
recordx = nCountx;
recordy = y;
}
// 清除临时填充的棋子
allqipan[nCountx][y] = 0;
}
// 横向判断,向左
for(nCountx=x + 1; allqipan[nCountx][y] == nColor && nCountx<=17; nCountx++);
if(nCountx <= 17 && allqipan[nCountx][y] == 0)
{
allqipan[nCountx][y]=nColor;
if(winchanglian(nCountx, y) == 1)
{
// 跨度不是5
if(nCountx - recordx != 5)
nCount++;
}
allqipan[nCountx][y]=0;
}
recordx = recordy = -50;
/*=================================竖的方向======================================*/
// 竖的,向下
for(nCounty = y; allqipan[x][nCounty] == nColor && nCounty >= 0; nCounty--);
if(nCounty >= 0 && allqipan[x][nCounty] == 0)
{
allqipan[x][nCounty] = nColor;
if(winchanglian(x,nCounty)==1)
{
nCount++;
recordx=x;
recordy=nCounty;
}
allqipan[x][nCounty]=0;
}
// 竖的,向上
for(nCounty = y+1; allqipan[x][nCounty] == nColor&&nCounty<=17;nCounty++);
if(nCounty <= 17 && allqipan[x][nCounty] == 0)
{
allqipan[x][nCounty] = nColor;
if(winchanglian(x,nCounty) == 1)
{
if(nCounty - recordy != 5)
{
nCount++;
}
}
allqipan[x][nCounty] = 0;
}
recordx=recordy=-50;
/*=================================左右的方向======================================*/
// 左右方向,先左
for(nCountx=x, nCounty=y; allqipan[nCountx][nCounty]==nColor && nCountx >= 0 && nCounty>=0; nCountx--,nCounty--);
if(nCounty>=0&&nCountx>=0&&allqipan[nCountx][nCounty]==0)
{
allqipan[nCountx][nCounty]=nColor;
if(winchanglian(nCountx,nCounty)==1)
{
nCount++;
recordx=nCountx;
recordy=nCounty;
}
allqipan[nCountx][nCounty]=0;
}
// 左右方向,再右
for(nCountx=x+1,nCounty=y+1;allqipan[nCountx][nCounty]==nColor&&nCountx<=17&&nCounty<=17;nCountx++,nCounty++);
if(nCounty<=17&&nCountx<=17&&allqipan[nCountx][nCounty]==0)
{
allqipan[nCountx][nCounty]=nColor;
if(winchanglian(nCountx,nCounty)==1)
{
if(nCountx-recordx!=4&&nCounty-recordy!=5)
{
nCount++;
}
}
allqipan[nCountx][nCounty]=0;
}
recordx=recordy=-50;
/*=================================右左的方向======================================*/
// 右左
for(nCountx=x,nCounty=y;allqipan[nCountx][nCounty]==nColor&&nCountx>=0&&nCounty<=17;nCountx--,nCounty++);
if(nCounty>=0&&nCountx<=17&&allqipan[nCountx][nCounty]==0)
{
allqipan[nCountx][nCounty]=nColor;
if(winchanglian(nCountx,nCounty)==1)
{
nCount++;
recordx=nCountx;
recordy=nCounty;
}
allqipan[nCountx][nCounty]=0;
}
for(nCountx=x+1,nCounty=y-1;allqipan[nCountx][nCounty]==nColor&&nCountx<=17&&nCounty<=17;nCountx++,nCounty--);
if(nCounty<=17&&nCountx>=0&&allqipan[nCountx][nCounty]==0)
{
allqipan[nCountx][nCounty]=nColor;
if(winchanglian(nCountx,nCounty)==1)
{
if(nCountx-recordx!=4&&recordy-nCounty!=5)
{
nCount++;
}
}
allqipan[nCountx][nCounty]=0;
}
/*=================================结果======================================*/
// 有两个或两个以上可能产生双四
if(nCount >= 2)
return 1;
else
return 0;
}
2、 判断当前的位置是不是五子长连
// 判断当前的位置是不是五子长连
int Overall::winchanglian(int x, int y)
{
// 判断是不是长连禁手
int nCountx, nCounty, nColor, nCount;
// 当前位置的颜色
nColor = allqipan[x][y];
// 横向方向判断
nCount = 0;
for(nCountx=x; allqipan[nCountx][y]==nColor&&nCountx>=0; nCountx--,nCount++);
for(nCountx=x+1; allqipan[nCountx][y]==nColor&&nCountx<=17; nCountx++,nCount++);
// 达到5个棋子,胜了
if(nCount == 5) return 1;
if(nCount > 5) return 0;
// 纵向方向判断
nCount = 0;
for(nCounty=y;allqipan[x][nCounty]==nColor&&nCounty>=0;nCounty--,nCount++);
for(nCounty=y+1;allqipan[x][nCounty]==nColor&&nCounty<=17;nCounty++,nCount++);
if(nCount==5) return 1;
if(nCount>5) return 0;
// 左右方向判断
nCount = 0;
for(nCountx=x,nCounty=y;allqipan[nCountx][nCounty]==nColor&&nCountx>=0&&nCounty>=0;nCountx--,nCounty--,nCount++);
for(nCountx=x+1,nCounty=y+1;allqipan[nCountx][nCounty]==nColor&&nCountx<=17&&nCounty<=17;nCountx++,nCounty++,nCount++);
if(nCount==5) return 1;
if(nCount>5) return 0;
// 右左方向判断
nCount = 0;
for(nCountx=x,nCounty=y;allqipan[nCountx][nCounty]==nColor&&nCountx>=0&&nCounty>=0;nCountx--,nCounty++,nCount++);
for(nCountx=x+1,nCounty=y-1;allqipan[nCountx][nCounty]==nColor&&nCountx<=17&&nCounty<=17;nCountx++,nCounty--,nCount++);
if(nCount==5) return 1;
if(nCount>5) return 0;
// 小于5个棋子颜色一样
return -1;
}
3、判断是不是双三