Skip to content

sickboyodd/FightTheLandLord

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 

Repository files navigation

 # C++ 斗地主

By CCL Team


2018.05.26 更新了策略。

// 斗地主(FightTheLandlord)样例程序
// 无脑策略
// 最后更新于2018-5-8
// 作者:zhouhy
// 游戏信息:http://www.botzone.org/games#FightTheLandlord

#include <iostream>
#include <set>
#include <string>
#include <cassert>
#include <cstring> // 注意memset是cstring里的
#include <algorithm>
#include "jsoncpp/json.h" // 在平台上,C++编译时默认包含此库
#include <vector>
using namespace std;
constexpr int PLAYER_COUNT = 3;

enum class CardComboType
{
    PASS, //
    SINGLE, // 单张
    PAIR, // 对子
    STRAIGHT, // 顺子
    STRAIGHT2, // 双顺
    TRIPLET, // 三条
    TRIPLET1, // 三带一
    TRIPLET2, // 三带二
    BOMB, // 炸弹
    QUADRUPLE2, // 四带二(只)
    QUADRUPLE4, // 四带二(对)
    PLANE, // 飞机
    PLANE1, // 飞机带小翼
    PLANE2, // 飞机带大翼
    SSHUTTLE, // 航天飞机
    SSHUTTLE2, // 航天飞机带小翼
    SSHUTTLE4, // 航天飞机带大翼
    ROCKET, // 火箭
    INVALID // 非法牌型
};

int cardComboScores[] = {
        0, //
        1, // 单张
        2, // 对子
        6, // 顺子
        6, // 双顺
        4, // 三条
        4, // 三带一
        4, // 三带二
        10, // 炸弹
        8, // 四带二(只)
        8, // 四带二(对)
        8, // 飞机
        8, // 飞机带小翼
        8, // 飞机带大翼
        10, // 航天飞机(需要特判:二连为10分,多连为20分)
        10, // 航天飞机带小翼
        10, // 航天飞机带大翼
        16, // 火箭
        0 // 非法牌型
};

template <typename CARD_ITERATOR>
CARD_ITERATOR plusplus(CARD_ITERATOR s,int n)
{
    for(int i=1;i<=n;i++)
        s++;
    return s;
}

#ifndef _BOTZONE_ONLINE
string cardComboStrings[] = {
        "PASS",
        "SINGLE",
        "PAIR",
        "STRAIGHT",
        "STRAIGHT2",
        "TRIPLET",
        "TRIPLET1",
        "TRIPLET2",
        "BOMB",
        "QUADRUPLE2",
        "QUADRUPLE4",
        "PLANE",
        "PLANE1",
        "PLANE2",
        "SSHUTTLE",
        "SSHUTTLE2",
        "SSHUTTLE4",
        "ROCKET",
        "INVALID"
};
#endif

// 用0~53这54个整数表示唯一的一张牌
using Card = short;
constexpr Card card_joker = 52;
constexpr Card card_JOKER = 53;

// 我的牌有哪些
set<Card> myCards;

// 地主被明示的牌有哪些
set<Card> landlordPublicCards;

// 大家从最开始到现在都出过什么
vector<vector<Card>> whatTheyPlayed[PLAYER_COUNT];


// 大家还剩多少牌
short cardRemaining[PLAYER_COUNT] = { 20, 17, 17 };

// 我是几号玩家(0-地主,1-农民甲,2-农民乙)
int myPosition;

// 除了用0~53这54个整数表示唯一的牌,
// 这里还用另一种序号表示牌的大小(不管花色),以便比较,称作等级(Level)
// 对应关系如下:
// 3 4 5 6 7 8 9 10	J Q K	A	2	小王	大王
// 0 1 2 3 4 5 6 7	8 9 10	11	12	13	14
using Level = short;
constexpr Level MAX_LEVEL = 15;
constexpr Level MAX_STRAIGHT_LEVEL = 11;
constexpr Level level_joker = 13;
constexpr Level level_JOKER = 14;
int passCnt=0;
/**
 * 将Card变成Level
 */
constexpr Level card2level(Card card)
{
    return card / 4 + card / 53;
}

// 牌的组合,用于计算牌型
struct CardCombo
{
    // 表示同等级的牌有多少张
    // 会按个数从大到小、等级从大到小排序
    struct CardPack
    {
        Level level;
        short count;

        bool operator< (const CardPack& b) const
        {
            if (count == b.count)
                return level > b.level;
            return count > b.count;
        }
    };
    vector<Card> cards; // 原始的牌,未排序
    vector<CardPack> packs; // 按数目和大小排序的牌种
    CardComboType comboType; // 算出的牌型
    Level comboLevel = 0; // 算出的大小序

    /**
     * 检查个数最多的CardPack递减了几个
     */
    int findMaxSeq() const
    {
        for (unsigned c = 1; c < packs.size(); c++)
            if (packs[c].count != packs[0].count ||
                packs[c].level != packs[c - 1].level - 1)
                return c;
        return packs.size();
    }

    /**
     * 这个牌型最后算总分的时候的权重
     */
    int getWeight() const
    {
        if (comboType == CardComboType::SSHUTTLE ||
            comboType == CardComboType::SSHUTTLE2 ||
            comboType == CardComboType::SSHUTTLE4)
            return cardComboScores[(int)comboType] + (findMaxSeq() > 2) * 10;
        return cardComboScores[(int)comboType];
    }

    // 创建一个空牌组
    CardCombo() : comboType(CardComboType::PASS) {}

    /**
     * 通过Card(即short)类型的迭代器创建一个牌型
     * 并计算出牌型和大小序等
     * 假设输入没有重复数字(即重复的Card)
     */
    template <typename CARD_ITERATOR>
    CardCombo(CARD_ITERATOR begin, CARD_ITERATOR end)
    {
        // 特判:空
        if (begin == end)
        {
            comboType = CardComboType::PASS;
            return;
        }

        // 每种牌有多少个
        short counts[MAX_LEVEL + 1] = {};

        // 同种牌的张数(有多少个单张、对子、三条、四条)
        short countOfCount[5] = {};

        cards = vector<Card>(begin, end);
        for (Card c : cards)
            counts[card2level(c)]++;
        for (Level l = 0; l <= MAX_LEVEL; l++)
            if (counts[l])
            {
                packs.push_back(CardPack{ l, counts[l] });
                countOfCount[counts[l]]++;
            }
        sort(packs.begin(), packs.end());

        // 用最多的那种牌总是可以比较大小的
        comboLevel = packs[0].level;

        // 计算牌型
        // 按照 同种牌的张数 有几种 进行分类
        vector<int> kindOfCountOfCount;//我的牌有多少種呀?
        for (int i = 0; i <= 4; i++)
            if (countOfCount[i])
                kindOfCountOfCount.push_back(i);
        sort(kindOfCountOfCount.begin(), kindOfCountOfCount.end());

        int curr, lesser;

        switch (kindOfCountOfCount.size())
        {
            case 1: // 只有一类牌
                curr = countOfCount[kindOfCountOfCount[0]];
                switch (kindOfCountOfCount[0])
                {
                    case 1:
                        // 只有若干单张
                        if (curr == 1)
                        {
                            comboType = CardComboType::SINGLE;
                            return;
                        }
                        if (curr == 2 && packs[1].level == level_joker)
                        {
                            comboType = CardComboType::ROCKET;
                            return;
                        }
                        if (curr >= 5 && findMaxSeq() == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::STRAIGHT;
                            return;
                        }
                        break;
                    case 2:
                        // 只有若干对子
                        if (curr == 1)
                        {
                            comboType = CardComboType::PAIR;
                            return;
                        }
                        if (curr >= 3 && findMaxSeq() == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::STRAIGHT2;
                            return;
                        }
                        break;
                    case 3:
                        // 只有若干三条
                        if (curr == 1)
                        {
                            comboType = CardComboType::TRIPLET;
                            return;
                        }
                        if (findMaxSeq() == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::PLANE;
                            return;
                        }
                        break;
                    case 4:
                        // 只有若干四条
                        if (curr == 1)
                        {
                            comboType = CardComboType::BOMB;
                            return;
                        }
                        if (findMaxSeq() == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::SSHUTTLE;
                            return;
                        }
                }
                break;
            case 2: // 有两类牌
                curr = countOfCount[kindOfCountOfCount[1]];
                lesser = countOfCount[kindOfCountOfCount[0]];
                if (kindOfCountOfCount[1] == 3)
                {
                    // 三条带?
                    if (kindOfCountOfCount[0] == 1)
                    {
                        // 三带一
                        if (curr == 1 && lesser == 1)
                        {
                            comboType = CardComboType::TRIPLET1;
                            return;
                        }
                        if (findMaxSeq() == curr && lesser == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::PLANE1;
                            return;
                        }
                    }
                    if (kindOfCountOfCount[0] == 2)
                    {
                        // 三带二
                        if (curr == 1 && lesser == 1)
                        {
                            comboType = CardComboType::TRIPLET2;
                            return;
                        }
                        if (findMaxSeq() == curr && lesser == curr &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::PLANE2;
                            return;
                        }
                    }
                }
                if (kindOfCountOfCount[1] == 4)
                {
                    // 四条带?
                    if (kindOfCountOfCount[0] == 1)
                    {
                        // 四条带两只 * n
                        if (curr == 1 && lesser == 2)
                        {
                            comboType = CardComboType::QUADRUPLE2;
                            return;
                        }
                        if (findMaxSeq() == curr && lesser == curr * 2 &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::SSHUTTLE2;
                            return;
                        }
                    }
                    if (kindOfCountOfCount[0] == 2)
                    {
                        // 四条带两对 * n
                        if (curr == 1 && lesser == 2)
                        {
                            comboType = CardComboType::QUADRUPLE4;
                            return;
                        }
                        if (findMaxSeq() == curr && lesser == curr * 2 &&
                            packs.begin()->level <= MAX_STRAIGHT_LEVEL)
                        {
                            comboType = CardComboType::SSHUTTLE4;
                            return;
                        }
                    }
                }
        }

        comboType = CardComboType::INVALID;
    }

    /**
     * 判断指定牌组能否大过当前牌组(这个函数不考虑过牌的情况!)
     */
    bool canBeBeatenBy(const CardCombo& b) const
    {
        if (comboType == CardComboType::INVALID || b.comboType == CardComboType::INVALID)
            return false;
        if (b.comboType == CardComboType::ROCKET)
            return true;
        if (b.comboType == CardComboType::BOMB)
            switch (comboType)
            {
                case CardComboType::ROCKET:
                    return false;
                case CardComboType::BOMB:
                    return b.comboLevel > comboLevel;
                default:
                    return true;
            }
        return b.comboType == comboType && b.cards.size() == cards.size() && b.comboLevel > comboLevel;
    }

    /**
     * 从指定手牌中寻找第一个能大过当前牌组的牌组
     * 如果随便出的话只出第一张
     * 如果不存在则返回一个PASS的牌组
     */
    template <typename CARD_ITERATOR>
    CardCombo findFirstValid(CARD_ITERATOR begin, CARD_ITERATOR end) const
    {
        if (comboType == CardComboType::PASS) // 如果不需要大过谁,只需要随便出
        {
            //            CARD_ITERATOR second = begin;
            //            second++;
            //            CardCombo temp3(begin,second);
            //            second++;
            //
            //            CardCombo temp(begin,second);
            //            if(temp.comboType==CardComboType::PAIR)
            //            {
            //                second++;
            //                CardCombo temp2(begin,second);
            //                if(temp2.comboType==CardComboType::TRIPLET)
            //                    return temp2;
            //                else
            //                    return temp;
            //            }
            //            else
            //                return temp3;
            //            // 那么就出第一张牌……
            CardCombo MyCombo(begin,end);

            auto MyDeck = vector<Card>(begin, end); //
            short MyCounts[MAX_LEVEL + 1] = {};
            unsigned short MyKindCount = 0;
            // 先数一下手牌里每种牌有多少个
            for (Card c : MyDeck)
                MyCounts[card2level(c)]++;
            // 再数一下手牌里有多少种牌
            for (short c : MyCounts)
                if (c)
                    MyKindCount++;


            // 同种牌的张数(有多少个单张、对子、三条、四条)
            short MyCountOfCount[5] = {};
            for (Level l = 0; l <= MAX_LEVEL; l++) {
                if (MyCounts[l]) {
                    MyCountOfCount[MyCounts[l]]++;
                }
            }
            //By ricky 如果手牌数目小于6直接出顺子
            //if(MyDeck.size()<6)
            //如果有三代
            if(MyCountOfCount[3])
            {
                vector<Card> solve;

                if(MyCountOfCount[3]<2)//只有一个三带
                {
                    CARD_ITERATOR beginIT = begin;
                    for(int i=0;i<MAX_LEVEL-3;i++)
                    {
                        if(MyCounts[i]==3)
                            break;
                        beginIT=plusplus(beginIT, MyCounts[i]);
                    }
                    for(int i=0;i<3;i++)
                    {
                        solve.push_back(*beginIT);
                        beginIT++;
                    }
                    //三代一
                    if(MyCountOfCount[1])
                    {
                        CARD_ITERATOR beginIT_1 = begin;
                        for(int i=0;i<MAX_LEVEL-3;i++)
                        {
                            if(MyCounts[i]==1) break;
                            beginIT_1=plusplus(beginIT_1,MyCounts[i]);
                        }
                        solve.push_back(*beginIT_1);
                        return CardCombo(solve.begin(),solve.end());
                    }
                    //三代二
                    if(MyCountOfCount[2])
                    {
                        CARD_ITERATOR beginIT_2 = begin;
                        for(int i=0;i<MAX_LEVEL-3;i++)
                        {
                            if(MyCounts[i]==2) break;
                            beginIT_2=plusplus(beginIT_2,MyCounts[i]);
                        }
                        solve.push_back(*beginIT_2);
                        beginIT_2++;
                        solve.push_back(*beginIT_2);
                        return CardCombo(solve.begin(),solve.end());
                    }
                    if(solve.size()!=0)
                        return CardCombo(solve.begin(),solve.end());
                }
                else
                {
                    int tmp_cards=0;
                    CARD_ITERATOR beginIT = begin;
                    for(int i = 0;i<MAX_LEVEL-3;++i)
                    {

                        if(MyCounts[i]!=3)
                            beginIT=plusplus(beginIT,MyCounts[i]);
                        else
                        {
                            int tmp_max=1;
                            for(int j=i+1;j<MAX_LEVEL-3;++j){
                                if(MyCounts[j]==3)
                                    tmp_max++;
                                else
                                    break;
                            }
                            if(tmp_max>=2)
                            {


                                for(int i=0;i<6;i++)
                                {
                                    solve.push_back(*beginIT);
                                    beginIT++;
                                }
                                //三代一
                                if(MyCountOfCount[1]>=2)
                                {
                                    int num=0;
                                    CARD_ITERATOR beginIT_1 = begin;
                                    for(int i=0;i<MAX_LEVEL-3;i++)
                                    {
                                        if(MyCounts[i]==1) {
                                            num++;
                                            solve.push_back(*beginIT_1);
                                        }
                                        if(num==2)break;
                                        beginIT_1=plusplus(beginIT_1,MyCounts[i]);
                                    }
                                    return CardCombo(solve.begin(),solve.end());
                                }
                                //三代二
                                if(MyCountOfCount[2])
                                {
                                    CARD_ITERATOR beginIT_2 = begin;
                                    for(int i=0;i<MAX_LEVEL-3;i++)
                                    {
                                        if(MyCounts[i]==2) break;
                                        beginIT_2=plusplus(beginIT_2,MyCounts[i]);
                                    }
                                    solve.push_back(*beginIT_2);
                                    beginIT_2++;
                                    solve.push_back(*beginIT_2);
                                    return CardCombo(solve.begin(),solve.end());
                                }
                                if(solve.size()!=0)
                                    return CardCombo(solve.begin(),solve.end());


                            }
                            else
                            {
                                CARD_ITERATOR beginIT = begin;
                                for(int i=0;i<MAX_LEVEL-3;i++)
                                {
                                    if(MyCounts[i]==3)
                                        break;
                                    beginIT=plusplus(beginIT, MyCounts[i]);
                                }
                                for(int i=0;i<3;i++)
                                {
                                    solve.push_back(*beginIT);
                                    beginIT++;
                                }
                                //三代一
                                if(MyCountOfCount[1])
                                {
                                    CARD_ITERATOR beginIT_1 = begin;
                                    for(int i=0;i<MAX_LEVEL-3;i++)
                                    {
                                        if(MyCounts[i]==1) break;
                                        beginIT_1=plusplus(beginIT_1,MyCounts[i]);
                                    }
                                    solve.push_back(*beginIT_1);
                                    return CardCombo(solve.begin(),solve.end());
                                }
                                //三代二
                                if(MyCountOfCount[2])
                                {
                                    CARD_ITERATOR beginIT_2 = begin;
                                    for(int i=0;i<MAX_LEVEL-3;i++)
                                    {
                                        if(MyCounts[i]==2) break;
                                        beginIT_2=plusplus(beginIT_2,MyCounts[i]);
                                    }
                                    solve.push_back(*beginIT_2);
                                    beginIT_2++;
                                    solve.push_back(*beginIT_2);
                                    return CardCombo(solve.begin(),solve.end());
                                }
                                if(solve.size()!=0)
                                    return CardCombo(solve.begin(),solve.end());
                            }
                            tmp_cards+=MyCounts[i];
                        }

                    }

                }
            }
            //如果有单牌
            if(MyCountOfCount[1]){
                CARD_ITERATOR beginIT = begin;

                if(MyCountOfCount[1]<5||MyCombo.findMaxSeq()<5||MyCountOfCount[1]<MyCombo.findMaxSeq()){//单张<5
                    bool flag=false;
                    for(int i  = 0;i < MAX_LEVEL;++i)
                    {
                        if(MyCounts[i]==1){break;}
                        int _i = MyCounts[i];
                        while(_i--){
                            beginIT++;
                        }
                        if(MyDeck.size()>8 && i>8)
                        {
                            flag=true;
                            break;
                        }


                    }
                    if(!flag){
                        CARD_ITERATOR tmpIT = beginIT;
                        tmpIT++;
                        return CardCombo(beginIT,tmpIT);
                    }
                }
                else{
                    int tmp_cards=0;
                    for(int i = 0;i<MAX_LEVEL-8;++i){
                        tmp_cards+=MyCounts[i];
                        if(MyCounts[i]==1){
                            int tmp_max=1;
                            for(int j=i+1;j<MAX_LEVEL-3;++j){
                                if(MyCounts[j]==1)
                                    tmp_max++;
                                else
                                    break;
                            }
                            if(tmp_max>=5){
                                //>5出顺子
                                CARD_ITERATOR tmpBegin=plusplus(begin, tmp_cards);
                                CARD_ITERATOR tmpEnd=plusplus(tmpBegin, tmp_max);
                                return CardCombo(tmpBegin,tmpEnd);
                            }
                            else
                            {
                                //否则出第一张最小的单牌
                                CARD_ITERATOR tmpBegin=plusplus(begin, tmp_cards);
                                CARD_ITERATOR second=tmpBegin;
                                second++;
                                return CardCombo(tmpBegin,second);
                            }
                        }
                    }
                }
            }

            //如果有对子
            if(MyCountOfCount[2])
            {
                CARD_ITERATOR beginIT = begin;
                if(MyCountOfCount[2]<3)   //如果没有连对
                {
                    for(int i  = 0;i < MAX_LEVEL;++i)
                    {
                        if(MyCounts[i]==2){break;}
                        beginIT = plusplus(beginIT, MyCounts[i]);
                    }
                    CARD_ITERATOR tmpIT = beginIT;
                    tmpIT++;
                    tmpIT++;
                    return CardCombo(beginIT,tmpIT);
                }
                else
                {
                    int tmp_cards=0;
                    for(int i = 0;i<MAX_LEVEL-8;++i){

                        if(MyCounts[i]==2){
                            int tmp_max=1;
                            for(int j=i+1;j<MAX_LEVEL-3;++j){
                                if(MyCounts[j]==2)
                                    tmp_max++;
                                else
                                    break;
                            }
                            if(tmp_max>=3){
                                CARD_ITERATOR tmpBegin=plusplus(begin, tmp_cards);
                                CARD_ITERATOR tmpEnd=plusplus(tmpBegin, tmp_max*2);
                                return CardCombo(tmpBegin,tmpEnd);
                            }
                            else
                            {
                                CARD_ITERATOR tmpBegin=plusplus(begin, tmp_cards);
                                CARD_ITERATOR second=tmpBegin;
                                second++;
                                second++;
                                return CardCombo(tmpBegin,second);
                            }
                        }
                        tmp_cards+=MyCounts[i];
                    }
                }
            }
            else
            {
                CARD_ITERATOR second=begin;
                second++;
                return CardCombo(begin,second);
            }

        }

        // 然后先看一下是不是火箭,是的话就过
        if (comboType == CardComboType::ROCKET)
            return CardCombo();

        // 现在打算从手牌中凑出同牌型的牌
        auto deck = vector<Card>(begin, end); // 手牌
        short counts[MAX_LEVEL + 1] = {};

        unsigned short kindCount = 0;

        // 先数一下手牌里每种牌有多少个
        for (Card c : deck)
            counts[card2level(c)]++;

        // 手牌如果不够用,直接不用凑了,看看能不能炸吧
        if (deck.size() < cards.size())//如果手牌数目小于对方出牌数目
            goto failure;

        // 再数一下手牌里有多少种牌
        for (short c : counts)
            if (c)
                kindCount++;
        if(comboType== CardComboType::SINGLE)
        {
            CARD_ITERATOR begin_s=begin;
            for(int i=0;i<MAX_LEVEL;i++)
            {
                if(i>packs[0].level && counts[i]==1)
                {
                    if(i==13 && counts[13]==1 && counts[14]==1)
                    {
                        return CardCombo();
                    }
                    else
                    {
                        CARD_ITERATOR second_s=begin_s;
                        second_s++;
                        return CardCombo(begin_s,second_s);
                    }
                }
                begin_s=plusplus(begin_s,counts[i]);

            }

            CARD_ITERATOR begin_d=begin;
            for(int i=0;i<MAX_LEVEL;i++)
            {
                if(i>packs[0].level && counts[i]!=4 && counts[i]!=0)

                {
                    CARD_ITERATOR end_d=begin_d;
                    end_d++;
                    return CardCombo(begin_d,end_d);
                }
                begin_d=plusplus(begin_d, counts[i]);
            }

            return CardCombo();
        }
        // 否则不断增大当前牌组的主牌,看看能不能找到匹配的牌组

        {
            // 开始增大主牌
            int mainPackCount = findMaxSeq();
            bool isSequential =
                    comboType == CardComboType::STRAIGHT ||
                    comboType == CardComboType::STRAIGHT2 ||
                    comboType == CardComboType::PLANE ||
                    comboType == CardComboType::PLANE1 ||
                    comboType == CardComboType::PLANE2 ||
                    comboType == CardComboType::SSHUTTLE ||
                    comboType == CardComboType::SSHUTTLE2 ||
                    comboType == CardComboType::SSHUTTLE4;
            for (Level i = 1; ; i++) // 增大多少
            {
                for (int j = 0; j < mainPackCount; j++)
                {
                    int level = packs[j].level + i;

                    // 各种连续牌型的主牌不能到2,非连续牌型的主牌不能到小王,单张的主牌不能超过大王
                    if ((comboType == CardComboType::SINGLE && level > MAX_LEVEL) ||
                        (isSequential && level > MAX_STRAIGHT_LEVEL) ||
                        (comboType != CardComboType::SINGLE && !isSequential && level >= level_joker))
                        goto failure;

                    // 如果手牌中这种牌不够,就不用继续增了
                    if (counts[level] < packs[j].count)
                        goto next;
                }

                {
                    // 找到了合适的主牌,那么从牌呢?
                    // 如果手牌的种类数不够,那从牌的种类数就不够,也不行
                    if (kindCount < packs.size())
                        continue;

                    // 好终于可以了
                    // 计算每种牌的要求数目吧
                    short requiredCounts[MAX_LEVEL + 1] = {};
                    for (int j = 0; j < mainPackCount; j++)
                        requiredCounts[packs[j].level + i] = packs[j].count;
                    for (unsigned j = mainPackCount; j < packs.size(); j++)
                    {
                        Level k;
                        for (k = 0; k <= MAX_LEVEL; k++)
                        {
                            if (requiredCounts[k] || counts[k] < packs[j].count)
                                continue;
                            requiredCounts[k] = packs[j].count;
                            break;
                        }
                        if (k == MAX_LEVEL + 1) // 如果是都不符合要求……就不行了
                            goto next;
                    }


                    // 开始产生解
                    vector<Card> solve;
                    for (Card c : deck)
                    {
                        Level level = card2level(c);
                        if (requiredCounts[level])
                        {
                            solve.push_back(c);
                            requiredCounts[level]--;
                        }
                    }
                    return CardCombo(solve.begin(), solve.end());
                }

                next:
                ; // 再增大
            }
        }

        failure:
        // 实在找不到啊
        // 最后看一下能不能炸吧

        for (Level i = 0; i < level_joker; i++)
            if (counts[i] == 4 && (comboType != CardComboType::BOMB || i > packs[0].level)) // 如果对方是炸弹,能炸的过才行
            {
                // 还真可以啊……
                Card bomb[] = { Card(i * 4), Card(i * 4 + 1), Card(i * 4 + 2), Card(i * 4 + 3) };
                return CardCombo(bomb, bomb + 4);
            }

        // 有没有火箭?
        if (counts[level_joker] + counts[level_JOKER] == 2)
        {
            Card rocket[] = { card_joker, card_JOKER };
            return CardCombo(rocket, rocket + 2);
        }

        // ……
        return CardCombo();
    }

    void debugPrint()
    {
#ifndef _BOTZONE_ONLINE
        std::cout << "" << cardComboStrings[(int)comboType] <<
                  "" << cards.size() << "张,大小序" << comboLevel << "";
#endif
    }
};


// 当前要出的牌需要大过谁
CardCombo lastValidCombo;


namespace BotzoneIO
{
    using namespace std;
    void input()
    {
        // 读入输入(平台上的输入是单行)
        string line;
        getline(cin, line);
        Json::Value input;
        Json::Reader reader;
        reader.parse(line, input);

        // 首先处理第一回合,得知自己是谁、有哪些牌
        {
            auto firstRequest = input["requests"][0u]; // 下标需要是 unsigned,可以通过在数字后面加u来做到
            auto own = firstRequest["own"];
            auto llpublic = firstRequest["public"];
            auto history = firstRequest["history"];
            for (unsigned i = 0; i < own.size(); i++)
                myCards.insert(own[i].asInt());
            for (unsigned i = 0; i < llpublic.size(); i++)
                landlordPublicCards.insert(llpublic[i].asInt());
            if (history[0u].size() == 0)
                if (history[1].size() == 0)
                    myPosition = 0; // 上上家和上家都没出牌,说明是地主
                else
                    myPosition = 1; // 上上家没出牌,但是上家出牌了,说明是农民甲
            else
                myPosition = 2; // 上上家出牌了,说明是农民乙
        }

        // history里第一项(上上家)和第二项(上家)分别是谁的决策
        int whoInHistory[] = { (myPosition - 2 + PLAYER_COUNT) % PLAYER_COUNT, (myPosition - 1 + PLAYER_COUNT) % PLAYER_COUNT };

        int turn = input["requests"].size();
        for (int i = 0; i < turn; i++)
        {
            // 逐次恢复局面到当前
            auto history = input["requests"][i]["history"]; // 每个历史中有上家和上上家出的牌
            int howManyPass = 0;
            for (int p = 0; p < 2; p++)
            {
                int player = whoInHistory[p]; // 是谁出的牌
                auto playerAction = history[p]; // 出的哪些牌
                vector<Card> playedCards;
                for (unsigned _ = 0; _ < playerAction.size(); _++) // 循环枚举这个人出的所有牌
                {
                    int card = playerAction[_].asInt(); // 这里是出的一张牌
                    playedCards.push_back(card);
                }
                whatTheyPlayed[player].push_back(playedCards); // 记录这段历史
                cardRemaining[player] -= playerAction.size();

                if (playerAction.size() == 0)
                    howManyPass++;
                else
                    lastValidCombo = CardCombo(playedCards.begin(), playedCards.end());
            }

            if (howManyPass == 2)
                lastValidCombo = CardCombo();

            if (i < turn - 1)
            {
                // 还要恢复自己曾经出过的牌
                auto playerAction = input["responses"][i]; // 出的哪些牌
                vector<Card> playedCards;
                for (unsigned _ = 0; _ < playerAction.size(); _++) // 循环枚举自己出的所有牌
                {
                    int card = playerAction[_].asInt(); // 这里是自己出的一张牌
                    myCards.erase(card); // 从自己手牌中删掉
                    playedCards.push_back(card);
                }
                whatTheyPlayed[myPosition].push_back(playedCards); // 记录这段历史
                cardRemaining[myPosition] -= playerAction.size();
            }
        }
    }

    /**
     * 输出决策,begin是迭代器起点,end是迭代器终点
     * CARD_ITERATOR是Card(即short)类型的迭代器
     */
    template <typename CARD_ITERATOR>
    void output(CARD_ITERATOR begin, CARD_ITERATOR end)
    {
        Json::Value result, response(Json::arrayValue);
        for (; begin != end; begin++)
            response.append(*begin);
        result["response"] = response;

        Json::FastWriter writer;
        cout << writer.write(result) << endl;
    }
}

int main()
{
    BotzoneIO::input();

    // 做出决策(你只需修改以下部分)

    // findFirstValid 函数可以用作修改的起点
    CardCombo myAction = lastValidCombo.findFirstValid(myCards.begin(), myCards.end());

    // 是合法牌
    assert(myAction.comboType != CardComboType::INVALID);

    assert(
    // 在上家没过牌的时候过牌
            (lastValidCombo.comboType != CardComboType::PASS && myAction.comboType == CardComboType::PASS) ||
            // 在上家没过牌的时候出打得过的牌
            (lastValidCombo.comboType != CardComboType::PASS && lastValidCombo.canBeBeatenBy(myAction)) ||
            // 在上家过牌的时候出合法牌
            (lastValidCombo.comboType == CardComboType::PASS && myAction.comboType != CardComboType::INVALID)
    );

    // 决策结束,输出结果(你只需修改以上部分)

    BotzoneIO::output(myAction.cards.begin(), myAction.cards.end());
}

2018.05.16

上传了样例程序。

#include <iostream>
#include <set>
#include <string>
#include <cassert>
#include <cstring> // 注意memset是cstring里的
#include <algorithm>
#include <vector>
#include "jsoncpp/json.h" // 在平台上,C++编译时默认包含此库
//using std::sort;
//using std::unique;
//using std::set;
//using std::string;
using namespace std;
constexpr int PLAYER_COUNT = 3;

enum class CardComboType
{
	PASS, //
	SINGLE, // 单张
	PAIR, // 对子
	STRAIGHT, // 顺子
	STRAIGHT2, // 双顺
	TRIPLET, // 三条
	TRIPLET1, // 三带一
	TRIPLET2, // 三带二
	BOMB, // 炸弹
	QUADRUPLE2, // 四带二(只)
	QUADRUPLE4, // 四带二(对)
	PLANE, // 飞机
	PLANE1, // 飞机带小翼
	PLANE2, // 飞机带大翼
	SSHUTTLE, // 航天飞机
	SSHUTTLE2, // 航天飞机带小翼
	SSHUTTLE4, // 航天飞机带大翼
	ROCKET, // 火箭
	INVALID // 非法牌型
};

int cardComboScores[] = {
	0, //
	1, // 单张
	2, // 对子
	6, // 顺子
	6, // 双顺
	4, // 三条
	4, // 三带一
	4, // 三带二
	10, // 炸弹
	8, // 四带二(只)
	8, // 四带二(对)
	8, // 飞机
	8, // 飞机带小翼
	8, // 飞机带大翼
	10, // 航天飞机(需要特判:二连为10分,多连为20分)
	10, // 航天飞机带小翼
	10, // 航天飞机带大翼
	16, // 火箭
	0 // 非法牌型
};

#ifndef _BOTZONE_ONLINE
string cardComboStrings[] = {
	"PASS",
	"SINGLE",
	"PAIR",
	"STRAIGHT",
	"STRAIGHT2",
	"TRIPLET",
	"TRIPLET1",
	"TRIPLET2",
	"BOMB",
	"QUADRUPLE2",
	"QUADRUPLE4",
	"PLANE",
	"PLANE1",
	"PLANE2",
	"SSHUTTLE",
	"SSHUTTLE2",
	"SSHUTTLE4",
	"ROCKET",
	"INVALID"
};
#endif

// 用0~53这54个整数表示唯一的一张牌
using Card = short;
constexpr Card card_joker = 52;
constexpr Card card_JOKER = 53;

// 除了用0~53这54个整数表示唯一的牌,
// 这里还用另一种序号表示牌的大小(不管花色),以便比较,称作等级(Level)
// 对应关系如下:
// 3 4 5 6 7 8 9 10	J Q K	A	2	小王	大王
// 0 1 2 3 4 5 6  7	8 9 10	11	12	13	14
using Level = short;
constexpr Level MAX_LEVEL = 15;
constexpr Level MAX_STRAIGHT_LEVEL = 11;
constexpr Level level_joker = 13;
constexpr Level level_JOKER = 14;

/**
 * 将Card变成Level
 */
constexpr Level card2level(Card card)
{
	return card / 4 + card / 53;
}

// 牌的组合,用于计算牌型
struct CardCombo
{
	// 表示同等级的牌有多少张
	// 会按个数从大到小、等级从大到小排序
	struct CardPack
	{
		Level level;
		short count;

		bool operator< (const CardPack& b) const
		{
			if (count == b.count)
				return level > b.level;
			return count > b.count;
		}
	};
	vector<Card> cards; // 原始的牌,未排序
	vector<CardPack> packs; // 按数目和大小排序的牌种
	CardComboType comboType; // 算出的牌型
	Level comboLevel = 0; // 算出的大小序

	/**
	 * 检查个数最多的CardPack递减了几个
	 */
	int findMaxSeq() const
	{
		for (unsigned c = 1; c < packs.size(); c++)
			if (packs[c].count != packs[0].count ||
				packs[c].level != packs[c - 1].level - 1)
				return c;
		return packs.size();
	}

	/**
	* 这个牌型最后算总分的时候的权重
	*/
	int getWeight() const
	{
		if (comboType == CardComboType::SSHUTTLE ||
			comboType == CardComboType::SSHUTTLE2 ||
			comboType == CardComboType::SSHUTTLE4)
			return cardComboScores[(int)comboType] + (findMaxSeq() > 2) * 10;
		return cardComboScores[(int)comboType];
	}

	// 创建一个空牌组
	CardCombo() : comboType(CardComboType::PASS) {}

	/**
	 * 通过Card(即short)类型的迭代器创建一个牌型
	 * 并计算出牌型和大小序等
	 * 假设输入没有重复数字(即重复的Card)
	 */
	template <typename CARD_ITERATOR>
	CardCombo(CARD_ITERATOR begin, CARD_ITERATOR end)
	{
		// 特判:空
		if (begin == end)
		{
			comboType = CardComboType::PASS;
			return;
		}

		// 每种牌有多少个
		short counts[MAX_LEVEL + 1] = {};

		// 同种牌的张数(有多少个单张、对子、三条、四条)
		short countOfCount[5] = {};

		cards = vector<Card>(begin, end);
		for (Card c : cards)
			counts[card2level(c)]++;
		for (Level l = 0; l <= MAX_LEVEL; l++)
			if (counts[l])
			{
				packs.push_back(CardPack{ l, counts[l] });
				countOfCount[counts[l]]++;
			}
		sort(packs.begin(), packs.end());

		// 用最多的那种牌总是可以比较大小的
		comboLevel = packs[0].level;

		// 计算牌型
		// 按照 同种牌的张数 有几种 进行分类
		vector<int> kindOfCountOfCount;
		for (int i = 0; i <= 4; i++)
			if (countOfCount[i])
				kindOfCountOfCount.push_back(i);
		sort(kindOfCountOfCount.begin(), kindOfCountOfCount.end());

		int curr, lesser;

		switch (kindOfCountOfCount.size())
		{
		case 1: // 只有一类牌
			curr = countOfCount[kindOfCountOfCount[0]];
			switch (kindOfCountOfCount[0])
			{
			case 1:
				// 只有若干单张
				if (curr == 1)
				{
					comboType = CardComboType::SINGLE;
					return;
				}
				if (curr == 2 && packs[1].level == level_joker)
				{
					comboType = CardComboType::ROCKET;
					return;
				}
				if (curr >= 5 && findMaxSeq() == curr &&
					packs.begin()->level <= MAX_STRAIGHT_LEVEL)
				{
					comboType = CardComboType::STRAIGHT;
					return;
				}
				break;
			case 2:
				// 只有若干对子
				if (curr == 1)
				{
					comboType = CardComboType::PAIR;
					return;
				}
				if (curr >= 3 && findMaxSeq() == curr &&
					packs.begin()->level <= MAX_STRAIGHT_LEVEL)
				{
					comboType = CardComboType::STRAIGHT2;
					return;
				}
				break;
			case 3:
				// 只有若干三条
				if (curr == 1)
				{
					comboType = CardComboType::TRIPLET;
					return;
				}
				if (findMaxSeq() == curr &&
					packs.begin()->level <= MAX_STRAIGHT_LEVEL)
				{
					comboType = CardComboType::PLANE;
					return;
				}
				break;
			case 4:
				// 只有若干四条
				if (curr == 1)
				{
					comboType = CardComboType::BOMB;
					return;
				}
				if (findMaxSeq() == curr &&
					packs.begin()->level <= MAX_STRAIGHT_LEVEL)
				{
					comboType = CardComboType::SSHUTTLE;
					return;
				}
			}
			break;
		case 2: // 有两类牌
			curr = countOfCount[kindOfCountOfCount[1]];
			lesser = countOfCount[kindOfCountOfCount[0]];
			if (kindOfCountOfCount[1] == 3)
			{
				// 三条带?
				if (kindOfCountOfCount[0] == 1)
				{
					// 三带一
					if (curr == 1 && lesser == 1)
					{
						comboType = CardComboType::TRIPLET1;
						return;
					}
					if (findMaxSeq() == curr && lesser == curr &&
						packs.begin()->level <= MAX_STRAIGHT_LEVEL)
					{
						comboType = CardComboType::PLANE1;
						return;
					}
				}
				if (kindOfCountOfCount[0] == 2)
				{
					// 三带二
					if (curr == 1 && lesser == 1)
					{
						comboType = CardComboType::TRIPLET2;
						return;
					}
					if (findMaxSeq() == curr && lesser == curr &&
						packs.begin()->level <= MAX_STRAIGHT_LEVEL)
					{
						comboType = CardComboType::PLANE2;
						return;
					}
				}
			}
			if (kindOfCountOfCount[1] == 4)
			{
				// 四条带?
				if (kindOfCountOfCount[0] == 1)
				{
					// 四条带两只 * n
					if (curr == 1 && lesser == 2)
					{
						comboType = CardComboType::QUADRUPLE2;
						return;
					}
					if (findMaxSeq() == curr && lesser == curr * 2 &&
						packs.begin()->level <= MAX_STRAIGHT_LEVEL)
					{
						comboType = CardComboType::SSHUTTLE2;
						return;
					}
				}
				if (kindOfCountOfCount[0] == 2)
				{
					// 四条带两对 * n
					if (curr == 1 && lesser == 2)
					{
						comboType = CardComboType::QUADRUPLE4;
						return;
					}
					if (findMaxSeq() == curr && lesser == curr * 2 &&
						packs.begin()->level <= MAX_STRAIGHT_LEVEL)
					{
						comboType = CardComboType::SSHUTTLE4;
						return;
					}
				}
			}
		}

		comboType = CardComboType::INVALID;
	}

	/**
	 * 判断指定牌组能否大过当前牌组(这个函数不考虑过牌的情况!)
	 */
	bool canBeBeatenBy(const CardCombo& b) const
	{
		if (comboType == CardComboType::INVALID || b.comboType == CardComboType::INVALID)
			return false;
		if (b.comboType == CardComboType::ROCKET)
			return true;
		if (b.comboType == CardComboType::BOMB)
			switch (comboType)
			{
			case CardComboType::ROCKET:
				return false;
			case CardComboType::BOMB:
				return b.comboLevel > comboLevel;
			default:
				return true;
			}
		return b.comboType == comboType && b.cards.size() == cards.size() && b.comboLevel > comboLevel;
	}

	/**
	 * 从指定手牌中寻找第一个能大过当前牌组的牌组
	 * 如果随便出的话只出第一张
	 * 如果不存在则返回一个PASS的牌组
	 */
	template <typename CARD_ITERATOR>
	CardCombo findFirstValid(CARD_ITERATOR begin, CARD_ITERATOR end) const
	{
		if (comboType == CardComboType::PASS) // 如果不需要大过谁,只需要随便出
		{
			CARD_ITERATOR second = begin;
			second++;
			return CardCombo(begin, second); // 那么就出第一张牌……
		}

		// 然后先看一下是不是火箭,是的话就过
		if (comboType == CardComboType::ROCKET)
			return CardCombo();

		// 现在打算从手牌中凑出同牌型的牌
		auto deck = vector<Card>(begin, end); // 手牌
		short counts[MAX_LEVEL + 1] = {};

		unsigned short kindCount = 0;

		// 先数一下手牌里每种牌有多少个
		for (Card c : deck)
			counts[card2level(c)]++;

		// 手牌如果不够用,直接不用凑了,看看能不能炸吧
		if (deck.size() < cards.size())
			goto failure;

		// 再数一下手牌里有多少种牌
		for (short c : counts)
			if (c)
				kindCount++;

		// 否则不断增大当前牌组的主牌,看看能不能找到匹配的牌组
		{
			// 开始增大主牌
			int mainPackCount = findMaxSeq();
			bool isSequential =
				comboType == CardComboType::STRAIGHT ||
				comboType == CardComboType::STRAIGHT2 ||
				comboType == CardComboType::PLANE ||
				comboType == CardComboType::PLANE1 ||
				comboType == CardComboType::PLANE2 ||
				comboType == CardComboType::SSHUTTLE ||
				comboType == CardComboType::SSHUTTLE2 ||
				comboType == CardComboType::SSHUTTLE4;
			for (Level i = 1; ; i++) // 增大多少
			{
				for (int j = 0; j < mainPackCount; j++)
				{
					int level = packs[j].level + i;

					// 各种连续牌型的主牌不能到2,非连续牌型的主牌不能到小王,单张的主牌不能超过大王
					if ((comboType == CardComboType::SINGLE && level > MAX_LEVEL) ||
						(isSequential && level > MAX_STRAIGHT_LEVEL) ||
						(comboType != CardComboType::SINGLE && !isSequential && level >= level_joker))
						goto failure;

					// 如果手牌中这种牌不够,就不用继续增了
					if (counts[level] < packs[j].count)
						goto next;
				}

				{
					// 找到了合适的主牌,那么从牌呢?
					// 如果手牌的种类数不够,那从牌的种类数就不够,也不行
					if (kindCount < packs.size())
						continue;

					// 好终于可以了
					// 计算每种牌的要求数目吧
					short requiredCounts[MAX_LEVEL + 1] = {};
					for (int j = 0; j < mainPackCount; j++)
						requiredCounts[packs[j].level + i] = packs[j].count;
					for (unsigned j = mainPackCount; j < packs.size(); j++)
					{
						Level k;
						for (k = 0; k <= MAX_LEVEL; k++)
						{
							if (requiredCounts[k] || counts[k] < packs[j].count)
								continue;
							requiredCounts[k] = packs[j].count;
							break;
						}
						if (k == MAX_LEVEL + 1) // 如果是都不符合要求……就不行了
							goto next;
					}


					// 开始产生解
					vector<Card> solve;
					for (Card c : deck)
					{
						Level level = card2level(c);
						if (requiredCounts[level])
						{
							solve.push_back(c);
							requiredCounts[level]--;
						}
					}
					return CardCombo(solve.begin(), solve.end());
				}

			next:
				; // 再增大
			}
		}

	failure:
		// 实在找不到啊
		// 最后看一下能不能炸吧

		for (Level i = 0; i < level_joker; i++)
			if (counts[i] == 4 && (comboType != CardComboType::BOMB || i > packs[0].level)) // 如果对方是炸弹,能炸的过才行
			{
				// 还真可以啊……
				Card bomb[] = { Card(i * 4), Card(i * 4 + 1), Card(i * 4 + 2), Card(i * 4 + 3) };
				return CardCombo(bomb, bomb + 4);
			}

		// 有没有火箭?
		if (counts[level_joker] + counts[level_JOKER] == 2)
		{
			Card rocket[] = { card_joker, card_JOKER };
			return CardCombo(rocket, rocket + 2);
		}

		// ……
		return CardCombo();
	}

	void debugPrint()
	{
#ifndef _BOTZONE_ONLINE
		std::cout << "" << cardComboStrings[(int)comboType] <<
			"" << cards.size() << "张,大小序" << comboLevel << "";
#endif
	}
};

// 我的牌有哪些
set<Card> myCards;

// 地主被明示的牌有哪些
set<Card> landlordPublicCards;

// 大家从最开始到现在都出过什么
vector<vector<Card>> whatTheyPlayed[PLAYER_COUNT];

// 当前要出的牌需要大过谁
CardCombo lastValidCombo;

// 大家还剩多少牌
short cardRemaining[PLAYER_COUNT] = { 20, 17, 17 };

// 我是几号玩家(0-地主,1-农民甲,2-农民乙)
int myPosition;

namespace BotzoneIO
{
	using namespace std;
	void input()
	{
		// 读入输入(平台上的输入是单行)
		string line;
		getline(cin, line);
		Json::Value input;
		Json::Reader reader;
		reader.parse(line, input);

		// 首先处理第一回合,得知自己是谁、有哪些牌
		{
			auto firstRequest = input["requests"][0u]; // 下标需要是 unsigned,可以通过在数字后面加u来做到
			auto own = firstRequest["own"];
			auto llpublic = firstRequest["public"];
			auto history = firstRequest["history"];
			for (unsigned i = 0; i < own.size(); i++)
				myCards.insert(own[i].asInt());
			for (unsigned i = 0; i < llpublic.size(); i++)
				landlordPublicCards.insert(llpublic[i].asInt());
			if (history[0u].size() == 0)
				if (history[1].size() == 0)
					myPosition = 0; // 上上家和上家都没出牌,说明是地主
				else
					myPosition = 1; // 上上家没出牌,但是上家出牌了,说明是农民甲
			else
				myPosition = 2; // 上上家出牌了,说明是农民乙
		}

		// history里第一项(上上家)和第二项(上家)分别是谁的决策
		int whoInHistory[] = { (myPosition - 2 + PLAYER_COUNT) % PLAYER_COUNT, (myPosition - 1 + PLAYER_COUNT) % PLAYER_COUNT };

		int turn = input["requests"].size();
		for (int i = 0; i < turn; i++)
		{
			// 逐次恢复局面到当前
			auto history = input["requests"][i]["history"]; // 每个历史中有上家和上上家出的牌
			int howManyPass = 0;
			for (int p = 0; p < 2; p++)
			{
				int player = whoInHistory[p]; // 是谁出的牌
				auto playerAction = history[p]; // 出的哪些牌
				vector<Card> playedCards;
				for (unsigned _ = 0; _ < playerAction.size(); _++) // 循环枚举这个人出的所有牌
				{
					int card = playerAction[_].asInt(); // 这里是出的一张牌
					playedCards.push_back(card);
				}
				whatTheyPlayed[player].push_back(playedCards); // 记录这段历史
				cardRemaining[player] -= playerAction.size();

				if (playerAction.size() == 0)
					howManyPass++;
				else
					lastValidCombo = CardCombo(playedCards.begin(), playedCards.end());
			}

			if (howManyPass == 2)
				lastValidCombo = CardCombo();

			if (i < turn - 1)
			{
				// 还要恢复自己曾经出过的牌
				auto playerAction = input["responses"][i]; // 出的哪些牌
				vector<Card> playedCards;
				for (unsigned _ = 0; _ < playerAction.size(); _++) // 循环枚举自己出的所有牌
				{
					int card = playerAction[_].asInt(); // 这里是自己出的一张牌
					myCards.erase(card); // 从自己手牌中删掉
					playedCards.push_back(card);
				}
				whatTheyPlayed[myPosition].push_back(playedCards); // 记录这段历史
				cardRemaining[myPosition] -= playerAction.size();
			}
		}
	}

	/**
	 * 输出决策,begin是迭代器起点,end是迭代器终点
	 * CARD_ITERATOR是Card(即short)类型的迭代器
	 */
	template <typename CARD_ITERATOR>
	void output(CARD_ITERATOR begin, CARD_ITERATOR end)
	{
		Json::Value result, response(Json::arrayValue);
		for (; begin != end; begin++)
			response.append(*begin);
		result["response"] = response;

		Json::FastWriter writer;
		cout << writer.write(result) << endl;
	}
}

int main()
{
	BotzoneIO::input();

	// 做出决策(你只需修改以下部分)

	// findFirstValid 函数可以用作修改的起点
	CardCombo myAction = lastValidCombo.findFirstValid(myCards.begin(), myCards.end());

	// 是合法牌
	assert(myAction.comboType != CardComboType::INVALID);

	assert(
		// 在上家没过牌的时候过牌
		(lastValidCombo.comboType != CardComboType::PASS && myAction.comboType == CardComboType::PASS) ||
		// 在上家没过牌的时候出打得过的牌
		(lastValidCombo.comboType != CardComboType::PASS && lastValidCombo.canBeBeatenBy(myAction)) ||
		// 在上家过牌的时候出合法牌
		(lastValidCombo.comboType == CardComboType::PASS && myAction.comboType != CardComboType::INVALID)
	);

	// 决策结束,输出结果(你只需修改以上部分)

	BotzoneIO::output(myAction.cards.begin(), myAction.cards.end());
}

About

In C++

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 100.0%