五子棋判断输赢,大家说一下自己的想法

yudun1989 2011-03-11 04:36:25
今天老师让编程模拟五子棋的程序,
我写了一个但是总觉得比较麻烦,大家都发表一下自己的看法,对于五子棋,如何做判断输赢比较方便,如何写的更精简,如何更省空间?
我写的程序想法这样的:
定义24*24的二维字符数组,但是用的时候只用中间部分的20*20的部分。
就像
**********
**********
**xxxxxx**
**xxxxxx**
**********
**********
每次下了一个棋子之后,遍历棋盘部分的所有已经下了棋的坐标,判断以此棋为中心的线是否形成5子,这样,因为边界多了两层,在每次就不用考虑边界问题。但是这样总觉得太复杂,有什么好的别的方法码?


...全文
971 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
scofiled12 2012-05-22
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]
刚好手里有个五子棋的程序,留邮箱,发给你参考!
[/Quote]


wangmengdi92@gmail.com 同求
lx3275852 2012-05-22
  • 打赏
  • 举报
回复
重新发一下方向

0 1 2
0 1 2
0 1 2
012
3333*4444
567
5 6 7
5 6 7
5 6 7
lx3275852 2012-05-22
  • 打赏
  • 举报
回复

/************全局变量***********/
char nHeiBai; //1:白子 2:黑子 0:停止
char qz[15][15]; //记录棋子
char qx, qy; //最后一颗棋子位置
int nTotle; //剩余空位置个数


/************判断胜利函数***********/
int IsWin()
{
int i, j;
int x, y; //当前判断棋子
int t; //离中心棋子距离
int k = 0; //方向
unsigned char w[8] = { 1, 1, 1, 1 }; //连续棋子个数
int ntq = nHeiBai % 2 + 1; //最后棋子位置,nHeiBai
--nTotle; //棋盘空位置计数(全局变量)
for( i = -1; i < 2; ++i )
for( j = -1; j < 2; ++j )
{
if( i == 0 && j == 0 ) continue;
t = 0;
do
{
if( t++ ) k < 4 ? ++w[k] : ++w[7-k]; //同方向结合
x = qx + j * t;
y = qy + i * t;
if( x < 0 || x > 14 || y < 0 || y > 14 ) break; //判断出界
} while ( qz[y][x] == ntq ); //连续棋子
++k;
}
for( i = 0; i < 4; ++i )
if( w[i] == 5 ) return ntq; //连续5颗棋子胜利
if( nTotle == 0 ) return 3; //棋盘占满则平局
return 0;
}



刚好3月份写过一个,只发了个函数!~

棋盘采用标准棋盘15*15

思路 分 8个方向遍历,直到不是当前落子颜色为止。最后结合为4个方向结合,有一个总计数



方向如下:

0 1 2
0 1 2
0 1 2
012
3333*4444
567
5 6 7
5 6 7
5 6 7


另外补充知识: http://baike.baidu.com/view/7794.htm

本函数只计算了防止长连禁手,暂时没做三三禁手和四四禁手,其实做起来也不难
lx3275852 2012-05-22
  • 打赏
  • 举报
回复

/************全局变量***********/
char nHeiBai; //1:白子 2:黑子 0:停止
char qz[15][15]; //记录棋子
char qx, qy; //最后一颗棋子位置
int nTotle; //剩余空位置个数


/************判断胜利函数***********/
int IsWin()
{
int i, j;
int x, y; //当前判断棋子
int t; //离中心棋子距离
int k = 0; //方向
unsigned char w[8] = { 1, 1, 1, 1 }; //连续棋子个数
int ntq = nHeiBai % 2 + 1; //最后棋子位置,nHeiBai
--nTotle; //棋盘空位置计数(全局变量)
for( i = -1; i < 2; ++i )
for( j = -1; j < 2; ++j )
{
if( i == 0 && j == 0 ) continue;
t = 0;
do
{
if( t++ ) k < 4 ? ++w[k] : ++w[7-k]; //同方向结合
x = qx + j * t;
y = qy + i * t;
if( x < 0 || x > 14 || y < 0 || y > 14 ) break; //判断出界
} while ( qz[y][x] == ntq ); //连续棋子
++k;
}
for( i = 0; i < 4; ++i )
if( w[i] == 5 ) return ntq; //连续5颗棋子胜利
if( nTotle == 0 ) return 3; //棋盘占满则平局
return 0;
}



刚好3月份写过一个,只发了个函数!~

棋盘采用标准棋盘15*15

思路 分 8个方向遍历,直到不是当前落子颜色为止。最后结合为4个方向结合,有一个总计数



方向如下:

0 1 2
0 1 2
0 1 2
012
3333*4444
567
5 6 7
5 6 7
5 6 7


另外补充知识: http://baike.baidu.com/view/7794.htm

本函数只计算了防止长连禁手,暂时没做三三禁手和四四禁手,其实做起来也不难
m825344041 2011-03-12
  • 打赏
  • 举报
回复
好长好长
super_admi 2011-03-12
  • 打赏
  • 举报
回复
发一段未经过测试的,刚写的程序。我看了下别人的五子棋,可能没他们写的好。


#define numb_direct 4
#define board_rows 16
#define board_cols 16
#define chess_over 1
#define chess_change 0

struct coord
{
int y;
int x;
};

int is_over(struct coord curr_coord, int curr_color, int board_data[board_rows][board_cols])
{
struct coord step_direct[numb_direct] = {{0, 1}, {1, 0}, {1, 1}, {1, -1}};
struct coord dest_coord; //搜索目标位置
int i, j, count_chessman;

for(i = 0; i < numb_direct; i++)
{
count_chessman = 1;
for(j = 0; j < 2; j++) //正反搜索方向
{
dest_coord.y = curr_coord.y + step_direct[i].y;
dest_coord.x = curr_coord.x + step_direct[i].x;
while(curr_color == board_data[dest_coord.y][dest_coord.x])
{//建议:棋盘边缘为-2,没有棋子为-1,红色为0,黑色为1
count_chessman++;
if(count_chessman >= 5)return chess_over;
dest_coord.y += step_direct[i].y;
dest_coord.x += step_direct[i].x;
}
step_direct[i].y *= -1;
step_direct[i].x *= -1; //搜索方向反转
}
}

return chess_change;
}
  • 打赏
  • 举报
回复
写几个函数。。每个函数判断一个方向。。。只要碰到不是自己的棋子。。且小于4.就执行下个函数。至到结束。。
qq120848369 2011-03-11
  • 打赏
  • 举报
回复
再简化点,方向步长可以定义为:

dire[4][2][2]; 一共就4个方向,横着,竖着,主对角线,副对角线,比如横着对应步长为:

(dire[0][0][0],dire[0][0][1])是往左的步长,(dirc[0][1][1],dire[0][1][1])是往右的步长,

计算这两个方向上连续的总长度+1,看是否>=5,边界问题楼主的办法没有问题。
qq120848369 2011-03-11
  • 打赏
  • 举报
回复
就8个方向,判断往上走+往下走+1是否>=5,判断往左+往右+1是否>=5,类似这样,写一个函数,接受两个方向步长,这样就可以有通用性了.
super_admi 2011-03-11
  • 打赏
  • 举报
回复
补充:
3.这个补充1稍微有点问题,计数不是清零,而是不变,同时下一个方向为当前方向的反方向。
终于有人回复了,我能修正一下了。
apollofsc2008 2011-03-11
  • 打赏
  • 举报
回复
先建立3个数组,row,column, slash, 分别记录通过改点的横,竖,斜3个方向中最大的连接数。
初始化全是0,当在当前格子下棋子时,就分别找横竖斜三个方向相连的点,好比是说在横的方向上设row[i-1]=a,row[i+1]=b,则该点的值为row[i]=a+b+1,如果row[i]>=5,则判断胜利,否则在横的方向上相连且不为0的格子都赋值为a+b+1。(如果a>0,则row[i-1]=a+b+1,同理b>0时,row[i+1]=a+b+1.此时还要看row[i-2]和row[i+2]是否为0,如果不为0也要赋值为a+b+1).
同理算出竖的方向和斜的方向即可。
还要考虑边界的情况和黑白不同色的情况就可以了

突然来的思路,不知道可行否。只看周围的数就行了,不用每次都累加
如果是八子棋,十子棋,数字越大会不会更好些
super_admi 2011-03-11
  • 打赏
  • 举报
回复
补充:
1.当退回搜索起点时,计数清零。
2.因为步进为1,因此,最好定义的棋盘,比实际棋盘要大1圈。比如实际棋盘是14X14,则定义的棋盘应该是16X16。
super_admi 2011-03-11
  • 打赏
  • 举报
回复
我的建议是:定义八个方向:{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}
每下一个棋子,以此棋子为中心,向八个方向搜索。
当搜索到同色棋子时,继续且计数加1;否则(空,或者不同色),则退回搜索起点,换下一个方向。
如果计数>=5,OK,赢了。
如果方向>8,OK,换Player,继续。
super_admi 2011-03-11
  • 打赏
  • 举报
回复
参考下王小春的《PC游戏编程(人机博弈)》吧。
yudun1989 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 njkido 的回复:]

用斜率试试?
[/Quote]
?额求指教
njkido 2011-03-11
  • 打赏
  • 举报
回复
用斜率试试?
yudun1989 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 xzjxylophone 的回复:]

每次下了一个棋子之后, 以该棋子为中心判定4次(8个方位,4条直线),4个函数.....总共以棋子为中心,分别去4个棋子看是否有(共9个)看是否有5个棋子(包括所下的棋子)是在一起的....就可以判断了
[/Quote]

如何判断连在一起?额,稍微有点没有听懂你的想法。。刚下的棋子在五子连线中的位置不确定,如何正确的遍历到那五个连在一起的?
yudun1989 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 linuxbirdman 的回复:]

边界另作处理
[/Quote]
刚下的棋子有可能属于五子的边界也可能属于五子的中间,你如何正确的判断五子连线?
边界另做判断是不是有点麻烦?
yudun1989 2011-03-11
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 w174504744 的回复:]

刚好手里有个五子棋的程序,留邮箱,发给你参考!
[/Quote]
yudun1989@gmail.com
Ulfsaar 2011-03-11
  • 打赏
  • 举报
回复
Chess[][]是一个二维数组,存储下棋的情况,0为未放子,1、2分别为白字和黑子
主要思想是从刚下的那点的四个方向判断是否有连续五个同颜色的子(当然只用考虑刚下的子的颜色)
m_eWinner 表示胜利的一方

void C_Player::UpdateResult(int x, int y)
{
int nCorrectValue = (m_eCurrPlayer == ePlayer_Black) ? 1 : 2;
//判断上下界
int nTop = y - 4;
int nBottom = y + 4;
int nLeft = x - 4;
int nRight = x + 4;

if (nTop < 0)
{
nTop = 0;
}

if (nLeft < 0)
{
nLeft = 0;
}

if (nBottom >= LineNumber)
{
nBottom = LineNumber-1;
}

if (nRight >= LineNumber)
{
nRight = LineNumber-1;
}

int nMaxLength = 0;
int i,j;
for (i=nLeft; i<= nRight; ++i)
{
if (Chess[i][y] == nCorrectValue)
{
if (++nMaxLength >=5)
{
break;
}
}
else
{
nMaxLength = 0;
}
}

if (nMaxLength >= 5)
{
m_eWinner = m_eCurrPlayer;
return;
}

nMaxLength = 0;
for (i=nTop; i<= nBottom; ++i)
{
if (Chess[x][i] == nCorrectValue)
{
if (++nMaxLength >=5)
{
break;
}
}
else
{
nMaxLength = 0;
}
}

if (nMaxLength >= 5)
{
m_eWinner = m_eCurrPlayer;
return;
}

nMaxLength = 0;
for (i=nLeft, j = nTop; i<= nRight, j<= nBottom; ++i, ++j)
{
if (Chess[i][j] == nCorrectValue)
{
if (++nMaxLength >= 5)
{
break;
}
}
else
{
nMaxLength = 0;
}
}

if (nMaxLength >= 5)
{
m_eWinner = m_eCurrPlayer;
return;
}

nMaxLength = 0;
for (i=nLeft, j = nBottom; i<= nRight, j >= nTop; ++i, --j)
{
if (Chess[i][j] == nCorrectValue)
{
if (++nMaxLength >=5)
{
break;
}
}
else
{
nMaxLength = 0;
}
}

if (nMaxLength >= 5)
{
m_eWinner = m_eCurrPlayer;
return;
}
}
加载更多回复(4)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧