2015華爲軟賽(八)——動作二

點滴記錄總結,一天一打雞血。

2015年5月華爲組織了一次軟件精英挑戰賽,賽題是德州撲克手牌AI~

環境及測試說明:http://pan.baidu.com/s/1dD2dL0P

最後一節吧,真心覺得貼代碼沒意思,反正自己不會去看代碼了,只想把中間一些感觸寫下來,時間一長加上一忙,感覺找不到了。這時候的感觸是,有貨趁早寫,別拿忙開脫,就是懶!這一節先別貼代碼,來點雞湯解渴先~

在能玩牌的基礎上,想玩好可不太簡單,特別是程序本身就是死的,這就需要策略具備一定靈活性,說到這就不由自主往機器學習上靠,其實沒那麼複雜,由於每次遊戲有上限600局,加上決策時間有限500ms,使得機器學習在這裏很難湊效的。但是,策略模型是要的,對手模型也是要的。這兩個,很重要,你可以ifelse壘起來,儘管效率不太高;也可以基於一些比較成熟的算法模型,這樣最好,但是需要理論基礎了。

你的策略會綜合很多指標,比如籌碼數、玩家數、跟注額、座次順序等,大部分玩家都是在這一點下足功夫了,因爲這樣簡單高效。至於對手模型,我個人覺得這纔是高端玩家的分水嶺,像馬雲說的,其他不重要,瞭解人需求最重要,由於大部分玩家程序比較刻板,這給建立對手模型帶來契機,當知道對手套路,加註棄牌收放自如。比賽中真看到的,有這樣的人。賽後還調侃,打個牌都算,還怎麼玩。。。

寫到這打住吧,說說我的響應動作。在HOLD圈,一般不會出現隨便跟注的情況,要麼自己是大盲注(要咋唬),要麼就是拿大牌,就加註,一般不會跟注,除非對手加註金額比較高。在之後的圈,就判斷自己是否是咋唬,咋唬一套,非咋唬一套,總之只要自己加了,就不會輕易棄牌。設定加註滿足一定條件就棄牌的策略,這樣真的不好,初賽看這樣的比賽真是虐心。。。
給出HOLD圈的正常代碼吧:

char* HoldOne() {
    float p = Uniform();
    int card[2] = {0};
    card[0] = gameInfo.card[0] % 14;    
    card[1] = gameInfo.card[1] % 14;

    int pairs = 0;  
    if (card[0] == card[1])
        pairs = card[0];

    int len = strlen(opponent.bigid);
    if (pairs >= 11) {
        bigcall = 0;
        if (gameInfo.total_call > 420)
            return "check";
        else if (gameInfo.total_call > 300)
            return Raise(3);
        else if (gameInfo.total_call > 120)
            return Raise(4);
        return Raise(8);
    }


    if (pairs >= 8) {
        if (len > 0) {
            bigcall = 1;
            return Raise(2);
        }
        if (gameInfo.total_call < 125)
            return Raise(3);
        else if (gameInfo.total_call < 200)
            return Raise(2);
        return "check";
    }


    if (card[0] >=11 && card[1] >= 11) {
        if (len > 0) {
            bigcall = 1;
            return Raise(2);
        }
        if (gameInfo.total_call < 125)
            return Raise(3);
        else if (gameInfo.total_call < 200)
            return Raise(2);
        return "check";
    }

    return FoldDecision();

}

最後有個FoldDecision(),這樣寫的好處之前說過,此外,還可以判斷自己是否第一個出牌,第一個就可以讓牌,沒必要棄牌的。
下面給出RIVER圈的代碼:

char*   RiverOne(int detaCall) {

    float p = Uniform();
    int card[7] = {0};
    card[0] = gameInfo.card[0] % 14;
    card[1] = gameInfo.card[1] % 14;
    card[2] = common_cards[0] % 14;
    card[3] = common_cards[1] % 14;
    card[4] = common_cards[2] % 14;
    card[5] = common_cards[3] % 14;
    card[6] = common_cards[4] % 14;
    int max_card = Max(Max(Max(card[2], card[3]), Max(card[4], card[5])), card[6]);

    if (cardType.my_type >= FOUR)//straight four
    {
        if (cardType.four.com > 0) 
            return ComFourDecision();

        if (detaCall < 80)
            return Raise(3);
        else if (detaCall <= 200)
            return Raise(2);
        return  "check";
    }
    else if (cardType.my_type == FULLHOUSE)//fullhouse
    {
        return FullHouseDecision(card, detaCall);
    }
    else if (cardType.my_type >= STRAIGHT) //s_card.flush
    {
        if (HasComPair(game_circle+2) >= 2) {
            if (detaCall <= 120)
                return "check";
            return FoldDecision();
        }
        if (cardType.s_card.own == 5) {
            if (cardType.s_card.com <= 3) {
                if (detaCall < 80)
                    return Raise(3);
                else if (detaCall <= 200)
                    return Raise(2);
                return  "check";
            }
            return "check";
        }
        if (cardType.f_card.own == 5) {
            if (cardType.s_card.com <= 3) {
                if (detaCall < 80)
                    return Raise(3);
                else if (detaCall <= 200)
                    return Raise(2);
                return  "check";

            }
            return "check";
        }
    }

    if (cardType.s_card.com >= 4 || cardType.f_card.com >= 4) 
        if (detaCall > 120)
            return FoldDecision();


    if (cardType.my_type == THREE) {//three
        if (card[0] == cardType.three || card[1] == cardType.three) {

            if (detaCall < 70)
                return Raise(3);
            else if (detaCall <= 120)
                return Raise(2);
            return  "check";
        }
        if (card[0] >= 12 || card[1] >= 12) {
            if (detaCall < 240)
                return "check";
            return FoldDecision();
        }
        if (detaCall > 100)
            return FoldDecision();
        return FoldDecision();
    }
    //under TwoPairDecision
    return TwoPairDecision(card, detaCall, max_card);

    return FoldDecision();

}

上面有個TwoPairDecision(card, detaCall, max_card);這樣寫的好處是提高代碼複用率了,因爲後面三個押注圈都會有這樣的策略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章