C++ 之 简单的五子棋AI程序
本人是大一新生,寒假无聊,抱着试试看的心态(没有想到可以完成),写了C++的简单五子棋程序,开心。
下面是效果图:
一、首先讲讲大致思路。
五子棋实现的基础:
二维数组是五子棋实现的基础。二维数组就像一个棋盘,其中0等于空格,1等于黑棋,2等于白棋,这里电脑就好比只能理解0和1的仆人,我们通过映射,使得五子棋变成计算机能够处理的0和1,进而计算机知道做我们要它做什么。
举例:5个连成水平线的白棋 ——— 00022222000;但是无论怎么样,我们不是电脑,必须看到真正棋才会下(除非你会下盲棋),所以我们需要一个函数,把二维数组中的数字信息转化为图像信息。我的代码如下:
- void gobang::display(){
- system("cls");
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(i == Y && j == X){
- cout << "╋";
- }
- else if(chessboard[i][j] == ){
- cout << "○";
- }
- else if(chessboard[i][j] == ){
- cout << "●";
- }
- else{
- cout << ". ";
- }
- }
- cout << endl;
- }
- }
这个显示函数是很“自由”的,你完全可以选择更好的显示方法,甚至有颜色什么的(我还不会...)。
五子棋的类的大致浏览:
数据:int chessboard[15][15] //存储棋盘信息
int Y, X //光标,用于玩家选择位置落子
int player, computer //记录玩家和电脑棋子的颜色
point laozi //记录最新落子位置,便于判断是否连成五子(point 是 创建的一个结构体:struct point{int y, x})
最主要函数:void play() //最主要的函数,下面是该函数调用的函数
次要函数:
int selMode() //选择模式
void turnPlayer() //玩家操作
void turnComputer() //电脑操作
bool isEnd() //判断是否连成五子
其他函数
具体代码如下:
- class gobang{
- private:
- int chessboard[][]; //记录棋盘信息
- int player; //玩家棋子
- int computer; //电脑棋子
- int Y, X; //光标位置
- point laozi; //落子位置
- public:
- void play();
- int selMode();
- void turnPlayer();
- void turnComputer();
- bool isEnd();
- protected:
- bool isInBoard(point p);
- void display();
- int score(point p, int who);
- point newPoint(point p, dir d, int lenth);
- };
五子棋的步骤(play函数):选择模式(选择电脑先手/玩家先手+数据初始化),循环(玩家/电脑操作 + 判断是否结束,如果是,说明胜利棋方跳出循环,如果不是,交换棋方)
下面是所需要的代码(除了电脑操作部分,比其他复杂一些,最后说)。
play函数
- void gobang::play(){
- int i = selMode();
- if(i == ){
- computer = ;
- player = ;
- }
- else{
- player = ;
- computer = ;
- }
- int cur = ;
- while(){
- if(cur == player){
- turnPlayer();
- }
- else{
- turnComputer();
- }
- if(isEnd()){
- if(cur == player){
- cout << "Player Win !";
- system("pause");
- break;
- }
- else{
- cout << "Computer Win !";
- system("pause");
- break;
- }
- }
- else{
- cur = (cur == ) ? : ;
- }
- }
- }
选择模式:这个函数包含两个部分,选择 和 数据初始化
- int gobang::selMode(){
- system("cls");
- cout << "*************************************************" << endl;
- cout << "******************0、退出************************" << endl;
- cout << "******************1、电脑先手********************" << endl;
- cout << "******************2、玩家先手********************" << endl;
- cout << "*************************************************" << endl;
- while(){
- int i;
- cin >> i;
- if(i == ){
- exit();
- }
- else if(i == || i == ){
- Y = ;
- X = ;
- for(int j = ; j < ; j ++){
- for(int k = ; k < ; k ++){
- chessboard[j][k] = ;
- }
- }
- display();
- return i;
- }
- else{
- cout << "非法输入,请重新输入!" << endl;
- }
- }
- }
玩家操作:玩家操作我采用光标Y,X可视化(display()) 和 键盘操作的方法(w:上 ,s : 下 , a : 左, d : 右, j : 确定落子)。其中操作函数中都会有laozi这个数据,是方便后面的判断是否结束的
- void gobang::turnPlayer(){
- cout << "turn player" << endl;
- while(){
- char c = getch();
- if(c == 'w'){
- if(Y != ){
- Y --;
- display();
- }
- }
- else if(c == 's'){
- if(Y != ){
- Y ++;
- display();
- }
- }
- else if(c == 'a'){
- if(X != ){
- X --;
- display();
- }
- }
- else if(c == 'd'){
- if(X != ){
- X ++;
- display();
- }
- }
- else if(c == 'j' && chessboard[Y][X] == ){
- laozi.y = Y;
- laozi.x = X;
- chessboard[Y][X] = player;
- display();
- break;
- }
- }
- }
判断是否结束:
- bool gobang::isEnd(){
- for(int i = ; i <= ; i ++){
- dir d;
- int count = ;
- switch(i){
- case :
- d = d1;
- break;
- case :
- d = d2;
- break;
- case :
- d = d3;
- break;
- case :
- d = d4;
- break;
- }
- for(int j = -; j <= ; j ++){
- point p1 = newPoint(laozi, d, j);
- if(isInBoard(p1) && chessboard[p1.y][p1.x] == chessboard[laozi.y][laozi.x]){
- count ++;
- }
- else{
- count = ;
- }
- if(count == ){
- return true;
- }
- }
- }
- return false;
- }
在这个函数里出现了一个新的函数——newpoint(point p, dir d, int lenth),其中point p 为 点的位置, int lenth 为长度, dir d 为单位向量
dir d 讲解 :dir 是创建的一个结构体,用来表示单位向量。它有很大的作用,通过它可以把横竖撇捺4个方向用一个简单的dir d 的 方向变量来处理,大大减少了代码量。代码如下:
- struct dir{
- int dy;
- int dx;
- };
- const dir d1 = {, }; //横
- const dir d2 = {, }; //竖
- const dir d3 = {, -}; //撇
- const dir d4 = {, }; //捺
- point gobang::newPoint (point p, dir d, int lenth){
- point p1 = {p.y + d.dy * lenth, p.x + d.dx * lenth};
- return p1;
- }
二、核心部分(电脑操作)讲解
电脑的下棋就是要找出最佳点。什么是最佳点,最佳点的判断指标是什么?这就需要给每个点打分。
打分的具体方法:
1.在棋盘空位置上预先添加要判断的棋子;
2.选择横竖撇捺中的一个方向(利用dir d);
3.找出与中心点相连的棋子数量,并且利用left[5],right[5]数组存储连子左右两边各4个棋子的颜色情况(可能会遇到边界问题,解决办法:通过 isInBoard(point p) 函数判断棋子是否出边界,如果出边界,则棋子颜色视为反方(opp)棋子存储在数组中,如果没有出边界,则棋子按本来情况存储在数组中。
4.利用连子数量以及连子左右两边各4个棋子的颜色情况来判断棋型,是否为连五,活四(高级/低级),冲死,活三(高级或低级),眠三(高级或低级),活二,低级活二,眠二中的一种。
5.综合四个方向,进行打分:
情况1:能成连5, 给予14分;
情况2:能成活4或者是双死4或者是死4活3,给予13分;
情况3:能成双活3,给予12分;
情况4:能成死3活3(高级),给予11分;
情况5:能成死4,给予10分;
情况6:能成低级死4,给予9分;
情况7:能成单活3,给予8分;
情况8:能成跳活3,给予7分;
情况9:能成双活2,给予6分;
情况10:能成活2,给予5分;
情况11:能成低级活2,给予4分;
情况12:能成死3,给予3分;
情况13:能成死2,给予2分;
情况14:其他情况(nothing),给予1分。
五子棋棋型知识(如果不知道可以看这里):
最常见的基本棋型大体有以下几种:连五,活四,冲四,活三,眠三,活二,眠二。
①连五:顾名思义,五颗同色棋子连在一起,不需要多讲。
图2-1
②活四:有两个连五点(即有两个点可以形成五),图中白点即为连五点。
稍微思考一下就能发现活四出现的时候,如果对方单纯过来防守的话,是已经无法阻止自己连五了。
图2-2
③冲四:有一个连五点,如下面三图,均为冲四棋型。图中白点为连五点。
相对比活四来说,冲四的威胁性就小了很多,因为这个时候,对方只要跟着防守在那个唯一的连五点上,冲四就没法形成连五。
图2-3 图2-4
图2-5
④活三:可以形成活四的三,如下图,代表两种最基本的活三棋型。图中白点为活四点。
活三棋型是我们进攻中最常见的一种,因为活三之后,如果对方不以理会,将可以下一手将活三变成活四,而我们知道活四是已经无法单纯防守住了。所以,当我们面对活三的时候,需要非常谨慎对待。在自己没有更好的进攻手段的情况下,需要对其进行防守,以防止其形成可怕的活四棋型。
图2-6 图2-7
其中图2-7中间跳着一格的活三,也可以叫做跳活三。
⑤眠三:只能够形成冲四的三,如下各图,分别代表最基础的六种眠三形状。图中白点代表冲四点。眠三的棋型与活三的棋型相比,危险系数下降不少,因为眠三棋型即使不去防守,下一手它也只能形成冲四,而对于单纯的冲四棋型,我们知道,是可以防守住的。
图2-8 图2-9
图2-10
2-11 图2-12
图2-13
如上所示,眠三的形状是很丰富的。对于初学者,在下棋过程中,很容易忽略不常见的眠三形状,例如图2-13所示的眠三。
有新手学了活三眠三后,会提出疑问,说活三也可以形成冲四啊,那岂不是也可以叫眠三?
会提出这个问题,说明对眠三定义看得不够仔细:眠三的的定义是,只能够形成冲四的三。而活三可以形成眠三,但也能够形成活四。
此外,在五子棋中,活四棋型比冲四棋型具有更大的优势,所以,我们在既能够形成活四又能够形成冲四时,会选择形成活四。
温馨提示:学会判断一个三到底是活三还是眠三是非常重要的。所以,需要好好体会。
后边禁手判断的时候也会有所应用。
⑥活二:能够形成活三的二,如下图,是三种基本的活二棋型。图中白点为活三点。
活二棋型看起来似乎很无害,因为他下一手棋才能形成活三,等形成活三,我们再防守也不迟。但其实活二棋型是非常重要的,尤其是在开局阶段,我们形成较多的活二棋型的话,当我们将活二变成活三时,才能够令自己的活三绵绵不绝微风里,让对手防不胜防。
图2-14 图2-15
图2-16
⑦眠二:能够形成眠三的二。图中四个为最基本的眠二棋型,细心且喜欢思考的同学会根据眠三介绍中的图2-13找到与下列四个基本眠二棋型都不一样的眠二。图中白点为眠三点。
图2-17 图2-18
图2-19 图2-20
这个部分是网上摘抄,网址:http://game.onegreen.net/wzq/HTML/142336.html
既然我们有了给每个点打分的方法,就该寻找最佳点了,但是这还不够,因为我们知道,下棋一般有两个思考方向,进攻或者防守(如果在给某点打分时放入的棋子为电脑棋子,则为进攻,反之,则为防守)。为什么要把进攻和防守分开考虑呢?为什么不可以把进攻得分和防守得分相加起来呢?我也试过,首先要把每种棋型的得分进行更改,即使这样也往往得不到一个好的结果。我可以通过一个比喻说明这个问题:某个学校举办学科竞赛,有语文和数学两个科目,但是每个班可以选择一名同学参加其中一项比赛,为此,老师对每个同学进行语文和数学测试,测试后,老师有2个方法寻找最佳的学生:1.语文和数学成绩一起考虑(比如相加)来寻找最佳学生;2.分别找出语文和数学成绩最好的两名同学,在比较选择。你们认为那种方法选出的学生比赛取得好成绩的概率更高呢?
通过这个比喻,我们寻找最佳点的方法也就出来,分别求出最佳进攻点,如果有多个最佳进攻点,则选择其中防守得分最高的,对于最佳防守点也如此。然后进一步比较,如果最佳进攻点得发大于等于最佳防守点,则以最佳进攻点为最佳点,反之,最佳防守点为最佳点。
具体代码如下:
void turnComputer()
- void gobang::turnComputer(){
- cout << "turn computer" << endl;
- point best1, best2;
- do{
- srand(time(NULL));
- best1.y = best2.y = rand()%;
- best1.x = best2.x = rand()%;
- }
- while(chessboard[best1.y][best1.x] != );
- int a1 = score(best1, computer), b1 = score(best1, player);
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(chessboard[i][j] != ){
- continue;
- }
- point cur = {i, j};
- int m1 = score(cur, computer);
- int m2 = score(cur, player);
- if(m1 > a1){
- best1 = cur;
- a1 = m1;
- b1 = m2;
- }
- else if(m1 == a1){
- if(m2 > b1){
- best1 = cur;
- b1 = m2;
- }
- }
- }
- }
- int a2 = score(best2, player), b2 = score(best2, computer);
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(chessboard[i][j] != ){
- continue;
- }
- point cur = {i, j};
- int m1 = score(cur, player);
- int m2 = score(cur, computer);
- if(m1 > a2){
- best2 = cur;
- a2 = m1;
- b2 = m2;
- }
- else if(m1 == a2){
- if(m2 > b2){
- best2 = cur;
- b2 = m2;
- }
- }
- }
- }
- if(a1 >= a2){
- laozi = best1;
- }
- else{
- laozi = best2;
- }
- chessboard[laozi.y][laozi.x] = computer;
- display();
- }
void score(point p, int who)
- int gobang::score(point p, int who){
- int win5 = , alive4 = , die4 = , ddie4 = , alive3 = ,
- dalive3 = , die3 = , alive2 = , dalive2 = , die2 = , nothing = ;
- int opp;
- if(who == ){
- opp = ;
- }
- else{
- opp = ;
- }
- for(int i = ; i <= ; i ++){
- dir d;
- switch(i){
- case :
- d = d1;
- break;
- case :
- d = d2;
- break;
- case :
- d = d3;
- break;
- case :
- d = d4;
- break;
- }
- int l = ;
- point le, ri, p1;
- int left[], right[];
- p1 = newPoint(p, d, -);
- le = p;
- while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
- le = p1;
- p1 = newPoint(p1, d, -);
- l ++;
- }
- p1 = newPoint(p, d, );
- ri = p;
- while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
- ri = p1;
- p1 = newPoint(p1, d, );
- l ++;
- }
- for(int j = ; j <= ; j ++){
- p1 = newPoint(le, d, -j);
- if(isInBoard(p1)){
- left[j] = chessboard[p1.y][p1.x];
- }
- else{
- left[j] = opp;
- }
- p1 = newPoint(ri, d, j);
- if(isInBoard(p1)){
- right[j] = chessboard[p1.y][p1.x];
- }
- else{
- right[j] = opp;
- }
- }
- //具体棋型判断
- if(l == ){
- win5 ++;
- }
- else if(l == ){
- if(left[] == && right[] == ){//alive4
- alive4 ++;
- }
- else if(left[] == || right[] == ){//die4
- die4 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who) || (right[] == && right[] == who)){//ddie4
- ddie4 ++;
- }
- else if(left[] == && right[] == && (left[] == || right[] == )){//alive3
- alive3 ++;
- }
- else if((left[] == && left[] == ) || (right[] == && right[] == )){//die3
- die3 ++;
- }
- else if(left[] == && right[] == ){//die3
- die3 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who && left[] == who) &&
- (right[] == && right[] == who && right[] == who)){//die4
- ddie4 ++;
- }
- else if(left[] == && right[] == &&
- ((left[] == who && left[] == ) || (right[] == who && right[] == ))){//dalive3
- dalive3 ++;
- }
- else if((left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == ) &&
- (left[] == who || right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == ) ||
- (left[] == && left[] == && right[] == && right[] == ) ||
- (left[] == && left[] == && left[] == && right[] == )){//alive2
- alive2 ++;
- }
- else if((left[] == && left[] == && left[] == ) ||
- (right[] == && right[] == && right[] == )){//die2
- die2 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who && left[] == who && left[] == who) ||
- (right[] == && right[] == who && right[] == who && right[] == who)){//ddie4
- ddie4 ++;
- }
- else if((left[] == && right[] == ) && ((left[] == who && left[] == who && left[] == ) ||
- (right[] == who && right[] == who && right[] == ))){//dalive3
- dalive3 ++;
- }
- else if((left[] == && right[] == ) &&
- ((left[] == who && left[] == who) || (right[] == who && right[] == who))){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == who) && (left[] == || right[] == )){//dalive2
- dalive2 ++;
- }
- else if((right[] == && left[] == && left[] == && left[] == who) &&
- (right[] == || left[] == )){//dalive2
- dalive2 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == && right[] == who) ||
- (right[] == && left[] == && left[] == && left[] == && left[] == who)){//dalive2
- dalive2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && right[] == && right[] == && left[] == who) ||
- (right[] == && left[] == && left[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && right[] == && left[] == who) ||
- (right[] == && right[] == && left[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- }
- if (win5 >= )
- return ;//赢5
- if (alive4 >= || die4 >= || (die4 >= && alive3 >= ))
- return ;//活4 双死4 死4活3
- if (alive3 >= )
- return ;//双活3
- if (die3 >= && alive3 >= )
- return ;//死3高级活3
- if (die4 >= )
- return ;//高级死4
- if (ddie4 >= )
- return ;//低级死4
- if (alive3 >= )
- return ;//单活3
- if (dalive3 >= )
- return ;//跳活3
- if (alive2 >= )
- return ;//双活2
- if (alive2 >= )
- return ;//活2
- if (dalive2 >= )
- return ;//低级活2
- if (die3 >= )
- return ;//死3
- if (die2 >= )
- return ;//死2
- return ;//没有威胁
- }
三、完整代码
- #include <iostream>
- #include <conio.h>
- #include <ctime>
- #include <cstdlib>
- using namespace std;
- struct point{
- int y;
- int x;
- };
- struct dir{
- int dy;
- int dx;
- };
- const dir d1 = {, };//横
- const dir d2 = {, };//竖
- const dir d3 = {, -};//撇
- const dir d4 = {, };//捺
- class gobang{
- private:
- int chessboard[][];//记录棋盘信息
- int player;//玩家棋子
- int computer;//电脑棋子
- int Y, X;//光标位置
- point laozi;//落子位置
- public:
- void play();
- int selMode();
- void turnPlayer();
- void turnComputer();
- bool isEnd();
- protected:
- bool isInBoard(point p);
- void display();
- int score(point p, int who);
- point newPoint(point p, dir d, int lenth);
- };
- void gobang::play(){
- int i = selMode();
- if(i == ){
- computer = ;
- player = ;
- }
- else{
- player = ;
- computer = ;
- }
- int cur = ;
- while(){
- if(cur == player){
- turnPlayer();
- }
- else{
- turnComputer();
- }
- if(isEnd()){
- if(cur == player){
- cout << "Player Win !";
- system("pause");
- break;
- }
- else{
- cout << "Computer Win !";
- system("pause");
- break;
- }
- }
- else{
- cur = (cur == ) ? : ;
- }
- }
- }
- int gobang::selMode(){
- system("cls");
- cout << "*************************************************" << endl;
- cout << "******************0、退出************************" << endl;
- cout << "******************1、电脑先手********************" << endl;
- cout << "******************2、玩家先手********************" << endl;
- cout << "*************************************************" << endl;
- while(){
- int i;
- cin >> i;
- if(i == ){
- exit();
- }
- else if(i == || i == ){
- Y = ;
- X = ;
- for(int j = ; j < ; j ++){
- for(int k = ; k < ; k ++){
- chessboard[j][k] = ;
- }
- }
- display();
- return i;
- }
- else{
- cout << "非法输入,请重新输入!" << endl;
- }
- }
- }
- void gobang::turnPlayer(){
- cout << "turn player" << endl;
- while(){
- char c = getch();
- if(c == 'w'){
- if(Y != ){
- Y --;
- display();
- }
- }
- else if(c == 's'){
- if(Y != ){
- Y ++;
- display();
- }
- }
- else if(c == 'a'){
- if(X != ){
- X --;
- display();
- }
- }
- else if(c == 'd'){
- if(X != ){
- X ++;
- display();
- }
- }
- else if(c == 'j' && chessboard[Y][X] == ){
- laozi.y = Y;
- laozi.x = X;
- chessboard[Y][X] = player;
- display();
- break;
- }
- }
- }
- void gobang::turnComputer(){
- cout << "turn computer" << endl;
- point best1, best2;
- do{
- srand(time(NULL));
- best1.y = best2.y = rand()%;
- best1.x = best2.x = rand()%;
- }
- while(chessboard[best1.y][best1.x] != );
- int a1 = score(best1, computer), b1 = score(best1, player);
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(chessboard[i][j] != ){
- continue;
- }
- point cur = {i, j};
- int m1 = score(cur, computer);
- int m2 = score(cur, player);
- if(m1 > a1){
- best1 = cur;
- a1 = m1;
- b1 = m2;
- }
- else if(m1 == a1){
- if(m2 > b1){
- best1 = cur;
- b1 = m2;
- }
- }
- }
- }
- int a2 = score(best2, player), b2 = score(best2, computer);
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(chessboard[i][j] != ){
- continue;
- }
- point cur = {i, j};
- int m1 = score(cur, player);
- int m2 = score(cur, computer);
- if(m1 > a2){
- best2 = cur;
- a2 = m1;
- b2 = m2;
- }
- else if(m1 == a2){
- if(m2 > b2){
- best2 = cur;
- b2 = m2;
- }
- }
- }
- }
- if(a1 >= a2){
- laozi = best1;
- }
- else{
- laozi = best2;
- }
- chessboard[laozi.y][laozi.x] = computer;
- display();
- }
- int gobang::score(point p, int who){
- int win5 = , alive4 = , die4 = , ddie4 = , alive3 = ,
- dalive3 = , die3 = , alive2 = , dalive2 = , die2 = , nothing = ;
- int opp;
- if(who == ){
- opp = ;
- }
- else{
- opp = ;
- }
- for(int i = ; i <= ; i ++){
- dir d;
- switch(i){
- case :
- d = d1;
- break;
- case :
- d = d2;
- break;
- case :
- d = d3;
- break;
- case :
- d = d4;
- break;
- }
- int l = ;
- point le, ri, p1;
- int left[], right[];
- p1 = newPoint(p, d, -);
- le = p;
- while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
- le = p1;
- p1 = newPoint(p1, d, -);
- l ++;
- }
- p1 = newPoint(p, d, );
- ri = p;
- while(isInBoard(p1) && chessboard[p1.y][p1.x] == who){
- ri = p1;
- p1 = newPoint(p1, d, );
- l ++;
- }
- for(int j = ; j <= ; j ++){
- p1 = newPoint(le, d, -j);
- if(isInBoard(p1)){
- left[j] = chessboard[p1.y][p1.x];
- }
- else{
- left[j] = opp;
- }
- p1 = newPoint(ri, d, j);
- if(isInBoard(p1)){
- right[j] = chessboard[p1.y][p1.x];
- }
- else{
- right[j] = opp;
- }
- }
- //具体棋型判断
- if(l == ){
- win5 ++;
- }
- else if(l == ){
- if(left[] == && right[] == ){//alive4
- alive4 ++;
- }
- else if(left[] == || right[] == ){//die4
- die4 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who) || (right[] == && right[] == who)){//ddie4
- ddie4 ++;
- }
- else if(left[] == && right[] == && (left[] == || right[] == )){//alive3
- alive3 ++;
- }
- else if((left[] == && left[] == ) || (right[] == && right[] == )){//die3
- die3 ++;
- }
- else if(left[] == && right[] == ){//die3
- die3 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who && left[] == who) &&
- (right[] == && right[] == who && right[] == who)){//die4
- ddie4 ++;
- }
- else if(left[] == && right[] == &&
- ((left[] == who && left[] == ) || (right[] == who && right[] == ))){//dalive3
- dalive3 ++;
- }
- else if((left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == ) &&
- (left[] == who || right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == ) ||
- (left[] == && left[] == && right[] == && right[] == ) ||
- (left[] == && left[] == && left[] == && right[] == )){//alive2
- alive2 ++;
- }
- else if((left[] == && left[] == && left[] == ) ||
- (right[] == && right[] == && right[] == )){//die2
- die2 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- else if(l == ){
- if((left[] == && left[] == who && left[] == who && left[] == who) ||
- (right[] == && right[] == who && right[] == who && right[] == who)){//ddie4
- ddie4 ++;
- }
- else if((left[] == && right[] == ) && ((left[] == who && left[] == who && left[] == ) ||
- (right[] == who && right[] == who && right[] == ))){//dalive3
- dalive3 ++;
- }
- else if((left[] == && right[] == ) &&
- ((left[] == who && left[] == who) || (right[] == who && right[] == who))){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && left[] == && left[] == who && left[] == who) ||
- (right[] == && right[] == && right[] == who && right[] == who)){//die3
- die3 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == who) && (left[] == || right[] == )){//dalive2
- dalive2 ++;
- }
- else if((right[] == && left[] == && left[] == && left[] == who) &&
- (right[] == || left[] == )){//dalive2
- dalive2 ++;
- }
- else if((left[] == && right[] == && right[] == && right[] == && right[] == who) ||
- (right[] == && left[] == && left[] == && left[] == && left[] == who)){//dalive2
- dalive2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && right[] == && right[] == && left[] == who) ||
- (right[] == && left[] == && left[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && right[] == && left[] == who) ||
- (right[] == && right[] == && left[] == && right[] == who)){//die2
- die2 ++;
- }
- else if((left[] == && left[] == && left[] == && left[] == who) ||
- (right[] == && right[] == && right[] == && right[] == who)){//die2
- die2 ++;
- }
- else{//nothing
- nothing ++;
- }
- }
- }
- if (win5 >= )
- return ;//赢5
- if (alive4 >= || die4 >= || (die4 >= && alive3 >= ))
- return ;//活4 双死4 死4活3
- if (alive3 >= )
- return ;//双活3
- if (die3 >= && alive3 >= )
- return ;//死3高级活3
- if (die4 >= )
- return ;//高级死4
- if (ddie4 >= )
- return ;//低级死4
- if (alive3 >= )
- return ;//单活3
- if (dalive3 >= )
- return ;//跳活3
- if (alive2 >= )
- return ;//双活2
- if (alive2 >= )
- return ;//活2
- if (dalive2 >= )
- return ;//低级活2
- if (die3 >= )
- return ;//死3
- if (die2 >= )
- return ;//死2
- return ;//没有威胁
- }
- bool gobang::isEnd(){
- for(int i = ; i <= ; i ++){
- dir d;
- int count = ;
- switch(i){
- case :
- d = d1;
- break;
- case :
- d = d2;
- break;
- case :
- d = d3;
- break;
- case :
- d = d4;
- break;
- }
- for(int j = -; j <= ; j ++){
- point p1 = newPoint(laozi, d, j);
- if(isInBoard(p1) && chessboard[p1.y][p1.x] == chessboard[laozi.y][laozi.x]){
- count ++;
- }
- else{
- count = ;
- }
- if(count == ){
- return true;
- }
- }
- }
- return false;
- }
- bool gobang::isInBoard(point p){
- if(p.y >= && p.y < && p.x >= && p.x < ){
- return true;
- }
- else{
- return false;
- }
- }
- point gobang::newPoint (point p, dir d, int lenth){
- point p1 = {p.y + d.dy * lenth, p.x + d.dx * lenth};
- return p1;
- }
- void gobang::display(){
- system("cls");
- for(int i = ; i < ; i ++){
- for(int j = ; j < ; j ++){
- if(i == Y && j == X){
- cout << "╋";
- }
- else if(chessboard[i][j] == ){
- cout << "○";
- }
- else if(chessboard[i][j] == ){
- cout << "●";
- }
- else{
- cout << ". ";
- }
- }
- cout << endl;
- }
- }
- int main(){
- gobang game;
- game.play();
- return ;
- }
四、写五子棋程序的建议:
1.首先要寻找好的代码,如果是那种完全是代码却一点都没有讲解的还是不要看了,给我帮助的博客有:https://www.cnblogs.com/songdechiu/p/5768999.html https://www.jb51.net/article/105675.htm
2.要先有规划,这就好比新年家里要大扫除,如果不做规划,就不知道从何开始,进行到哪里,做得怎么样。我一开始没有规划,盲目打代码,结果必定的错误百出,而且还难以寻找错误(连自己的代码为什么这样写都糊里糊涂),后来重新开始,先写一个思路图,在打代码,最后检查错误,时间节省了很多。
3.完成之后,不妨教给别人(写博客是个好方法,可是应该没什么人看),在写的过程中,我要思考如何把一些问题讲清楚明白,让不会的人能理解,虽然我只是学到了皮毛,但是在这个过程中对程序的理解又有所提升。
最后、因为我这个五子棋程序很简单,下赢它不难(我不太会五子棋,下不赢5555),我希望自己可以用博弈树在写一个五子棋程序,加油吧!
C++ 之 简单的五子棋AI程序的更多相关文章
- 使用QT creator实现一个五子棋AI包括GUI实现(8K字超详细)
五子棋AI实现 五子棋游戏介绍 五子棋的定义 五子棋是全国智力运动会竞技项目之一,是具有完整信息的.确定性的.轮流行动的.两个游戏者的零和游戏.因此,五子棋是一个博弈问题. 五子棋的玩法 五子棋有两种 ...
- 五子棋AI大战OC实现
Gobang 五子棋AI大战,该项目主要用到MVC框架,用算法搭建AI实现进攻或防守 一.项目介绍 1.地址: github地址:Gobang 2.效果图: 二.思路介绍 大概说下思路,具体看代码实现 ...
- 用c语言实现简单的五子棋
用c语言实现简单的五子棋 这个小游戏是从零开始的实现的,框架灵感来自于小游戏<走迷宫>. 游戏代码配置: 二维数组+简单逻辑+getch读取键盘+windows函数(刷屏,改颜色,改窗口大 ...
- 五子棋AI清月连珠开源
经过差不多两年的业余时间学习和编写,最近把清月连珠的无禁手部分完善得差不多了.这中间进行了很多思考,也有很多错误认识,到现在有一些东西还没有全面掌握,所以想通过开源于大家共同交流. 最近一直发表一些五 ...
- 一个简单的P2P传输程序
写了一个简单的P2P传输程序,在P2P的圈子中传输文件,不过为了简便,这个程序没有真正的传输文件,只是简单的判断一下文件的位置在哪里.这个程序可以处理当有一个peer闪退的情况,在这种情况下,剩下的p ...
- 循序渐进做项目系列(2):最简单的C/S程序——消息异步调用与消息同步调用
上篇博客 循序渐进做项目系列(1):最简单的C/S程序——让服务器来做加法 实现了一个最简单的C/S程序,即让服务器来做加法.当时为了通俗易懂采用了消息异步调用的方式.今天我们要采用消息同步调用的方式 ...
- IOS开发之小实例--使用UIImagePickerController创建一个简单的相机应用程序
前言:本篇博文是本人阅读国外的IOS Programming Tutorial的一篇入门文章的学习过程总结,难度不大,因为是入门.主要是入门UIImagePickerController这个控制器,那 ...
- iOS开发UI篇—简单的浏览器查看程序
iOS开发UI篇—简单的浏览器查看程序 一.程序实现要求 1.要求 2. 界面分析 (1) 需要读取或修改属性的控件需要设置属性 序号标签 图片 图片描述 左边按钮 右边按钮 (2) 需要监听响应事件 ...
- iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序
iOS开发UI篇—使用嵌套模型完成的一个简单汽车图标展示程序 一.plist文件和项目结构图 说明:这是一个嵌套模型的示例 二.代码示例: YYcarsgroup.h文件代码: // // YYcar ...
随机推荐
- HTML5 CSS3专题 诱人的实例 CSS3打造百度贴吧的3D翻牌效果
首先感谢w3cfuns的老师~ 今天给大家带来一个CSS3制作的翻牌效果,就是鼠标移到元素上,感觉可以看到元素背后的信息.大家如果制作考验记忆力的连连看.扑克类的游戏神马的,甚至给女朋友写一些话语,放 ...
- 【转载】JavaScript基础知识体系
前言 最近总是有一种感觉,对于知识没有积淀,很多时候都是忘记了哪里就去查一下,比如JS这种语言,很是浪费时间,如果能够把这些知识形成知识体系塞进大脑,做到即用即取就好了,那么就可以借助思维导图来帮助我 ...
- python中RabbitMQ的使用(安装和简单教程)
1,简介 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现的产品,RabbitMQ是一个消息代理,从"生产者"接收消息 ...
- machine learning 之 Anomaly detection
自Andrew Ng的machine learning课程. 目录: Problem Motivation Gaussian Distribution Algorithm Developing and ...
- j2ee 使用db.properties连接mysql数据库
转自: http://blog.csdn.net/u013815546/article/details/50808493 注: 下面的方法是未安装构架的写法,需要自己加载驱动并建立连接. 若引入了Ac ...
- bzoj 2653 middle 二分答案 主席树判定
判断中位数是否可行需要将当前的解作为分界,大于其的置为1,小于为-1,然后b-c必选,ab,cd可不选,这个用线段树判定就好 但不能每次跑,所以套主席树,按权值排序,构建主席树,更新时将上一个节点改为 ...
- stm32的NVIC是什么?
NVIC的全称是Nested vectoredinterrupt controller,即嵌套向量中断控制器. 对于M3和M4内核的MCU,每个中断的优先级都是用寄存器中的8位来设置的.8位的话 ...
- BZOJ1500 [NOI2005]维修数列-fhq_Treap
题面见这里 反正是道平衡树,就拿 fhq_Treap 写了写... 这道题思路基本是围绕“用 Treap 维护中序遍历” 和 中序遍历的性质 来进行的操作 所以就可以类比线段树进行一些操作 1. 建树 ...
- OpenLayer实现路径运动
近期由于业务的需求,让我这从未想过要碰Web Gis的业余前端开发者,走了Web Gis的开发道路.功能需求很简单,但却也是让自己难为了好几天.如,应该选择那个Gis框架,Gis框架的兼容性如何,直接 ...
- PHP过滤数组中的空值
php对数组的操作已经很完善了,提供给我们很多内置函数用以操作数组,其实可以用array_filter函数对PHP数组中的控制进行过滤 array_filter() 函数用回调函数过滤数组中的值.该函 ...