一、引言

最近身边好几个朋友开始玩立体四子棋,激起了我的好奇心。那么首先来说什么是【立体四子棋】,规则又是如何呢?

上图即为立体四子棋,规则类似于五子棋四子连在一起,但是四子棋更加多样、丰富。不仅可以在平面内横竖斜四子连在一起,还可以在不同平面内四子斜着连在一起、同一根柱子上四子连在一起,可谓十分有趣。

二、规则介绍

那么我们用科学的方法总结一下规则:

情况一:xy平面内横竖斜四子连成

上图中的三种情况,可以推广到任意z平面

情况二:立体中四子斜着连成

以上情况同样可以在同一x轴上、同一y轴上成立

情况三:

这种情况在任意位置均成立,即z轴上四子连成

三、设计思路

鉴于立体四子棋脱胎于五子棋,那么我们可以在传统五子棋的AI算法上进行我们的创作。首先对于棋盘来说,五子棋可下的位置一共有15*15=225个,立体四子棋可下的位置有4*4*4=64个,并且由于空间限制,任何一步内的可下位置不会超过16个。这是因为不能违背物理限制,落子时棋子的下方必须不为空。

那么我们可以简单的建立一个int[4][4][4]来表示当前棋盘状态,此处不需要过多解释。对于棋盘的各种状态,我们可以通过一个enum chessPicesStatus{empty, black, white}来描述一个位置的情况。同样我们建立一个棋子位置的结构体来提供更多的信息:(value的作用后续会在提到)

enum chessPicesStatus{empty, black, white};
struct PicesPos{
int x;
int y;
int z;
chessPicesStatus type;
int value;
};

说完这些,我们再来聊聊真正的算法部分。立体四子棋和其他棋类如五子棋、围棋、国际象棋一样,均为【零和博弈】,以下为维基百科中的定义

在零和属性(如果一方得益,另一方必然损失)下,是指结果是零和的情况下会出现帕累托最优的现象。反过来说,全体参加者可得益或受损的情况被称为非零和博弈。如果一个国家利用其过剩的香蕉与另一国家剩余的苹果进行贸易,因为两方都从交易中受惠,这是一个非零和的例子。

这个概念最早是在博弈论(game theory)上发展,因此零和情况通常被称为零和游戏(zero-sum game)。

翻译一下,棋类零和游戏必须满足的几点:

  1. 整个棋盘必须是透明的,即游戏双方都可以了解到棋盘所有的信息
  2. 双方轮流出棋
  3. 在规则下必定出现一方胜利,一方失败的局面,或者产生和棋

目前在这类博弈中算法大部分已经相当成熟,基本都采用暴力搜索,模拟未来n步走子产生最优位置。但是鉴于棋类巨大的可能性,模拟出未来的每种可能性是不现实的,因此,模拟出尽可能多的步数是大家努力的目标。举个例子,著名围棋Ai Alpha Go,核心的地方在于在突破传统的蒙特卡洛搜索树,采用预先训练好的【价值评估网络】和【走子网络】两个神经网络来评估,缩小了每层的搜索量,并且配以Google的TPU,实现超越人类棋手。

在我们这次的程序中,将采用极值(极大极小)算法,以及启发式搜索,并配以alpha-beta剪枝来优化搜索量。鉴于立体四子棋每层16个位置的搜索,我们暂时还用不到蒙特卡洛搜索树和神经网络。

四、基本功能

好了,既然理论知识已经扫盲完成(没明白也没关系,后续还会再详细介绍),我们快速构建一下之后会用到的各个功能。

首先定义chessBoard类,提供如下方法:

typedef std::vector<PicesPos> PicesPosList;

class ChessBoard
{
public:
int chessBoard[][][]; void init();
bool insertPices(int x,int y,int type);
void printBoard(); PicesPosList getAvailablePos(int board[][][],chessPicesStatus side);
}

接着我们来依次实现:

首先是初始化,鉴于未来我们会重复使用棋盘,这个方法还是有一定必要性的。

void ChessBoard::init()
{
for(int z = ;z < ;z++)
{
for(int y = ;y < ;y++)
{
for(int x = ;x < ;x++)
{
chessBoard[x][y][z] = chessPicesStatus::empty;
}
}
}
}

很简单,然后我们实现落子的方法。在此需要保证几点:

  1. 这个位置是存在的
  2. 这个位置并没有落满
  3. 插入中不能出现悬空的状态
bool ChessBoard::insertPices(int x, int y, int type)
{
if(x < || x > || y < || y > )
return false; //check 0-3th floor
for(int z = ;z < ;z++)
{
if(chessBoard[x][y][z] == chessPicesStatus::empty)
{
chessBoard[x][y][z] = chessPicesStatus(type);
return true;
}
} return false;
}

同样没什么难度,接着我们来看打印函数,这个函数只是让我们能方便的看到棋盘情况,真正项目中还需要用更友好的UI来替代。

void ChessBoard::printBoard()
{
for(int z = ;z < ;z++)
{
cout<<"The "<<z<<"th floor"<<endl;
for(int y = ;y < ;y++)
{
for(int x = ;x < ;x++)
{
cout<<chessBoard[x][y][z]<<" ";
}
cout<<endl;
}
cout<<"\\\\\\\\\\\\\\"<<endl;
}
}

打印效果如下:

The 0th floor

\\\\\\\
The 1th floor \\\\\\\
The 2th floor \\\\\\\
The 3th floor \\\\\\\

最后我们来看下稍有难度的获取当前可下位置的方法,其实也很简单:

PicesPosList ChessBoard::getAvailablePos(int board[][][], chessPicesStatus side)
{
PicesPosList availablePos; for(int y = ;y < ;y++)
{
for(int x = ;x < ;x++)
{
for(int z = ; z < ;z++)
{
if(board[x][y][z] == chessPicesStatus::empty)
{
PicesPos pos;
pos.x = x;
pos.y = y;
pos.z = z;
pos.type = chessPicesStatus::empty;
pos.value = getPosValue(board,&pos,side);
availablePos.push_back(pos);
break;
}
}
}
} return availablePos;
}

基本就是对于每个x,y,从下往上找可用位置,找到后退出。其中side参数和getPosValue(board,&pos,side)是我们之后会提到的启发式搜索所用到的价值评估函数,可以先行略过。

至此,我们已经构建了一个基本的棋盘,配上简单的io交互就可以在这上面下棋了!

在之后的几篇文章,我会讲到胜负判断、当前局势分评估、搜索树的构建,剪枝算法优化,启发式搜索等内容,敬请期待!

参考博文:

http://blog.csdn.net/lihongxun945/article/details/50625267

https://www.cnblogs.com/pangxiaodong/archive/2011/05/26/2058864.html

https://www.zhihu.com/question/27221568

致谢!

新手立体四子棋AI教程(1)——基础扫盲的更多相关文章

  1. 新手立体四子棋AI教程(3)——极值搜索与Alpha-Beta剪枝

    上一篇我们讲了评估函数,这一篇我们来讲讲立体四子棋的搜索函数. 一.极值搜索 极值搜索是game playing领域里非常经典的算法,它使用深度优先搜索(因为限制最大层数,所以也可以称为迭代加深搜索) ...

  2. 新手立体四子棋AI教程(2)——价值评估函数

    上一篇我们完成了整个程序的基础框架,那么在讲到真正的搜索算法前,我们先来看看五子棋如何评估当前局势,以及如何计算某个位置的价值. 一.五子棋 在五子棋中,包括成五,活三,活二等定势,下图为山东师范大学 ...

  3. 新手立体四子棋AI教程(4)——启发式搜索与主程序

    通过前面几篇文章的学习,我们的四子棋程序已经有了框架.搜索几大部分,但是还有着不少问题,我们的程序只能迭代很有限的步骤,导致棋力低下,在这一篇我们将通过启发式搜索极大的优化搜索效率. 一.原因 我们之 ...

  4. swing桌面四子棋程序开发过程中遇到的一些问题记录(二)

    第二个遇到的问题是将JButton按钮设置成透明的按钮.首先UI给我一张透明的图片,如果我直接给Button按钮设置背景图片的话,是没有透明的效果的,只会留下白色的底,设置前后的效果如下图 制作透明的 ...

  5. codevs1004四子连棋[BFS 哈希]

    1004 四子连棋   时间限制: 1 s   空间限制: 128000 KB   题目等级 : 黄金 Gold   题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗 ...

  6. Codevs p1004 四子连棋

                          四子连棋 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向 ...

  7. 【宽度优先搜索】神奇的状态压缩 CodeVs1004四子连棋

    一.写在前面 其实这是一道大水题,而且还出在了数据最水的OJ上,所以实际上这题并没有什么难度.博主写这篇blog主要是想写下一个想法--状态压缩.状态压缩在记录.修改状态以及判重去重等方面有着极高的( ...

  8. codevs 1004 四子连棋

    1004 四子连棋  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold     题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白 ...

  9. codevs 1004 四子连棋 BFS、hash判重

    004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold       题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋 ...

随机推荐

  1. uploadify上传文件(2)--基础语法

    隔了好久,因为最近搬家,离开从小生活的城市,来到杭州.找工作.找房子等诸多事宜耽误了这篇文章许久.今天难得闲暇在旅馆中完成uploadify上传文件系列的第二篇--uploadify使用的基础语法. ...

  2. Redis笔记1-redis的搭建和使用

    1.   Redis的安装 1.1. Redis的安装 Redis是c语言开发的. 安装redis需要c语言的编译环境.如果没有gcc需要在线安装.yum install gcc-c++ 安装步骤: ...

  3. jQuery手机发送验证码倒计时代码

    <!DOCTYPE> <html> <head> <meta charset="UTF-8"> <script type=&q ...

  4. 移动端-手机端-日历选择控件(支持Zepto和JQuery)

    一. 效果图 二. 功能说明 1. 支持切换年份,月份. 2. 支持点击选中日期,也可以点击确定选择日期. 三. 使用方法 1. 添加Input 在你的页面中添加Input输入框.可以再html里,也 ...

  5. 使用simhash库来进行网页去重

    首先感谢作者yanyiwu贡献的开源项目https://github.com/yanyiwu/simhash.在做项 目过程中,翻了一遍<这就是搜索引擎  核心技术详解>这本书的查重算法, ...

  6. 关于编译FFMPEG的初级教程

    首先我们要下载相关工具,这里不多说,大家按照我的地址去下载文件就好了 MINGW下载地址:http://prdownloads.sourceforge.net/mingw/MinGW-3.1.0-1. ...

  7. 笔记︱信用风险模型(申请评分、行为评分)与数据准备(违约期限、WOE转化)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 巴塞尔协议定义了金融风险类型:市场风险.作业风 ...

  8. PHP XML简介

    php xml文件编程. xml简介 XML作用 1.可以作为程序间通讯的标准(ajax text xml) 2.可以作为配置文件 3.可以作为小型数据库 XML语法 一个xml文件应该包括以下几个内 ...

  9. linux2.6硬盘扇区直接读写程序

    下面的程序可以在linux2.6内核直接读写硬盘的指定扇区,也是根据网上一个朋友的做法做了修改的: 有两个不是很明白的地方就是:1.bd_claim函数的使用,这个是个递归函数,像是匹配内存指针和设备 ...

  10. javaWeb之自动发送邮件生日祝福(ServletContextListener监听)

    在看完本随笔仍然不理解的可以看  javaWeb邮箱发送  :里面有具体的邮箱服务器配置 企业在员工生日当天发送邮箱生日祝福: 一般是用监听器完成:  而合适的监听是ServletContextLis ...