点击注册
点击注册
.

你的位置:真人斗地主游戏 > 斗地主技巧 >

现金斗地主游戏 斗地主残局的对抗搜索解法

现金斗地主游戏 斗地主残局的对抗搜索解法

  许久未打开手机斗地主,前日登录发现新增“残局”模式,便思考尝试编程给出解法。

搜索网络上相关资料较少,去重后仅找到两个简单的Python实现,其一仅能判断必胜策略的存在性,另一给出了低效的简单实现,且牌型的支持不够完整,对于一个简单残局的运算耗时五分钟,相比下本文的C++多线程实现仅耗时数秒,且复用对象减少内存消耗。

  斗地主残局双方明牌,玩家作为地主方先出。

完全信息,有限步数(手牌数有限,打完结束),符合策梅洛定理* ,且显然没有平局,双方必有一方有必胜策略。

至于如何暴力搜索,此处非常符合“对抗搜索”的应用范围,即MinMax算法。

某书的一部分* 介绍得很清晰,很有帮助。

  放在双人斗地主的场景中来说,这意味着在每一次出牌时,玩家都会选择打出对自己最有利的一手牌,打出对对方最不利的一手牌。

而这是一个零和博弈,每种出牌最终都会导致一个二选一的结果——地主赢(我们认为该节点得分为1)或农民赢(得分-1)。

地主轮将努力最大化分值,从众多分支中挑分值最大的一个,并将其作为当前节点的分值;相应的,农民轮将从众多分支中挑分值最小的作为当前节点的分值。

显然,地主要想有必胜策略,根节点得分需要为1 。

  至此,该问题已可以完全地用MinMax算法表述出来并简单地得到解决框架:状态为地主、农民手牌;地主/农民步骤函数根据状态计算出后续可能的状态(出牌型);一方手牌为空时该节点为叶子结点,得到结果分值;获取分值函数递归计算节点分值。

借用资料中伪代码阐释:

  至此,判断必胜策略的存在性问题已得到理论解决。

关于保存步骤以供回溯,我选择在Action(s)函数中顺便构建状态树作为一个搜索时的副作用。

当求得根节点分值的同时状态树已构建完成

  其中所有非标量对象均为指向堆上对象的指针。

结构体包含一个析构函数,用以析构children指向的堆上的一个std::vector<Node*>对象。

  斗地主可能出牌策略的规模在N!级别,考虑双人游戏,规模可达N!M!级别。

若独立创建对象,极其容易栈溢出、占满内存。

因此我实现了两个对象池,有效缓解了空间压力,分别用以储存出牌牌型、手牌。

  牌型池的效果应是最明显的,因为全局牌型总量在第一层便应被固定了,此后只减不增。

复用后全局牌型对象一般维持在20~30个。

  Key uint8_t 算法:手牌对象储存结构为std::map,key为牌面大小,value为该牌数量。

牌面大小数值为3~18(出于方便计算顺子的缘故,中间有空缺),而牌数最多支持两副,每张牌最多八张,为1~8 。

故uint8_t高五位储存牌面,低3位储存数量。

  手牌池的设计修改了很多次,最终采用了这个方法。

由于决策树不深(最大深度应为两者牌数相加M+N),vector不会很大。

使用后再未出现过内存不足、栈溢出甚至蓝屏的情况,最大内存使用量目前在10GB左右,一般在1GB左右。

本人以前也是一名宅男,宅男心里面想做什么事笔者都非常明白,到现在笔者早已将这些想法都一一实现了。

一)舍弃二条—有四张三条、三张四条、四张五条、三张六条、四张七条,共十八张有利了J“条子牌求进的机会。

  由于决策树是一颗深度有限,但广度扩展较广的树,因此保留MinMax算法的递归结构,对栈压力较小。

出于效率考虑,设法对其进行剪枝。

考虑到应用场景为双人明牌斗地主,玩家(地主)先出,进行如下剪枝:

  对于某一次出牌产生的节点,若进行该行动的玩家行动后手牌为空,则该节点作为其父节点的唯一子节点也是叶子结点并立即返回上一层递归(当能一次出完牌时,没有理由出其他牌);

  对玩家(地主)而言,对于对方每一次出牌,玩家只需知道唯一一个有必胜策略的应对方式即可。

因此遍历玩家可能的策略时,若子节点分值不为1则删除(见

  节)子树,若子节点分值为1则该子树为其父节点的唯一子树,并立即break并删除所有其他子节点。

这能使问题规模下降到最乐观情况下M!(此处配合另一处细节,见

  尝试使用多线程充分利用计算资源,加速计算。

对于这一本质上类似深度优先搜索的问题,采用了较为简单的“划分问题子空间”的方法。

又考虑到需控制线程数量以免导致性能下降,故选取农民的第一步可能的出牌作为子空间划分点。

选择一层划分的优点在于在“Reduce”最终获得的结果时,由于使用了std::future,在前面获得了确认分值的结果时,迭代可以直接break并返回上一层递归调用,而由后台进程继续构建其他尚未构建完成的子树(此处再次涉及到其他优化一节的设计)。

  之前在剪枝一节中提到了玩家决策过程中删除非必要子树。

此过程删除的子树数量较多、大小较大,采用了递归算法删除;于搜索过程中删除较为耗时,且删除子树行为本身不对搜索过程产生副作用,因此想到开后台线程删除;然而直接开线程挤占计算线程的资源,更拖慢了效率。

于是构建了一个“伐木工”类,实现了一个“多生产者,单消费者”的模型。

将欲删除的子树的根节点丢到任务队列,由该单线程循环获取任务并进行删除,有效降低了计算资源挤占,提高了速度。

基本实现如下:

  最后一个出于提高剪枝效率考虑的设计在GetAllSolution(获取所有可能的出牌牌型)函数上。

剪枝中提前返回的逻辑在最差情况下事实上是无法降低时间复杂度的,只能事后诸葛地降低空间复杂度。

如何尽量避免最差情况呢。

我尝试在获取出牌牌型时将长牌型(如顺子、连对)的搜索结果放置于前,短牌型(如单牌、对子)放置于后,使得遍历搜索结果时先尽量多出牌,使得先遍历的树深度、广度都较小,也较为偏向人类思考方式(先想着多出长牌型),提高剪枝的优化效果。

  代码已托管于Github,并提供Windows下64位预编译的Release,欢迎Issue/Fork/Star。

由于是个人第一个较完整的C++项目,代码较脏,欢迎指正。

  之前有“Triggered a Breakpoint”Bug出现(Release版本下表现为闪退),但未能找到原因,修改了一些实现后再未出现过。

  运行时中等问题内存占用1G以下,2秒以下解出;偶现高复杂度问题(手牌多,单牌多;欢乐斗地主专家级前38关中出现2-3次)需要约10G内存,耗时30秒-1分钟。





Powered by 真人斗地主游戏 @2013-2022 RSS地图 HTML地图

网站统计——

  • 谷歌搜索留痕推广
  • 谷歌搜索留痕排名技术
  • 谷歌快速排名
  • 留痕方法
  • 谷歌搜索快速方法
  • google搜索留痕程序
  • 谷歌快速排名
  • 澳门太阳城
  • 最大博彩公司
  • 谷歌搜索关键词排名
  • 搜索留痕程序
  • 谷歌排名出售
  • 谷歌蜘蛛池排名
  • 搜索留痕软件
  • 缅甸果敢赌场
  • 电子游艺规则
  • 谷歌留痕推广
  • google引流程序
  • 谷歌快速排名
  • google引流程序
  • 留痕推广
  • 大西洋城赌场
  • 买球地址
  • 搜索留痕
  • 搜索留痕程序出售
  • 谷歌蜘蛛池排名技术
  • 留痕程序
  • 如何提高google搜索排名
  • 数字币博彩
  • 洗钱方法
  • Google留痕收录
  • 最新谷歌搜索留痕排名
  • 搜索留痕
  • Google留痕收录
  • google搜索留痕
  • 数字币博彩网站
  • 足球投注平台
  • 博彩推广话术
  • 推广引流方法
  • 引流方法
  • 博彩推广话术
  • 网上博彩推广引流
  • 数字币赌场
  • 皇冠现金网
  • 蜘蛛池排名
  • 谷歌蜘蛛池
  • 留痕程序出售
  • google搜索留痕程序
  • 比特币网上赌场
  • 洗钱平台
  • 搜索留痕
  • 博彩推广方式
  • 网上博彩推广
  • 快速排名
  • 搜索留痕程序
  • bbin平台大全
  • 体育博彩公司排名
  • 留痕排名技术
  • 最新谷歌关键词排名
  • 推广渠道
  • 谷歌快速排名
  • 博彩推广
  • 世界杯赌球地址
  • 皇冠博彩公司
  • 谷歌排名出售
  • 博彩引流渠道
  • 搜索留痕程序
  • google搜索留痕
  • 引流渠道
  • 果敢网上赌场
  • 世界杯赌球
  • 搜索留痕方法
  • 博彩搜索留痕
  • 博彩引流
  • 博彩引流
  • 搜索留痕
  • 缅甸网上赌场
  • 欧洲杯赌球
  • 谷歌搜索排名
  • 留痕程序
  • 网上博彩推广引流
  • 留痕技术
  • 搜索留痕技术出售
  • 澳门威尼斯人网上赌场
  • 外围博彩
  • 博彩网站推广
  • 推广引流
  • 留痕程序出售
  • 谷歌推广引流技术
  • 推广引流方法
  • 美国在线赌场
  • 沙巴体育投注平台
  • 最新谷歌搜索留痕
  • 谷歌蜘蛛池排名技术
  • 网站推广方法
  • 留痕程序出售
  • 博彩推广方法
  • 菠菜论坛
  • 买球平台
  • 谷歌搜索留痕
  • 蜘蛛池排名
  • 博彩公司推广渠道
  • 谷歌搜索留痕
  • 博彩公司推广渠道
  • 真钱游戏
  • 网上赌球地址
  • 赌球平台推荐
  • 赌球网址
  • 博彩包网
  • 买球app
  • 澳门博彩公司
  • 威尼斯人赌场
  • 博彩平台推荐
  • 美国博彩网站
  • 缅甸实体赌场
  • 柬埔寨网上赌场
  • 柬埔寨在线赌场
  • 韩国博彩
  • 支持人民币的博彩公司
  • 世界五大比特币交易所
  • 欧易是哪个国家的
  • 中币跑路
  • 亚洲博彩公司
  • 合法网上赌场
  • 马尼拉赌场
  • 支持人民币的博彩公司
  • 大陆博彩平台
  • 澳门新葡京娱乐城
  • 老挝赌场
  • 世界赌场排名
  • 网上博彩公司排行
  • 菠菜论坛
  • 东南亚赌博网站
  • 虚拟币博彩
  • 澳门百家乐网址
  • 网上博彩导航
  • 区块链百家乐游戏
  • 马来西亚博彩公司
  • 越南赌场
  • 区块链百家乐
  • 香港娱乐场
  • 澳大利亚赌博网站
  • 足球赔率
  • 菲律宾网上赌场
  • 数字币博彩网站
  • 足球投注网站
  • 百家乐论坛
  • 皇冠体育博彩公司
  • 网上赌博网站
  • 网上博彩推广话术
  • 谷歌搜索快速方法
  • 网上博彩推广话术
  • 数字币赌场
  • 皇冠博彩公司
  • 世界杯博彩公司
  • 英国博彩公司
  • 网上博彩合法化
  • 新加坡赌场
  • 比特币网上赌场
  • 怎么洗钱
  • 加密货币博彩平台
  • 世界杯赌球网址
  • 网上赌球地址
  • 博彩推广方式
  • 印度尼西亚博彩公司
  • 国际包网
  • bbin平台直营
  • 亚洲体育博彩平台
  • 越南博彩公司
  • 百家乐路单
  • 澳门博彩官网
  • 博彩网推荐
  • 澳门太阳城网址
  • 百家乐网址
  • 世界杯赌球网址
  • 皇冠博彩网址
  • 洗钱方法
  • 买球网站
  • 欧洲杯赌球平台
  • 皇冠现金网
  • 外围赌球平台
  • 果敢赌场
  • 买球技巧
  • 全球最大博彩公司
  • 电子游艺
  • 真人电子游戏
  • 骰宝游戏规则
  • 亚洲体育博彩平台
  • 澳门在线赌场
  • 缅甸赌场地址
  • 赌球平台
  • 赌场如何赢钱
  • 世界杯买球网站
  • 真人牌九游戏
  • 世界杯买球官网
  • 时时彩平台
  • 六合彩预测
  • 威尼斯人网上赌场
  • 外围赌球网站
  • 赌博网址
  • 彩票群
  • 微信赌博群
  • 韩国首尔赌场
  • 赌钱游戏
  • 美国网上赌场
  • bbin官网
  • 沙巴体育官网
  • 博彩平台推荐
  • 数字币博彩网站
  • 比特币网上赌场
  • 世界赌场名单
  • 美国赌场攻略
  • 菠菜论坛排名
  • 菠菜论坛排名
  • 缅甸网上赌场
  • 支持人民币的博彩公司