基于C++实现五子棋AI算法思想

今天我想要分享一下我做五子棋AI的思路。因为在做这个之前,我没有接触过任何像这种类似的东西。通过这一次,我也算是有所了解,我的思路也是来自很多网络上的博客,看了很多,最终总结出了自己的这样一个。

那我的五子棋是15*15的大小(一般也就是这样的一个大小)。我的AI算法要求每一次落子之后都要去计算每一个空暇的位置的“分值”,简单的说,我们需要一个存放棋子的数组,表示是否存放了棋子,还要一个计算每一个空格的数组来记录“分数”,这个分数是后期AI用来运算的基础,也是你AI难度控制的点。

我现有的思路就是分两部分。首先是如果是玩家先落子,那么要求电脑AI随即在你落子的地方的任意一个方向,随机落子,这是第一步。接下来以后就正式进入到算法中去。

首先初始化你的分数数组,让他们全部为零。然后在每一次落子之后进行全盘的遍历,如果发现该处为空白,于是检查其四周八个方向(当然如果是边缘位置就相对修改,判断是否出了边界)。若在空白处,且发现在某一对角线方向发现有一个其他颜色的棋子,那么相对的给这个空白区域的分数数组加上一定的分值,然后继续往这个方向检测是否还有连续的同一颜色的棋子,若没有则检查其他方向或者检测下一个空白位置。若是还在同一方向上面找到了相同颜色的棋子,那么第二个棋子的出现,你可以给改空白处加上双倍的分值,表明这个空白位置更加重要。一次类推,继续检测。(PS:因为最终AI棋子落在什么地方,依靠的是最后遍历整个分数数组,然后根据分数的高低来进行判断落子落在哪里的,在下面讲)。

经过上一遍的遍历,每一次落子都会使得分数数组得到一些变化,每一次都会导致AI判断的变化。在这个基础上,每一次落子还要进行一次对自己本身棋子颜色的一个遍历,判断自己的情况,同时加分加在分数数组之中,这样一来,电脑就会根据自己的棋子的情况以及玩家的落子情况进行判断,哪一个地方更加适合落子。

因为我是第一次做AI,网络上搜到的一些思想一般也是这种类似的遍历思想。理解了以后写代码就比较方便。最后可能会有一些点的分数是相同的,所以还有设置一下随机落子。把分数相同的地点随机落子。

个人感觉AI的强弱是根据你每一次给他增加分数的多少来确定的。这个我的AI有时候也会抽风,不过一般情况比较正常,可能运气也占了一部分,当初设计加分的时候其实没想那么多,现在却发现好像还不错。

大家要多去实践练习,多改改分数可能就会出来不错的AI了,o(^▽^)o。

下面贴上我的代码!

void GameScene::Robot(int *x, int *y, int *Sum)
{
  ExWhile1 = true;
  if (*Sum == 1)
  {
    while (ExWhile1)
    {
      ChessOne(*x, *y);
      if (ch[*x][*y] == 2){ ExWhile1 = false; }
    }
    ch[*x][*y] = tp;   //记录这个点
    printpart(*x, *y, tp);     //打印出电脑AI第一次落子
    isTouch = true;
    tp++;
    tp = tp % 2;
  }
  else      //从第2步开始,使用评分系统
  {
    Findscore(*x, *y);
  }
} 

void GameScene::Findscore(int &x, int &y)   //查找评分最高的坐标
{
  srand((unsigned)time(NULL));
  int i, j, x1, x2, y1, y2, lx;
  int Max = 0;
  ChessScore();      //调用评分函数
  for (i = 0; i<15; i++)
  {
    for (j = 0; j<15; j++)
    {
      if (Score[i][j]>Max)
      {
        Max = Score[i][j];  //获取所有点中,评分最高的
        x1 = i;
        y1 = j;
      }
    }
  }
  x2 = x1; y2 = y1;
  for (i = 0; i<15; i++)    //可能的话,有评分相同的多个点
  {
    for (j = 0; j<15; j++)
    {
      if (Score[i][j] == Max&&i != x2&&j != y2)   //在这么多个相同分数的点中,随机找一个
      {
        lx = rand() % 10;
        if (lx<5)
        {
          x2 = i, y2 = j;
          break;
        }
      }
    }
  }
  if (x2 != x1 || y2 != y1)   //棋盘上有2个最高分
  {
    lx = rand() % 10;    //随机一个
    if (lx>6)
    {
      x = x1, y = y1;
    }
    else
    {
      x = x2, y = y2;
    }
  }
  else    //棋盘上只有一个最高分
  {
    x = x1, y = y1;
  }
  Max = 0;    //清空最大值
  ch[x][y] = tp;       //记录这个点
  printpart(x, y, tp);    //打印出电脑AI落子
  if (winerValue==2)
  {
    isTouch = true;
  } 

  tp++;
  tp = tp % 2;
} 

inline void GameScene::ChessOne(int &x, int &y)   //玩家走第1步时的落子
{
  int i, j;
  srand((unsigned)time(NULL));    //随机数随着时间的改变而改变
  for (i = 0; i<15; i++)
  {
    for (j = 0; j<15; j++)
    {
      if (ch[i][j] == 0)  //如果找到了玩家的棋子,在它的8个方的任意一点落子
      {
        int lx = rand() % 7;
        if (lx == 0)
        {
          x = i + 1; y = j + 1;
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 1)
        {
          x = i + 1; y = j - 1;
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 2)
        {
          x = i - 1; y = j - 1;
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 3)
        {
          x = i - 1; y = j + 1;
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 4)
        {
          x = i - 1; y = j;    //上
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 5)
        {
          x = i; y = j - 1;   //左
          if (ch[x][y] == 2){ break; }
        }
        else if (lx == 6)
        {
          x = i; y = j + 1;   //右
          if (ch[x][y] == 2){ break; }
        }
        else
        {
          x = i + 1; y = j;    //下
          if (ch[x][y] == 2){ break; }
        }
      }
    }
  }
} 

void GameScene::ChessScore()
{
  int x, y, i, j, k;      //循环变量
  int number1 = 0, number2 = 0;   //number用来统计玩家或电脑棋子连成个数
  int empty = 0;    //empty用来统计空点个数
  memset(Score, 0, sizeof(Score));                    //把评分数组先清零
  for (x = 0; x<15; x++)
  {
    for (y = 0; y<15; y++)
    {
      if (ch[x][y] == 2)    //如果这个点为空
      {
        for (i = -1; i <= 1; i++)
        {
          for (j = -1; j <= 1; j++)   //判断8个方向
          {
            if (i != 0 || j != 0)   //若是都为0的话,那不就是原坐标嘛
            {
              //对玩家落点评分
              for (k = 1; i <= 4; k++)   //循环4次
              {                        //这点没越界  且这点存在黑子(玩家)
                if (x + k*i >= 0 && x + k*i <= 14 &&
                  y + k*j >= 0 && y + k*j <= 14 &&
                  ch[x + k*i][y + k*j] == 0)
                {
                  number1++;
                }
                else if (ch[x + k*i][y + k*j] == 2)     //这点是个空点,+1后退出
                {
                  empty++;
                  break;
                }
                else                    //否则是墙或者对方的棋子了
                {
                  break;
                }
              }
              for (k = -1; k >= -4; k--)            //向它的相反方向判断
              {                        //这点没越界  且这点存在黑子(玩家)
                if (x + k*i >= 0 && x + k*i <= 14 &&
                  y + k*j >= 0 && y + k*j <= 14 &&
                  ch[x + k*i][y + k*j] == 0)
                {
                  number1++;
                }
                else if (ch[x + k*i][y + k*j] == 2)     //这点是个空点,+1后退出
                {
                  empty++;
                  break;
                }
                else
                {
                  break;
                }
              }
              if (number2 == 1)   //2个棋子
              {
                Score[x][y] += 1;
              }
              else if (number1 == 2)   //3个棋子
              {
                if (empty == 1)
                {
                  Score[x][y] += 5;   //有一个空点+5分 死3
                }
                else if (empty == 2)
                {
                  Score[x][y] += 10;  //有两个空点+10分 活3
                }
              }
              else if (number1 == 3)   //4个棋子
              {
                if (empty == 1)
                {
                  Score[x][y] += 20;  //有一个空点+20分 死4
                }
                else if (empty == 2)
                {
                  Score[x][y] += 100;  //有2个空点+100分 活4
                }
              }
              else if (number1 >= 4)
              {
                Score[x][y] += 1000;  //对方有5个棋子,分数要高点,先堵
              }   

              empty = 0;   //统计空点个数的变量清零  

              //对电脑落点评分
              for (k = 1; i <= 4; k++)   //循环4次
              {       //这点没越界  且这点存在白子(电脑)
                if (x + k*i >= 0 && x + k*i <= 14 &&
                  y + k*j >= 0 && y + k*j <= 14 &&
                  ch[x + k*i][y + k*j] == 1)
                {
                  number2++;
                }
                else if (ch[x + k*i][y + k*j] == 2)
                {
                  empty++; break;   //空点
                }
                else
                {
                  break;
                }
              }
              for (k = -1; k >= -4; k--)   //向它的相反方向判断
              {
                if (x + k*i >= 0 && x + k*i <= 14 &&
                  y + k*j >= 0 && y + k*j <= 14 &&
                  ch[x + k*i][y + k*j] == 1)
                {
                  number2++;
                }
                else if (ch[x + k*i][y + k*j] == 2)
                {
                  empty++; break;
                }
                else
                {
                  break;   //注释与上面玩家版相同
                }
              }
              if (number2 == 0)
              {
                Score[x][y] += 1;    //1个棋子
              }
              else if (number2 == 1)
              {
                Score[x][y] += 2;    //2个棋子
              }
              else if (number2 == 2)   //3个棋子
              {
                if (empty == 1)
                {
                  Score[x][y] += 8;  //死3
                }
                else if (empty == 2)
                {
                  Score[x][y] += 30;  //活3
                }
              }
              else if (number2 == 3)   //4个棋子
              {
                if (empty == 1)
                {
                  Score[x][y] += 50;   //死4
                }
                else if (empty == 2)
                {
                  Score[x][y] += 200;   //活4
                }
              }
              else if (number2 >= 4)
              {
                Score[x][y] += 10000;   //自己落在这点能形成5个,也就能胜利了,分数最高
              }  

              number1 = 0;     //清零,以便下次重新统计
              number2 = 0;
              empty = 0;
            }
          }
        }
      }
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++简单五子棋的AI设计实现

    本文实例为大家分享了C++五子棋的AI设计实现代码,供大家参考,具体内容如下 设计思路:通过接口获取信息来确定颜色,通过set_chess函数来确定落点. 对每个点位给出两种颜色棋子的打分,分别存在两个15*15的数组里,数组下标代表点的位置. 确定最大值所在数组之后,遍历该数组找出所有最大值对应的位置,然后对这些位置统计另一种颜色的棋子的分数,再选取一次最大值,从而确定要落点的位置. 打分函数的设计:在四个方向分别统计然后相加.对于某一个方向的分数统计,则分为正反两个方向进行,统计的时候如果有

  • C++实现五子棋游戏

    三子棋.五子棋之类的游戏,非常简单,对于初学者来说是一个不错的练手的小项目,以前用C语言写过三子棋游戏.最近在看C++,所以就想到在三子棋的基础上利用C++语言实现五子棋游戏. 主要功能: 有3个模式:0表示退出.1表示电脑vs玩家.2表示玩家vs玩家. 当一局完成之后选择'y'则又会进入选择模式. 源代码(VS2013编译器下写的): #include<iostream> #include<stdio.h> #include<stdlib.h> #include &l

  • C++程序设计-五子棋

    前言:很多刚刚接触编程的人都不知道怎么下手编写程序,特别是学习了新的知识点,不知道有什么用,那么本文将以简单的存储结构及简单的运算,条件语句,分支语句,循环语句结合,带来一个双人对战版五子棋,这是一个简单的模型,实现了五子棋最最基本的功能,还有好多地方需要补全,如边界问题,设计问题,游戏逻辑问题,希望读者阅读后能够注意,通过自己的努力来完善它,还能扩展各种功能,如悔棋,网络对战等,有时候写程序和小生命一样,慢慢会成长,而我们作为"父母"的看到自己的小宝宝成为有用之才,过程之欣喜特别棒!

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

    本文为大家分享了C++五子棋的设计思路和设计实现,供大家参考,具体内容如下 算法思路: 在结束了对C++的学习之后,准备自己编制一些简单的练习程序.目前初步设想是编制一个人机对战的简易五子棋软件. 以下为个人设计思考的过程. 首先,进行问题分析与设计.计划实现的功能为,开局选择人机或双人对战,确定之后比赛开始.比赛结束后初始化棋盘,询问是否继续比赛或退出.后续可加入复盘.悔棋等功能.整个过程中,涉及到了棋子和棋盘两种对象,同时要加上人机对弈时的AI对象,即涉及到三个对象. 棋盘类的设计. 数据存

  • C++实现五子棋小程序

    这是一个用C++写的五子棋的小程序,关于A若是占据了已经下了的位置处理的不好.改动 hight,与width ,与q[][] 可以将棋盘扩大. #include<iostream> #include<vector> using namespace std; class qipan { public: qipan() {} ~qipan() {}; //向上下左右,斜的方向 char left(int x, int y) {//检查是否合适 if (x >= 1 &&a

  • 基于c++ ege图形库实现五子棋游戏

    本文分享的五子棋实例,制作基于ege图像库, 首先需要安装配置ege环境 就可以编写小游戏了. 用到的ege库函数不多 , 主要是基于c++的. 先看界面效果: 输入界面:(就是控制台) 游戏胜利界面: 文档如下: 关于五子棋的构思: 实现人人对战的五子棋游戏.使用面向对象的c++ 和 ege库实现. ege的安装过程不在说明 , 在添加编译链接时去掉 -mwindows 选项. dev c++ 的运行环境设置为 TDM-GCC 4.8.1.32-bit Debug 为保险起见,编译时选择菜单栏

  • C++面向对象实现五子棋小游戏

    尽量将面向对象的思想融入进程序中 ChessBoard.h //ChessBoard.h #pragma once #define ROW 15 #define COL 15 #include<iostream> using namespace std; class ChessBoard//棋盘类 { public: char m_cSquare[ROW][COL]; public: ChessBoard(); void show(); }; ChessBoard.cpp //ChessBoa

  • 基于C++实现五子棋AI算法思想

    今天我想要分享一下我做五子棋AI的思路.因为在做这个之前,我没有接触过任何像这种类似的东西.通过这一次,我也算是有所了解,我的思路也是来自很多网络上的博客,看了很多,最终总结出了自己的这样一个. 那我的五子棋是15*15的大小(一般也就是这样的一个大小).我的AI算法要求每一次落子之后都要去计算每一个空暇的位置的"分值",简单的说,我们需要一个存放棋子的数组,表示是否存放了棋子,还要一个计算每一个空格的数组来记录"分数",这个分数是后期AI用来运算的基础,也是你AI

  • Java实现五子棋AI算法

    五子棋AI算法 也算是一个典型的游戏AI算法,一些棋类的AI算法都可以参考实现,下面是Java实现代码 棋盘抽象接口 import java.util.List; public interface IChessboard { //取得棋盘最大横坐标 public int getMaxX(); //最大纵坐标 public int getMaxY(); //取得当前所有空白点,这些点才可以下棋 public List<Point> getFreePoints(); } 棋子类实现 //棋子类 p

  • AI算法实现五子棋(java)

    本文实例为大家分享了AI算法实现五子棋的具体代码,供大家参考,具体内容如下 首先,实现一个五子棋要有一个棋盘,然后在这个棋盘上我们再来画出图画,五子棋棋盘有固定的行数和列数,再加上界面的大小和菜单栏,这些数据可能很多个类都需要用到,我们可以先考虑自己写一个接口用来存储这些数据: public interface Config { public static final int SIZE=703; //面板大小 public static final int X0=SIZE/19*2-8; pub

  • 算法之排序算法的算法思想和使用场景总结

    1. 概述 排序算法是计算机技术中最基本的算法,许多复杂算法都会用到排序.尽管各种排序算法都已被封装成库函数供程序员使用,但了解排序算法的思想和原理,对于编写高质量的软件,显得非常重要. 本文介绍了常见的排序算法,从算法思想,复杂度和使用场景等方面做了总结. 2. 几个概念 (1)排序稳定:如果两个数相同,对他们进行的排序结果为他们的相对顺序不变.例如A={1,2,1,2,1}这里排序之后是A = {1,1,1,2,2} 稳定就是排序后第一个1就是排序前的第一个1,第二个1就是排序前第二个1,第

  • 深入解析堆排序的算法思想及Java代码的实现演示

    一.基础知识 我们通常所说的堆是指二叉堆,二叉堆又称完全二叉树或者叫近似完全二叉树.二叉堆又分为最大堆和最小堆. 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.数组可以根据索引直接获取元素,时间复杂度为O(1),也就是常量,因此对于取值效率极高. 最大堆的特性如下: 父结点的键值总是大于或者等于任何一个子节点的键值 每个结点的左子树和右子树都是一个最大堆 最小堆的特性如下: 父结点的键值总是小于或者等于任何一个

  • 基于JVM 中常见垃圾收集算法介绍

    JVM 中常见的垃圾收集算法有四种: 标记-清除算法(Mark-Sweep): 复制算法(Copying): 标记-整理(Mark-Compact): 分代收集: 下面我们来一一介绍: 一.标记-清除算法(Mark-Sweep) 这是最基础的垃圾收集算法,算法分为"标记"和"清除"两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象.它的主要缺点有两个:一个是效率问题,标记和清除效率都不高:另一个是空间问题,标记清除后会产生大量不连续的内存

  • Java编程基于快速排序的三个算法题实例代码

    快速排序原理简介 快速排序是我们之前学习的冒泡排序的升级,他们都属于交换类排序,都是采用不断的比较和移动来实现排序的.快速排序是一种非常高效的排序算法,它的实现,增大了记录的比较和移动的距离,将关键字较大的记录从前面直接移动到后面,关键字较小的记录从后面直接移动到前面,从而减少了总的比较次数和移动次数.同时采用"分而治之"的思想,把大的拆分为小的,小的拆分为更小的,其原理如下:对于给定的一组记录,选择一个基准元素,通常选择第一个元素或者最后一个元素,通过一趟扫描,将待排序列分成两部分,

  • 基于flask实现五子棋小游戏

    本文实例为大家分享了基于flask实现五子棋小游戏的具体代码,供大家参考,具体内容如下 前言 首先说明一下,本人方向是java后端,只因老师布置了一个作业,要用flask来做一个五子棋,没办法被逼上梁山,程序不太美观,但是应付作业还是够了的. 废话不多说,下面开锤! 首先整个程序是一个web应用,前端html+css+javaScript(有用到jquery)(基本都是现学的,所以程序很多注释也很丑),后端用的flask框架. 准备工作 **1.**python环境.安装flask **2.**

  • 基于Python实现五子棋-(人机对战)

    目录 前言 人人对战 动态演示 源码分享 人机对战 前言 快520了,咱们来玩玩五子棋陶冶情操.快拿这个和你女朋友去对线.(分了别来找我哇).多的不说直接进入正题 人人对战 游戏规则:p1为黑子,p2为白子,黑子先手,一方达到五子相连即为获胜. 动态演示 源码分享 cheackboard.py 定义黑白子,落子位置以及获胜规则. from collections import namedtuple Chessman = namedtuple('Chessman', 'Name Value Col

  • Java使用动态规划算法思想解决背包问题

    目录 动态规划算法 动态规划算法的思想 最优性原理 动态规划算法的三大特点 动态规划算法中的0/1背包问题 动态规划算法的优点 小结 动态规划算法 动态规划算法的思想 动态规划算法处理的对象是多阶段复杂决策问题,动态规划算法和分治算法类似,其基本思想也是将待求解问题分解成若干个子问题(阶段),然后分别求解各个子问题(阶段),最后将子问题的解组合起来得到原问题的解,但是与分治算法不同的是,子问题往往不是相互独立的,而是相互联系又相互区别的 动态规划算法问题求解的目标是获取导致问题最优解的最优决策序

随机推荐