开发h5斗地主大厅算法——第十二章の主动出牌(1)

本章开始,我们介绍主动出牌的算法,和被动出牌类似,我们第一步把主要架子搭起来。

首先清空出牌序列

[cpp] view plain copy

clsHandCardData.ClearPutCardList();  

主动出牌的策略按照优先级大体可以分为三类:

【一】能直接一手牌出去,优先出。

【二】两手牌出去且有绝对大牌,先出绝对大牌。

【三】出一手牌使得接下来自己手牌价值最大化。

[cpp] view plain copy

//剪枝:如果能出去最后一手牌直接出
    CardGroupData SurCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList);
    //如果能一次性出去且没有炸弹,因为有炸弹的话权值可能会更大
    if (SurCardGroupData.cgType != cgERROR&&!HasBoom(clsHandCardData.value_aHandCardList))
    {
            Put_All_SurCards(clsHandCardData, SurCardGroupData);
            return;
    }  

然后是【二】:目前2.0版本我们暂时不考虑记牌功能,所以绝对大牌只支持王炸,以后在这里可以做更多智能的处理。

[cpp] view plain copy

/*王炸——当前策略只处理王炸作为倒数第二手的优先出牌逻辑,后续版本会在此基础上优化*/
    if (clsHandCardData.value_aHandCardList[17] > 0 && clsHandCardData.value_aHandCardList[16] > 0)
    {  

        clsHandCardData.value_aHandCardList[17] --;
        clsHandCardData.value_aHandCardList[16] --;
        clsHandCardData.nHandCardCount -= 2;
        HandCardValue tmpHandCardValue = get_HandCardValue(clsHandCardData);
        clsHandCardData.value_aHandCardList[16] ++;
        clsHandCardData.value_aHandCardList[17] ++;
        clsHandCardData.nHandCardCount += 2;
        if (tmpHandCardValue.NeedRound == 1)
        {
            clsHandCardData.value_nPutCardList.push_back(17);
            clsHandCardData.value_nPutCardList.push_back(16);
            clsHandCardData.uctPutCardType = get_GroupData(cgKING_CARD, 17, 2);
            return;
        }
    }  

接下来就是第三步, 就是我们选择打出一手牌尽量使得接下来自己手牌价值最大化。

与被动出牌不一样的是,主动出牌我们没有限制条件,我也尝试过全部枚举,不过时间消耗肯定是爆炸的。于是我定制了一个基本的出牌优先级策略:

①三带一、飞机等牌优先打出,因为这种牌型可以把小牌带出。其实这里对比较大的三带一不是很公平,后续版本可以在此处做分支处理,比如说三带一的话只循环到10,J以上先不着急打出。飞机倒还好说,那玩意基本管不到别人,所以出了就出了。至于四带二嘛。。。四带二是个什么东西?我不知道,我眼里只有炸弹。

所以,这部分的架子应该是这样的。

若可以出这几种牌型,选择一种价值最高的打出。因为要枚举所有的牌,所以在循环外根据最佳策略进行出牌处理。

②没有上述牌型后,优先处理当前最小的一张牌。若是该牌有四张,先不处理。

这里出牌处理就放在循环内了,因为当确定了这个i值后无论如何都是要打出一手牌的,且打完牌就可以return了。

③如果没有从3到2的非炸牌,那么看看有没有单王,如果有,可以出。

[cpp] view plain copy

//如果没有3-2的非炸牌,则看看有没有单王
if (clsHandCardData.value_aHandCardList[16] == 1 && clsHandCardData.value_aHandCardList[17] == 0)
{
    clsHandCardData.value_nPutCardList.push_back(16);
    clsHandCardData.uctPutCardType = get_GroupData(cgSINGLE, 16, 1);
    return;
   }
if (clsHandCardData.value_aHandCardList[16] == 0 && clsHandCardData.value_aHandCardList[17] == 1)
{
    clsHandCardData.value_nPutCardList.push_back(17);
    clsHandCardData.uctPutCardType = get_GroupData(cgSINGLE, 17, 1);
    return;
}  

④单王也没有,出炸弹。

[cpp] view plain copy

//单王也没有,出炸弹
    for (int i = 3; i < 16; i++)
    {
        if (clsHandCardData.value_aHandCardList[i] == 4)
        {
            clsHandCardData.value_nPutCardList.push_back(i);
            clsHandCardData.value_nPutCardList.push_back(i);
            clsHandCardData.value_nPutCardList.push_back(i);
            clsHandCardData.value_nPutCardList.push_back(i);  

            clsHandCardData.uctPutCardType = get_GroupData(cgBOMB_CARD, i, 4);  

            return;
        }
    }  

这里可能有人会想,需不需要再加上炸弹也没有,出王炸呢?其实不存在的,因为如果你真的没牌打了就剩王炸了,早在前面剪枝部分就处理了。

所以如果走到这里都没有返回的话,肯定是出现错误了。

把上述的各个模块连接起来,即构成主动出牌的基本架子:

[cpp] view plain copy

void get_PutCardList_2(HandCardData &clsHandCardData)
{  

    clsHandCardData.ClearPutCardList();  

    //剪枝:如果能出去最后一手牌直接出
    CardGroupData SurCardGroupData = ins_SurCardsType(clsHandCardData.value_aHandCardList);
    //如果能一次性出去且不是四带二,因为主动出牌若手上剩四带二牌的话可以考虑先打一手然后炸,获得双倍积分
    if (SurCardGroupData.cgType != cgERROR&&SurCardGroupData.cgType!=cgFOUR_TAKE_ONE&&SurCardGroupData.cgType !=cgFOUR_TAKE_TWO)
    {
    }  

    /*王炸——当前策略只处理王炸作为倒数第二手的优先出牌逻辑,后续版本会在此基础上优化*/
    if (clsHandCardData.value_aHandCardList[17] > 0 && clsHandCardData.value_aHandCardList[16] > 0)
    {
    }  

    //暂存最佳的价值
    HandCardValue BestHandCardValue;
    BestHandCardValue.NeedRound = 20;
    BestHandCardValue.SumValue = MinCardsValue;
    //我们认为不出牌的话会让对手一个轮次,即加一轮(权值减少7)便于后续的对比参考。
    BestHandCardValue.NeedRound += 1;  

    //暂存最佳的组合
    CardGroupData BestCardGroup;  

    //带出去的牌
    int tmp_1 = 0;
    int tmp_2 = 0;
    int tmp_3 = 0;
    int tmp_4 = 0;
    //优先处理三牌、飞机等牌
    for (int i = 3; i < 16; i++)
    {
    }
    //这部分出牌处理放到循环外
    if (BestCardGroup.cgType == cgTHREE_TAKE_ONE)
        {  

        }
    else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO)
        {  

        }
    else if (BestCardGroup.cgType == cgTHREE_TAKE_ONE_LINE)
        {  

        }
    else if (BestCardGroup.cgType == cgTHREE_TAKE_TWO_LINE)
        {  

        }  

    //次之处理当前价值最低的牌,现在不必再考虑这张牌可能被三牌带出等情况
    for (int i = 3; i < 16; i++)
    {
    }
    //如果没有3-2的非炸牌,则看看有没有单王
    if (clsHandCardData.value_aHandCardList[16] == 1 && clsHandCardData.value_aHandCardList[17] == 0)
    {
    }
    if (clsHandCardData.value_aHandCardList[16] == 0 && clsHandCardData.value_aHandCardList[17] == 1)
    {
    }
    //单王也没有,出炸弹
    for (int i = 3; i < 16; i++)
    {
    }  

    //异常错误
    clsHandCardData.uctPutCardType = get_GroupData(cgERROR, 0, 0);
    return;  

}  

至此主动出牌的架子就搭好了,且除了三带牌型出牌策略及解决最小值牌出牌策略这两个大部分,其他部分代码本章均已给出,下一章我们开始实现三带牌型的出牌策略。

原文地址:http://blog.51cto.com/13595127/2068387

时间: 2024-08-02 15:31:21

开发h5斗地主大厅算法——第十二章の主动出牌(1)的相关文章

每日算法之四十二:Permutation Sequence (顺序排列第k个序列)

The set [1,2,3,-,n] contains a total of n! unique permutations. By listing and labeling all of the permutations in order, We get the following sequence (ie, for n = 3): "123" "132" "213" "231" "312" "

算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树

搜索树数据结构支持许多动态集合操作,如search(查找).minmum(最小元素).maxmum(最大元素).predecessor(前驱).successor(后继).insert(插入).delete(删除),这些都是基本操作,可以使用一颗搜索树当做一个字典或者一个优先队列. 12.1.什么事二叉搜索树 二叉搜索树是以一棵二叉树来组织的,可以用一个链表数据结构来表示,也叫二叉排序树.二叉查找树: 其中的每个结点都是一个对象,每个对象含有多个属性(key:该结点代表的值大小,卫星数据:不清楚

MiS603开发板 第十二章 SLAVE FIFO流传输

作者:MiS603开发团队 日期:20150911 公司:南京米联电子科技有限公司 论坛:www.osrc.cn 网址:www.milinker.com 网店:http://osrc.taobao.com EAT博客:http://blog.chinaaet.com/whilebreak 博客园:http://www.cnblogs.com/milinker/ MiS603开发板 第十二章 SLAVE FIFO流传输 15.1 USB 固件源码分析 SLAVE FIFOUSB 固件源码仍然采用上

算法导论第十二章__二叉搜索数

package I第12章__二叉搜索树; //普通二叉树 public class BinaryTree<T> { // -----------------------数据结构--------------------------------- private int height = 0; private Node<T> rootNode; class Node<T> { T t; int key; Node left; Node right; public Node

[CSAPP笔记][第十二章并发编程]

第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟悉的例子. 我们主要将并发看做是一种操作系统内核用来运行多个应用程序的机制. 但是,并发不仅仅局限于内核.它也可以在应用程序中扮演重要的角色. 例如 Unix信号处理程序如何允许应用响应异步事件 例如:用户键入ctrl-c 程序访问虚拟存储器的一个未定义的区域 其他情况 访问慢速I/O设备 当一个应

【.NET Core项目实战-统一认证平台】第十二章 授权篇-深入理解JWT生成及验证流程

原文:[.NET Core项目实战-统一认证平台]第十二章 授权篇-深入理解JWT生成及验证流程 [.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章介绍了基于Ids4密码授权模式,从使用场景.原理分析.自定义帐户体系集成完整的介绍了密码授权模式的内容,并最后给出了三个思考问题,本篇就针对第一个思考问题详细的讲解下Ids4是如何生成access_token的,如何验证access_token的有效性,最后我们使用.net webapi来实现一个外部接口(本来想用JAVA来实现的,

《构建之法》第十一、十二章学习总结

第十一章的内容是软件设计与实现. 在第一节中,讲的是关于分析和设计方法,向我们介绍在"需求分析"."设计与实现"阶段."测试""发布"阶段该搞清楚的问题. 在第二节中,讲的是关于图形建模和分析方法.在表达实体和实体之间的关系时,可以用到思维导图(Mind Map).实体关系图(ERD).UCD ;在表达数据的流动时,可以用到DFD工具:在表达控制流的时候可以用到FSM工具:前面提到的这些图形建模方法各有特点,UML却可以有一个

JavaScript DOM编程艺术-学习笔记(第十二章)

第十二章 1.本章是综合前面章节的所有东西的,一个综合实例 2.流程:①项目简介:a.获取原始资料(包括文本.图片.音视频等) b.站点结构(文件目录结构) c.页面(文件)结构 ②设计(切图) ③css -  base.css用于引入使用的css文件 color.css  - 用于设置样式 layout.css - 用于设置布局 Typography.css - 用于设置版式 3.题外话:①在实际开发中,即使是一个空白项目也往往不会从一无所有做起,而借助的平台一般会提供目录结构,所以需要把自己

第二十二章 TCP/IP层的实现

                      第二十二章    TCP/IP层的实现        我比较喜欢先难后易,如果把GPU显示管理.和网络管理拿下后:我会从头整理.改写一遍APO操作系统.这样,就会形成APO操作系统的锥形.也获得了全局观.内核CPU线路.和用户CPU线路,你可以将它们看成是独立的2个32位CPU核:内核CPU主要任务是实时处理.硬件中断,256个实时线程包含了一些中断程序的后半部.用户CPU主要是动态优先级进程.线程调度,各种应用程序的运行:2个核之间是通过消息交互.句