算法思路在上一篇[C++之简单五子棋的设计思路](http://blog.csdn.net/black_kyatu/article/details/79293392)中描述的较为清晰了。接下来则是设计数据类型和语言实现部分。
类及类的实现
#ifndef RENJU_H
#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 "renju.h"
#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;
}
AI算法待后续补全