C++语言设计实现五子棋

本文为大家分享了C++五子棋的设计思路和设计实现,供大家参考,具体内容如下

算法思路:

在结束了对C++的学习之后,准备自己编制一些简单的练习程序。目前初步设想是编制一个人机对战的简易五子棋软件。 以下为个人设计思考的过程。

首先,进行问题分析与设计。计划实现的功能为,开局选择人机或双人对战,确定之后比赛开始。比赛结束后初始化棋盘,询问是否继续比赛或退出。后续可加入复盘、悔棋等功能。整个过程中,涉及到了棋子和棋盘两种对象,同时要加上人机对弈时的AI对象,即涉及到三个对象。

棋盘类的设计。

数据存储:五子棋棋盘为15*15的网格结构,即一共有225个节点,每个节点有横竖坐标各一,同时每个节点状态有3种,黑,白,或者为空。可考虑采用二维数组来存储。每个节点三种状态,适合采用枚举(enum)类型。

-* 实现功能*:1. 棋盘对象应负责实时更新棋盘状态并对外显示,因此需要接收棋子对象的输入,同时需要对外输出。而棋盘对象不需要对棋子对象发送信息,所以可以设计棋盘类中更新棋盘状态的函数接收棋子对象作为形参。2. 同时,在每次走棋之后,棋盘对象都要及时更新棋盘信息,即输出棋盘状态。3. 而且,每次走棋之后更新输出之前,应该对棋子走棋是否符合规则以及输赢进行判定。若将规则判定单独封装为一个对象,则不方便调用棋盘信息,故将规则判定设计为棋盘类的成员函数,接收两个形参,一个是棋盘当前的状态,一个是即将走的下一步棋,即一个棋子对象。

设计棋子对象。棋子对象应包含两种信息。一是棋子颜色,二是当前要走的棋子的位置坐标,并保留对外输出的接口。

接下来细化规则判定函数。

  • 首先进行走棋规则判定。接收当前棋子位置信息后,判定该位置是否越界或为空,若非空或者越界,则判定违规,抛掷异常,交付上级调用处理。
  • 然后进行输赢判定。按照一定顺序对当前落子位置的相邻元素进行同色判定并计数。当发现某条直线上同色棋子超过四枚,则判定当前走棋方获胜 。判定过程中同样需要注意是否越界。若均未构成五星连珠,则进入平局判定。
  • 平局判定,遍历棋盘,统计空位,若空位为0,即棋盘已满,判定为平局。

接下来设计下棋AI。设计为一个棋子类型的函数,即接收当前棋盘状态和对方最后一次落棋,返回棋子对象类型。

对弈算法设计。

  • 首先进行先后手判定:若棋盘为空则直接落子(8,8),正中开局。
  • 然后进行防守判定:针对对方上次落棋进行活棋检测,在横、竖、左斜、右斜四条直线上依次进行检测。在任意方向检测到四或活三,即可进行 封堵操作,给出所有可行的封堵位置。若未检测到四或活三,则统计活二并给出所有可能的封堵位置。然后针对所有可能的封堵位置进行评分,选取分数最高的位置进行落子。若上述检测均未找到防守点,则转入进攻算法。
  • 进攻算法:采用枚举,即暴力破解的方法。遍历整个棋盘的所有空位,并给出每个空位的评分,选取最高分进行落子。
  • 活棋检测算法:给定参照棋子,在四个方向上分别检测。以横向检测为例,设参照棋子坐标为(x,y),设定同色计数器count=1(计算同色棋子数目),设定封锁端统计量lock=0,设定已判断的方向统计judge=0。对x-1,判断节点状态,若同色计数器加1,继续判断x-2;若异色,则lock+1,judge+1,若judge=2,终止判断,若judge<2,反向判断x+1;若空白,judge+1,若judge=2,终止判断,若judge<2,反向判断。最后得到被封堵的端口数lock和同色数count。若lock=0,count=3或2,判定为活3或活2。若lock=1,count=4,判定为4,若lock=1,count=3,判定为半3。但是在这种算法中,关于空白的判定存在着一些问题。用0代表空白,用+代表同色,-代表异色,则当出现下列情况时:-0++0-,-+++0-,事实上是死棋,而+0++0,+0+++-,实际上相当于活3或半4。为此,需要对活2和半3的情况进行进一步筛选,即空白端应保证连续两个空白。在活棋检测过程中,如果遇到活3或者半4,则立即终止检测,返回落子的可能位置。若没有则记录活2半3的防守位置,换方向检测。最后返回一个棋子类的数组,包含所有建议的落子位置。若均无,则遍历棋盘,统计所有空白位置,返回。
  • 落子位置评分算法:对活棋检测返回数组中的每个位置进行评分,即以该点为己方参照点,进行活棋检测,若有count=5,直接返回该落子位置。有活三或者半4,分数加20,有活2,分数加5,对角线有相邻同色,分数+2,有异色,分数-2,横竖有同色,分数+1,有异色,分数-1。最后排序,取最高分对应的落子,返回该落子。

接下来则是数据结构和对象设计及主函数调用实现:

类及类的实现

#define RENJU_H

#include <iostream>

#include <windows.h>

#include <string>

#define hor 7

#define ver 4

using namespace std;

//用于记录坐标

struct position

{

int x;

int y;

position()

{

x = 0;

y = 0;

}

position(int a,int b)

{

x = a;

y = b;

}

};

//用于记录棋子颜色和节点状态

enum state

{

blank=0,black=1,white=2

};

//用于存储棋局分析信息:未完赛,犯规,平局,黑方胜,白方胜

enum result

{

go_on,error,draw,black_win,white_win

};

// 设置光标

void setpos(COORD a)

{

HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);

SetConsoleCursorPosition(out, a);

}

// 设置光标

void setpos(int i, int j)

{

COORD pos = { i, j };

setpos(pos);

}

//绘图函数,用于在指定坐标输出指定字符

inline void gps(int x,int y,char c)

{

setpos(y,x);

cout<<c;

}

//绘图函数,用于在指定坐标输出整数

inline void gps(int x,int y,int i)

{

setpos(y,x);

if(i>=10)

cout<<i;

else

cout<<0<<i;

}

//绘图函数,用于在指定坐标输出字符串

inline void gps(int x,int y,string s)

{

setpos(y,x);

cout<<s;

}

//绘图函数,用于在给定坐标打印棋盘中的一格

void tab(int x,int y,state str)

{

string s;

switch (str)

{

case blank:

s=" ";

break;

case black:

s="黑";

break;

case white:

s="白";

break;

default:

break;

}

setpos(y,x);

cout<<" ------ ";

setpos(y,x+1);

cout<<"| |";

setpos(y,x+2);

cout<<"| "<<s<<" |";

setpos(y,x+3);

cout<<"| |";

setpos(y,x+4);

cout<<" ------ ";

}

//查找最大值

int MAX(const int *a,int n)

{

int max = a[0];

for(int i =1; i < n ;i++)

{

if(a[i] > max)

max = a[i];

}

return max;

}

//检测是否符合胜利条件

//棋子类

class chess

{

public:

inline chess(int x=0,int y=0,state c=blank)

{ point.x=x,point.y=y;

color=c;

};

inline chess(chess &ch)

{ point=ch.drop_point();

color=ch.get_color();

}

~chess(){};

struct position drop_point()const;//用于向外部提供棋子位置

inline state get_color() const { return color;}//提供棋子颜色信息

void set_point();//用于从外部获取棋子位置

void set_point(int x,int y){ point.x=x,point.y=y;}

void set_point(position p){ point.x=p.x,point.y=p.y;}

void set_color(state c){ color=c;}//设置棋子颜色

private:

position point;

enum state color;

};

position chess::drop_point()const

{

return point;

}

void chess::set_point()

{

if(color==black)

{

setpos(110,1);

cout<<"请黑方输入落子列数和行数,空格隔开:";

cin>>point.x>>point.y;

while(point.x<1||point.x>15)

{

setpos(110,1);

cout<<"列数输入超出范围,请重新输入1~15之间数字 ";

cin>>point.x;

}

while(point.y<1||point.y>15)

{

setpos(110,2);

cout<<"行数输入超出范围,请重新输入1~15之间数字 ";

cin>>point.y;

}

}

else if(color==white)

{

setpos(110,1);

cout<<"请白方输入落子列数和行数,空格隔开:";

cin>>point.x>>point.y;

while(point.x<1||point.x>15)

{

setpos(110,1);

cout<<"列数输入超出范围,请重新输入1~15之间数字 ";

cin>>point.x;

}

while(point.y<1||point.y>15)

{

setpos(110,2);

cout<<"行数输入超出范围,请重新输入1~15之间数字 ";

cin>>point.y;

}

}

point.x--;

point.y--;

}

//棋盘类

class chessboard

{

public:

chessboard()

{

for(int i=0;i<15;i++)

for(int j=0;j<15;j++)

{

square[i][j]=blank;

}

}

chessboard(chessboard *cb)

{

for(int i=0;i<15;i++)

for(int j=0;j<15;j++)

{

square[i][j]=cb->viewboard(i,j);

}

}

inline state viewboard(position p_c) const;//接收坐标,返回该位置的状态

inline state viewboard(int x,int y) const;//接收整数坐标,返回该位置的状态

void update(chess ch);//接收新棋子,更新棋盘状态

void display()const;//向外输出棋盘状态

result judge(chess ch)const;//规则函数,判断走棋是否犯规和输赢

void clear()//清空棋盘

{

for(int i=0;i<15;i++)

for(int j=0;j<15;j++)

{

square[i][j]=blank;

}

}

private:

state square[15][15];

};

int check_five(chessboard bd,chess ch)

{

position ori=ch.drop_point();

int count=1;//计数器,统计同色个数

int sum[4]={0};

bool locked=0;//逻辑标记量,用来标记是否遇到了非同色节点

//水平方向检测

for(int i=0,locked=0;i<5&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x-i,ori.y))

count++;

else

if(i!=0)

locked=1;

//sum[0]=count-1;

for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x+i,ori.y))

count++;

else

if(i!=0)

locked=1;

//sum[1]=count-sum[0]-2;

sum[0]=count;

if(count>=5)

return count;

//竖直方向检测

count=1;

for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x,ori.y-i))

count++;

else

if(i!=0)

locked=1;

//sum[2]=count-1;

for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x,ori.y+i))

count++;

else

if(i!=0)

locked=1;

//sum[3]=count-sum[2]-2;

sum[1]=count;

if(count>=5)

return count;

//左上到右下斜向检测

count=1;

for(int i=0,locked=0;i<5&&((ori.y-i)>=0)&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x-i,ori.y-i))

count++;

else

if(i!=0)

locked=1;

//sum[4]=count-1;

for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y+i)<=14)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x+i,ori.y+i))

count++;

else

if(i!=0)

locked=1;

//sum[5]=count-sum[4]-2;

sum[2]=count;

if(count>=5)

return count;

//左下到右上斜向检测

count=1;

for(int i=0,locked=0;i<5&&((ori.y+i)<=14)&&((ori.x-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x-i,ori.y+i))

count++;

else

if(i!=0)

locked=1;

//sum[6]=count-1;

for(int i=0,locked=0;i<5&&((ori.x+i)<=14)&&((ori.y-i)>=0)&&(!locked);i++)//终止循环条件:同色超过4个或触碰到棋盘边界或遇到非同色节点

if(ch.get_color()==bd.viewboard(ori.x+i,ori.y-i))

count++;

else

if(i!=0)

locked=1;

//sum[7]=count-sum[6]-2;

sum[3]=count;

if(count>=5)

return count;

return MAX(sum,4);

}

state chessboard::viewboard(position p_c) const

{

return square[p_c.x][p_c.y];

}

state chessboard::viewboard(int x,int y) const

{

return square[x][y];

}

void chessboard::update(chess ch)

{

position pos=ch.drop_point();

square[pos.x][pos.y]=ch.get_color();

}

void chessboard::display()const

{

system("cls");

for(int i=0;i<15;i++)//打印列坐标说明

{

gps(0,6+i*hor,i+1);

}

for(int i=0;i<15;i++)//打印列坐标说明

{

gps(16*ver,6+i*hor,i+1);

}

for(int i=0;i<15;i++)//打印行坐标说明

{

gps(3+i*ver,1,i+1);

}

for(int i=0;i<15;i++)//打印行坐标说明

{

gps(3+i*ver,1+16*hor,i+1);

}

for(int i=0,j=0;i<15;i++)

{

for(j=0;j<15;j++)

tab(1+i*ver,3+hor*j,square[j][i]);

}

cout<<endl;

}

result chessboard::judge(chess set)const

{

bool full=1;

if(viewboard(set.drop_point())!=blank)

{

return error;

}

if(check_five(*this,set)>=5&&(set.get_color()==black))

return black_win;

if(check_five(*this,set)>=5&&(set.get_color()==white))

return white_win;

for(int i=0;i<15;i++)

for(int j=0;j<15;j++)

{

if(square[i][j]==blank)

full=0;

}

if(full==1)

return draw;

else

return go_on;

}

#endif

主函数,应该再定义game类进行优化,不过设计的时候没有考虑周全,还是按照C的思想写了。

#include "ai.h"

#include <stdlib.h>

int main()

{

system("mode con cols=150 lines=150 ");

system("color 27");

chessboard bd;

chess now;

result final;

int mode;

gps(5,40,"==============欢迎使用简易五子棋!==============");

gps(10,50,">>>>输入1或2进行模式选择<<<<");

gps(11,50," <1> 双人对战 ");

gps(12,50," <2> 人机对战 ");

do{

cout<<endl<<" input mode:";

cin>>mode;

}while(mode != 1 && mode != 2);

//双人对战

if (mode==1)

{

loop1: now.set_color(black);//执黑先行

bd.clear();

bd.display(); //初始化棋盘

setpos(110,0);

cout<<"对局开始,黑旗先行";

//循环判断上一次落子结果,收集下一次输入,直到棋局出结果

do{

now.set_point();//输入

final=bd.judge(now);

//判断是否违规

while(final==error)//犯规输入则重新输入

{

system("cls");

bd.display();

setpos(110,10);

cout<<"犯规(输入坐标已有棋子)!";

now.set_point();

final=bd.judge(now);

}

//正确落子后更新棋盘

bd.update(now);

bd.display();

//反转下一步走棋的颜色

if(now.get_color()==black)

now.set_color(white);

else

now.set_color(black);

}while(final==go_on);

switch (final)

{

case go_on:

break;

case error:

break;

case draw:

setpos(110,10);

cout<<"平局:游戏结束";

break;

case black_win:

setpos(110,10);

cout<<"黑旗获胜:游戏结束";

break;

case white_win:

setpos(110,10);

cout<<"白旗获胜:游戏结束";

break;

default:

break;

}

setpos(110,11);

cout<<"是否继续下一局?Y/N";

char flag;

cin>>flag;

if(flag == 'Y')

goto loop1;

}

if(mode == 2)

{

chess ai_ch;

system("cls");

gps(5,40,"==============欢迎使用简易五子棋!==============");

gps(10,50,">>>>输入1或2进行模式选择<<<<");

gps(11,50," <1> 执黑先行 ");

gps(12,50," <2> 执白后行 ");

do{

cout<<endl<<" input mode:";

cin>>mode;

}while(mode != 1 && mode != 2);

if(mode == 1)

{

loop2: now.set_color(black);//执黑先行

bd.clear();

bd.display(); //初始化棋盘

Ai afago(bd,white);

setpos(110,0);

cout<<"对局开始,请您落子";

now.set_point();

bd.update(now);

ai_ch.set_color(white);

ai_ch.set_point(left(now.drop_point(),false));

bd.update(ai_ch);

bd.display();

//循环判断上一次落子结果,收集下一次输入,直到棋局出结果

do{

now.set_point();//输入

final=bd.judge(now);

//判断是否违规

while(final==error)//犯规输入则重新输入

{

system("cls");

bd.display();

setpos(110,10);

cout<<"犯规(输入坐标已有棋子)!";

now.set_point();

final=bd.judge(now);

}

//正确落子后更新棋盘

bd.update(now);

if(final != black_win)

{

ai_ch=afago.set_chess();

final=bd.judge(ai_ch);

bd.update(ai_ch);

bd.display();

}else{bd.display();}

}while(final==go_on);

switch (final)

{

case go_on:

break;

case error:

break;

case draw:

setpos(110,10);

cout<<"平局:游戏结束";

break;

case black_win:

setpos(110,10);

cout<<"恭喜您棋艺高超,战胜了AI:游戏结束";

break;

case white_win:

setpos(110,10);

cout<<"电脑获胜,请继续努力提高自己:游戏结束";

break;

default:

break;

}

setpos(110,11);

cout<<"是否继续下一局?Y/N";

char flag;

cin>>flag;

if(flag=='Y')

goto loop2;

}

if(mode == 2)

{

loop3: ai_ch.set_color(black);//AI执黑先行

now.set_color(white);

bd.clear(); //初始化棋盘

Ai afago(bd,black);

ai_ch.set_point(7,7);

bd.update(ai_ch);

bd.display();

setpos(110,0);

cout<<"对局开始,请您落子";

//循环判断上一次落子结果,收集下一次输入,直到棋局出结果

do{

now.set_point();//输入

final=bd.judge(now);

//判断是否违规

while(final==error)//犯规输入则重新输入

{

system("cls");

bd.display();

setpos(110,10);

cout<<"犯规(输入坐标已有棋子)!";

now.set_point();

final=bd.judge(now);

}

//正确落子后更新棋盘

bd.update(now);

if(final != white_win)

{

ai_ch=afago.set_chess();

final=bd.judge(ai_ch);

bd.update(ai_ch);

bd.display();

}else{bd.display();}

}while(final==go_on);

switch (final)

{

case go_on:

break;

case error:

break;

case draw:

setpos(110,10);

cout<<"平局:游戏结束";

break;

case white_win:

setpos(110,10);

cout<<"恭喜您棋艺高超,战胜了AI:游戏结束";

break;

case black_win:

setpos(110,10);

cout<<"电脑获胜,请继续努力提高自己:游戏结束";

break;

default:

break;

}

setpos(110,11);

cout<<"是否继续下一局?Y/N";

char flag;

cin>>flag;

if(flag=='Y')

goto loop3;

}

}

return 0;

}

更多有趣的经典小游戏实现专题,分享给大家:

C++经典小游戏汇总

python经典小游戏汇总

python俄罗斯方块游戏集合

JavaScript经典游戏 玩不停

java经典小游戏汇总

javascript经典小游戏汇总

以上是 C++语言设计实现五子棋 的全部内容, 来源链接: utcz.com/z/342200.html

回到顶部