ชนะการแข่งขันฟันดาบเสมือน (เทียบกับเพื่อนแลกเปลี่ยนของคุณ)


16

คำเตือน: นี่เป็นปัญหาที่ค่อนข้างซับซ้อนในรูปแบบการต่อสู้แบบ king-of-the-hill พร้อมกับการสุ่มเพิ่มรหัสที่ดีที่สุดอาจไม่ชนะเสมอไป โปรดอ่านกฎทั้งหมดให้ครบถ้วนเนื่องจากค่อนข้างซับซ้อน!

FLAVOR TEXT

บิลและสตีฟตัดสินใจที่จะมีการดวลแบบ "เป็นมิตร" แต่การมีคนรวยและชาญฉลาดมากจึงตัดสินใจที่จะให้โปรแกรมเมอร์ที่ดีที่สุดของพวกเขาลองส่งรหัสเพื่อเอาชนะซึ่งกันและกัน คุณกำลังพูดว่าโปรแกรมเมอร์

OBJECTIVE

ในการฟันดาบเป้าหมายของคุณคือทำคะแนนความนิยมมากที่สุดกับคู่ต่อสู้ของคุณ

MOVES

รหัสของคุณจะมีตัวเลือก "ย้าย" ดังต่อไปนี้

โจมตี
Parry
บล็อก
Lunge
และ
หัวหน้า
หน้าอก
เท้า

SCORING POINTS

จู่โจมเต้น Parrying 1 แต้ม
Lunging beats Blocking, 1 แต้ม
Parrying Beats Lunging, 1พ้อยท์
Blocking beats จู่โจม, 1 จุด
Lunging เสมอการโจมตีด้วยผู้เล่น lunging ไม่สามารถปิดกั้นหรือปัดป้องในรอบถัดไปและผู้เล่นที่โจมตีไม่สามารถ ที่จะโจมตีหรือแทงรอบต่อไป
การปิดกั้นความสัมพันธ์ปัดป้องด้วยผู้เล่นปัดป้องไม่สามารถปิดกั้นหรือปัดป้องในรอบถัดไปและผู้เล่นปิดกั้นไม่สามารถโจมตีหรือแทงรอบถัดไป

HEIGHT OF ACTION

คุณยังจะเลือก "ความสูง" สำหรับการกระทำของคุณด้วยเหตุนี้ผลลัพธ์ดังกล่าวจะเกิดขึ้นก็ต่อเมื่อความสูงของผู้เล่นทั้งสองนั้นตรงกับความสูงของการโจมตี หากความสูงไม่ตรงกันผู้เล่นทั้งสองอาจไม่เลือกการกระทำเดียวกันอีกต่อไป (ความสูงไม่ถูก จำกัด ) เหมือนกับรอบการผูกก่อนหน้านี้จนกว่าจะมีการทำคะแนนหรือการกระทำทั้ง 4 ได้ถูกกรอกแล้ว มีอีกครั้ง)

CODE REQUIREMENTS

สำหรับแต่ละรอบมันควรกระตุ้นการเคลื่อนที่ของคู่ต่อสู้ในรอบก่อนหน้า (ยกเว้นรอบที่ 1) เปรียบเทียบกับของตัวเองพิจารณาผลลัพธ์ของรอบก่อนหน้าจากนั้นจึงส่งออกหมายเลขรอบถัดไปคะแนนและตัวเลือก / ตำแหน่ง สำหรับรอบนั้น

เช่น:
อินพุต: LC (หน้าอกพุ่ง) เอาท์
พุท: รอบก่อนหน้า: PM เทียบกับคะแนน LC - PM! ตอนนี้คะแนน 2-1 การกระทำสำหรับรอบต่อไปคือ AH (หัวหน้าโจมตี)

WINNER

เกมจะจบลงหลังจาก 50 รอบหรือหลังได้ 3 คะแนน

AGAINST OTHER PLAYERS

คำตอบแรกจะได้รับการรับประกันทันทีที่ชนะตราบใดที่มันทำงานได้จริง / เล่น แต่ละคำตอบจะได้รับการประเมินตามลำดับการโพสต์เทียบกับผู้ชนะก่อนหน้านี้และหากชนะจะได้รับการประกาศให้เป็นผู้ชนะคนใหม่ ฉันถามว่าในขณะที่ชนะหรือรอที่จะแข่งขันคุณจะไม่เปลี่ยนรหัสของคุณ เมื่อพ่ายแพ้คุณจะไม่สามารถแข่งขันเพื่อชิงแชมป์ด้วยภาษาเดียวกันอีกต่อไปคุณอาจส่งคำตอบภาษาอื่น (ต้องแตกต่างกันอย่างมากไม่ต้องใช้รูปแบบของเนื้อหาพื้นฐานเดียวกัน)

ฉันจะพยายามเรียกใช้แต่ละความท้าทายและจะโพสต์ผลลัพธ์ในความคิดเห็นของผู้ชนะและผู้ท้าชิงรวมถึงประกาศผู้ชนะคนใหม่ - เนื่องจากฉันอาจไม่สามารถเรียกใช้ทุกภาษาได้โดยเฉพาะอย่างยิ่งภาษาที่ไม่ชัดเจนบางอย่าง ความช่วยเหลือที่เป็นไปได้ใด ๆ ที่คุณสามารถให้เพื่อให้แน่ใจว่าคำตอบของคุณจะได้รับการพิจารณา ขอขอบคุณ!


1
หมายเหตุ: การกำหนดเป้าหมายอัลกอริทึมผู้ชนะปัจจุบันเพื่อตอบโต้ผู้เล่นนั้นอยู่ในลักษณะของการฟันดาบและนี่คือราชาแห่งเนินเขาดังนั้นการกระทำดังกล่าวไม่เพียง แต่ได้รับอนุญาต แต่ยังได้รับการสนับสนุนด้วย! - พยายามหาวิธีสร้างผลลัพธ์ทำให้งงงวยรหัสของคุณหรือวิธีอื่นในการ "ป้องกัน" ตัวคุณเองและหาวิธีที่ดีที่สุดในการ "โจมตี" รหัสของผู้เล่นอื่น! - โปรด
รักษาความคิดเห็นที่เปิดเผย

พ่ายแพ้ครั้งเดียวหากคุณต้องการให้ข้อมูลเชิงลึกเกี่ยวกับวิธีการทำสิ่งต่าง ๆ ทำไมคุณทำสิ่งต่าง ๆ เช่นในความคิดเห็นหรือแก้ไขคำตอบอย่าลังเลที่จะ ในขณะที่รหัสของคุณอยู่ในบรรทัดอย่างไรก็ตามโปรดอย่าแก้ไข :)
NRGdallas

ตัวอย่างของคุณถูกต้องหรือไม่ ดูเหมือนว่าจะทำให้อินพุต LC เข้าสู่การกระทำของ LM
Peter Taylor

วิธีการเกี่ยวกับการสุ่มในการแก้ปัญหา? การแข่งขันจะต้องกำหนดขึ้นหรือไม่ ถ้าไม่ผู้ตัดสินจะเลือกเมล็ดพันธุ์อย่างไรและจะเล่นเกมกี่รายการระหว่างสองรายการเพียงหนึ่งรายการ การแข่งขัน robocode มักจะมี 10 เพื่อ จำกัด ผลกระทบของโอกาสตาบอด
vsz

3
ฉันไม่ชอบวิธีการออกแบบนี้ ฉันคิดว่าคุณควรจะมีโค้ดเพื่อใช้ในการแข่งขันโดยการรันโปรแกรมที่ส่งมา 2 โปรแกรมถ่ายทอดการเคลื่อนไหวและคำนวณคะแนน โปรแกรมฟันดาบควรพิมพ์การเคลื่อนไหวของพวกเขาเพื่อ stdout และอ่านการเคลื่อนไหวของคู่ต่อสู้ในรูปแบบ stdin
aditsu

คำตอบ:


5

หลาม

กำลังมองหา!

นักรบของฉันรวมเอาความคาดเดาไม่ได้เข้ากับตาที่แหลมเพื่อจุดอ่อนในท่าทางของคู่ต่อสู้ของเขา เขาค่อนข้างมั่นใจว่าเขาจะสามารถกำจัดศัตรูที่ดุดัน แต่ผู้ฝึกสอนของฉัน (ฉัน) อาจล้มเหลวในการคาดการณ์สถานการณ์บางอย่างหรืออาจกังวลมากกว่านี้อาจตีความกฎผิดพลาด (ข้อผิดพลาด !!)

อย่างไรก็ตามฉันใหม่ดังนั้นหวังว่านี่เป็นรูปแบบที่ใช้ได้สำหรับรหัส:

from random import choice, random

def cleverly_pick_move(me_allowed,op_allowed,opp_last_move=None) :
    """ Behold the genius you're up against!
    Pretty much everything else is just flavour text or match rules
    so you'll probably only want to read this...
    """
    heights = ['head','chest','feet']
    rand_choice = lambda a,h : {'type':choice([t for t in a if a[t]]),
                                'height':choice(h)}

    if opp_last_move is None or feeling_like_a_lucky_punk():
        return rand_choice(me_allowed,heights)

    if sum(1 for x in op_allowed if op_allowed[x]) == 3 :
        for i in op_allowed:
            if not op_allowed[i] :
                weakness = i
                break
        return {'type':exploit_weakness(weakness,me_allowed),
                'height':choice(heights)}
    return rand_choice(me_allowed,heights)

def exploit_weakness(weakness,me_allowed) :
    moves = ['attack','parry','lunge','block']
    for i,move in enumerate(moves) :
        if move == weakness :
            if me_allowed[moves[(i+1) % 4]] :
                return moves[(i+1) % 4]
            break
    if me_allowed[weakness] :
        return weakness
    return choice([x for x in me_allowed if me_allowed[x]])

def feeling_like_a_lucky_punk() :
    return random() > 0.8

def main():

    this_round = 1
    opp_last_move = None
    score   = {'myself':0, 'the blaggard':0}
    quips   = ['blaggard', 'fool', 'scum', 'raggamuffin']
    adverbs = ['deftly', 'skillfully', 'gracefully', 'clumsily']

    me_allowed = {'attack':True,'block':True,'lunge':True,'parry':True}
    op_allowed = {'attack':True,'block':True,'lunge':True,'parry':True}

    while (this_round <= 50 and
           all([points < 3 for points in score.values()])) :

        if this_round == 1 :
            move = cleverly_pick_move(me_allowed,op_allowed) 
        else:
            move = cleverly_pick_move(me_allowed,op_allowed,
                                      opp_last_move=opp_last_move)

        print "Our hero %s %ss at the %s's %s" % (
            choice(adverbs),
            move['type'],
            choice(quips),
            move['height']
            )
        print "We await the %s's response..." % choice(quips)
        print "Our hero's move: " + (move['type'][0]+move['height'][0]).upper()

        opp_move = parse_move(raw_input("Opponent's move: "))

        outcome,me_allowed,op_allowed = get_outcome(move,opp_move,me_allowed,
                                                    op_allowed)
        if outcome == 'WIN' :
            print "Our hero pulls off an excellent round!"
            score['myself'] += 1
        elif outcome == 'LOSE' :
            print "Never before have we seen such blatant cheating!"
            score['the blaggard'] += 1
        else :
            print "Our hero is clearly toying with his opponent as he allows \
a drawn round."

        print ("""The score after round %d:\nOur hero:\t%d\nHis opponent:\t%d""" 
                % (this_round, score['myself'], score['the blaggard']))
        opp_last_move = opp_move
        this_round += 1

    print "Match over, surely the victory is mine!"
    print """Final score:\n
             Our hero:\t%d\nOpponent:\t%d""" % (score['myself'],
                                                score['the blaggard'])

    if score['myself'] > score['the blaggard'] :
        print "My victory was inevitable!"
    elif score['myself'] == score['the blaggard'] :
        print "An even match! Huzzar!"
    else :
        print ""    
    return

def reset_allowed(dictionary) :
    return dict((x,True) for x in dictionary)

def get_outcome(mymove,opmove,me_allowed,op_allowed) :
    result = ''

    if not me_allowed[mymove['type']] :
        print "Whoops, I forgot I couldn't do that..."
        result = 'LOSE'

    if not op_allowed[opmove['type']] :
        print "Haha! What a clutz!"
        result = 'WIN'

    if mymove['height'] != opmove['height'] :
        print "The combatants flail at each other with little effect!"
        print "They'll have to try something else next round!"
        result = 'DRAW'

    if mymove['type'] == opmove['type'] :
        if mymove['type'] in ['attack','lunge']:
            print "The combatants' blades clash dramatically!"
        else :
            print "Both combatants take a moment to practice their \
defensive stance..."
        result = 'DRAW'

    if result :
        me_allowed, op_allowed = (reset_allowed(me_allowed),
                                  reset_allowed(op_allowed))
        if mymove['height'] != opmove['height'] :
            me_allowed[mymove['type']] = op_allowed[opmove['type']] = False
        return (result, me_allowed,op_allowed)
    else :
        return compare_attacks(mymove,opmove,me_allowed,op_allowed)

def compare_attacks(mymove,opmove,me_allowed,op_allowed) :
    """
    0 A > P 1
     ^  x  v
    3 B < L 2
    """
    print "Our hero %ss, his opponent %ss!" % (mymove['type'],opmove['type'])

    move_val = {'attack':0,'parry':1,'lunge':2,'block':3}
    result_num = (move_val[opmove['type']] - move_val[mymove['type']]) % 4
    results = ['DRAW','WIN','DRAW','LOSE']

    me_allowed, op_allowed = (reset_allowed(me_allowed),
                              reset_allowed(op_allowed))    
    if result_num == 1 :
        print "Our hero easily outwits his foe! *Huge cheers from crowd*"
        return ('WIN',me_allowed,op_allowed)
    elif result_num == 3 :
        print "Our hero graciously allows his opponent a charity point.\
*A torrent of boos from the crowd*"
        return ('LOSE',me_allowed,op_allowed)
    else:
        # Combatants drew and will have their moves restricted next round.
        if mymove['type'] in ['attack','parry'] :
            me_allowed['attack'] = me_allowed['lunge'] = False
            me_allowed['parry']  = me_allowed['block'] = True
            op_allowed['parry']  = op_allowed['block'] = False
            op_allowed['attack'] = op_allowed['lunge'] = True
        else :
            me_allowed['parry']  = me_allowed['block'] = False
            me_allowed['attack'] = me_allowed['lunge'] = True 
            op_allowed['attack'] = me_allowed['lunge'] = False
            op_allowed['parry']  = op_allowed['block'] = True
        return ('DRAW',me_allowed,op_allowed)

def parse_move(move_string) :
    m_types = {'A':'attack','B':'block','L':'lunge','P':'parry'}
    m_heights = {'C':'chest','H':'head','F':'feet'}

    move_string = move_string.strip().upper()
    if not move_string :
        print "Couldn't understand your input: %s" % move_string
        return parse_move(raw_input("Opponent's move: "))

    if move_string[0] not in m_types :
        move_string = move_string[::-1] 

    try :
        move = {'type':m_types[move_string[0]],
                'height':m_heights[move_string[1]]}
        return move
    except KeyError :
        print "Couldn't understand your input: %s" % move_string
        return parse_move(raw_input("Opponent's move: "))

if __name__ == '__main__' :
    main()

รักข้อความรสชาติ! หวังว่าจะได้รับสิ่งเหล่านี้เพื่อทำมันออกมาที่นี่ในสุดสัปดาห์นี้ น่าเสียดายที่มันใช้เวลานานมากตั้งแต่โพสต์และเพิ่งได้รับแรงฉุดดังนั้นตอนนี้ฉันเตรียมที่จะทำไม่ดี แต่ฉันควรจะมาที่นี่ภายในสองสามวัน!
NRGdallas

1
ไม่ต้องห่วง. บอกตามตรงฉันไม่ได้ตรวจสอบวันที่ของโพสต์ด้านบน คนป่าเถื่อนของ @Arkady ต้องรู้สึกอวดดี / เหงาบนเนินเขาเป็นเวลา 8 สัปดาห์ ฉันจะใช้เพื่อประโยชน์ของฉัน!
ejrb

ฉันจะตรวจสอบเรื่องนี้ในภายหลัง (ฉันไม่มีล่าม Python ที่ทำงาน) และอาจตอบโต้การโจมตีในภายหลัง เป็น "ระวัง" ตามที่พวกเขาอาจพูดในฝรั่งเศส
Arkady

2

ฉันเรียกร้องเขา!

รวมถึงเฟรมเวิร์กที่ดูแลการจับคู่อินพุตและเอาต์พุต สิ่งที่คุณต้องทำคือกำหนดรุ่นสองฟังก์ชันของคุณเองในส่วนหัว "AIh" ซึ่งกำหนดการย้ายครั้งแรกและการย้ายอื่น ๆ

คอมไพล์ใน VS2012 (เวอร์ชั่นฟรี) ความรู้ของฉันที่ดีที่สุดจะรวบรวมในคอมไพเลอร์ที่ได้มาตรฐานใด ๆ

ฉันเรียก AI นี้ว่า "Barbarian ที่ไม่ซับซ้อน" ฉันแน่ใจว่าจะใช้เวลาไม่นานสำหรับคนที่จะเอาชนะมัน

// A.I.h
    #pragma once

    #include "Fencer.h"

    #include <algorithm>

    Move Fencer::chooseFirstMove() const
    {
        // Choose first move here.
        return Move( Action::Attack , Height::Head );
    }

    Move Fencer::chooseNextMove() const
    {
        using namespace std;

        // Implement A.I. here.
        auto legalActions = match.legalActions();
        auto isLegal = [&legalActions]( Action a ) {
            return find( begin(legalActions) , end(legalActions) , a ) == end(legalActions);
        };

        if( isLegal( Action::Attack ) )
            return Move( Action::Attack , Height::Head );
        if( isLegal( Action::Lunge ) )
            return Move( Action::Lunge , Height::Head );
        if( isLegal( Action::Block ) )
            return Move( Action::Lunge , Height::Head );
        if( isLegal( Action::Parry ) )
            return Move( Action::Parry , Height::Head );

    }

    // Fencer.h
    #pragma once

    #include "Match.h"

    class Fencer
    {
    public:
        std::string nextRound( const std::string& oppsMove );
        std::string getNextMove() const { return nextMove.toStr(); }
        bool matchInProgress() const { return match.inProgress(); }
        Fencer( unsigned int targetScore = 3 , unsigned int match_rounds = 50 );
    private:
        Move chooseNextMove() const;
        Move chooseFirstMove() const;
        Move nextMove;
        Match match;
    };

    // Match.h
    #pragma once

    #include <vector>
    #include <string>

    enum class Action : char
    {
        Attack,
        Parry,
        Block,
        Lunge,
        UNITIALIZED
    };

    enum class Height : char
    {
        Head,
        Chest,
        Feet,
        UNITIALIZED
    };

    enum class Result : char
    {
        Win,
        Tie,
        Lose,
        UNITIALIZED
    };

    struct Move
    {
        Action action;
        Height height;
        Move( Action a , Height h )
            : action(a) , height(h) {}
        std::string toStr() const;

        // For the STL. Please don't use these.
        Move() : action( Action::UNITIALIZED ) , height( Height::UNITIALIZED ) {}
        Move operator=( const Move& );
    };

    Result scoreRound( Move me , Move opp );

    struct Round
    {
        Move myMove;
        Move oppsMove;
        Result result;
        Round( Move me , Move opp )
            : myMove(me) , oppsMove(opp) , result(scoreRound(me,opp)) {}

        // For the STL. Please don't use these.
        Round() : myMove() , oppsMove() , result( Result::UNITIALIZED ) {}
        Round operator=( const Round& );
    };

    class Match
    {
    public:
        // Constructor.
        Match( unsigned int winningScore, unsigned int rounds );

        // Generate a list of legal actions.
        std::vector<Action> legalActions() const;

        // Get a copy of all previous rounds.
        std::vector<Round> getHistory() const { return results; }

        // Gets the scores
        unsigned int myScore() const;
        unsigned int oppsScore() const;
        bool inProgress() const { return in_progress; }

        // Perform next round. Returns the TTY for the round.
        std::string nextRound( const std::string& myMove , const std::string& oppsMove );
    private:
        const unsigned int winning_score;
        const unsigned int n_rounds;
        std::vector<Round> results;
        bool in_progress;
    };

    // Fencer.cpp
    #include "AI.h"

    #include <algorithm>

    using namespace std;

    Fencer::Fencer( unsigned int target , unsigned int rounds ) :
        match( target , rounds ) , nextMove( chooseFirstMove() )
    {}

    string Fencer::nextRound( const string& oppsMove )
    {
        string output = match.nextRound( nextMove.toStr() , oppsMove );
        if( match.inProgress() ) {
            nextMove = chooseNextMove();
            vector<Action> legalActions = match.legalActions();
            auto it = find( legalActions.begin() , legalActions.end() , nextMove.action );
            auto it2 = legalActions.end();
            if( legalActions.end() == it ) {
                output += "\n\nWARNING! Chosen move is illegal!\n\n";
            }
            output += " Action for next round is " + getNextMove() + ".";
        }
        return output;
    }

    // Match.cpp
    #include "Match.h"

    #include <algorithm>
    #include <sstream>
    #include <cassert>
    #include <functional>

    using namespace std;

    string Move::toStr() const
    {
        string str;
        switch( action )
        {
        case Action::Attack:
            str.push_back( 'A' );
            break;
        case Action::Block:
            str.push_back( 'B' );
            break;
        case Action::Lunge:
            str.push_back( 'L' );
            break;
        case Action::Parry:
            str.push_back( 'P' );
            break;
        default:
            assert( false );
            break;
        }
        switch( height )
        {
        case Height::Head:
            str.push_back( 'H' );
            break;
        case Height::Chest:
            str.push_back( 'C' );
            break;
        case Height::Feet:
            str.push_back( 'F' );
            break;
        default:
            assert( false );
            break;
        }
        return str;
    }

    Move Move::operator=( const Move& rhs )
    {
        action = rhs.action;
        height = rhs.height;
        return *this;
    }

    Result scoreRound( Move me , Move opp )
    {
        if( me.height != opp.height ) {
            return Result::Tie;
        }
        if( me.action == opp.action ) {
            return Result::Tie;
        }
        switch ( me.action ) {
        case Action::Attack:
            switch( opp.action ) {
            case Action::Parry:
                return Result::Win;
            case Action::Lunge:
                return Result::Tie;
            case Action::Block:
                return Result::Lose;
            default:
                assert( false );
            }
        case Action::Lunge:
            switch( opp.action ) {
            case Action::Block:
                return Result::Win;
            case Action::Attack:
                return Result::Tie;
            case Action::Parry:
                return Result::Lose;
            default:
                assert( false );
            }
        case Action::Parry:
            switch( opp.action ) {
            case Action::Lunge:
                return Result::Win;
            case Action::Block:
                return Result::Tie;
            case Action::Attack:
                return Result::Lose;
            default:
                assert( false );
            }
        case Action::Block:
            switch( opp.action ) {
            case Action::Attack:
                return Result::Win;
            case Action::Parry:
                return Result::Tie;
            case Action::Lunge:
                return Result::Lose;
            default:
                assert( false );
            }
        default:
            assert( false );
        }
        return Result::Tie;
    }

    Round Round::operator=( const Round& rhs )
    {
        myMove = rhs.myMove;
        oppsMove = rhs.oppsMove;
        result = rhs.result;
        return *this;
    }

    Match::Match( unsigned int targetScore , unsigned int rounds ) :
        winning_score( targetScore ) , n_rounds( rounds) , results() , in_progress( true )
    {
        results.reserve( rounds );
    }

    vector<Action> Match::legalActions() const
    {
        typedef unsigned int ActionBits;

        // Make a bitfield representing the four legal actions.
        const ActionBits ATTACK = 0x1;
        const ActionBits PARRY = 0x2;
        const ActionBits BLOCK = 0x4;
        const ActionBits LUNGE = 0x8;

        const auto actionBitsToVector = [=](ActionBits ab) -> vector<Action> {
            vector<Action> vec;
            if( ab == 0 ) // Nothing is allowed
                ab = ATTACK | PARRY | BLOCK | LUNGE; // So allow all actions
            if( (ATTACK & ab) == ATTACK )
                vec.push_back( Action::Attack );
            if( (PARRY & ab) == PARRY )
                vec.push_back( Action::Parry );
            if( (BLOCK & ab) == BLOCK )
                vec.push_back( Action::Block );
            if( (LUNGE & ab) == LUNGE )
                vec.push_back( Action::Lunge );
            return vec;
        };

        auto availableActions = ATTACK | PARRY | BLOCK | LUNGE;

        const auto lastResult = *results.rbegin();

        // If a point was scored in the last round all actions are available.
        if( lastResult.result != Result::Tie ) {
            return actionBitsToVector( availableActions );
        }

        // If the heights do not match, both players may no longer
        // select the same action (height is not restricted)
        // as the previous tying rounds, until a point is scored,
        // or all 4 actions have been filled.
        if( lastResult.myMove.height != lastResult.oppsMove.height ) {
            for( auto it = results.rbegin() ; it!= results.rend() ; ++it ) {
                if( it->result != Result::Tie )
                    break;
                else {
                    switch( it->myMove.action )
                    {
                    case Action::Attack:
                        availableActions &= ~ATTACK;
                        break;
                    case Action::Parry:
                        availableActions &= ~PARRY;
                        break;
                    case Action::Block:
                        availableActions &= ~BLOCK;
                        break;
                    case Action::Lunge:
                        availableActions &= ~LUNGE;
                        break;
                    default:
                        break;
                    }
                }
            }
            return actionBitsToVector( availableActions );
        }

        // Attack vs. Lunge
        if( lastResult.myMove.action == Action::Attack &&
            lastResult.oppsMove.action == Action::Lunge ) {
                return actionBitsToVector( PARRY | BLOCK );
        }
        if( lastResult.myMove.action == Action::Lunge &&
            lastResult.oppsMove.action == Action::Attack ) {
                return actionBitsToVector( ATTACK | LUNGE );
        }

        // Block vs Parry
        if( lastResult.myMove.action == Action::Block &&
            lastResult.oppsMove.action == Action::Parry ) {
                return actionBitsToVector( ATTACK | LUNGE );
        }
        if( lastResult.myMove.action == Action::Parry &&
            lastResult.oppsMove.action == Action::Block ) {
                return actionBitsToVector( BLOCK | PARRY );
        }
        return actionBitsToVector( availableActions );
    }

    unsigned int Match::myScore() const
    {
        return count_if( begin(results) , end(results) ,
            [=](const Round& r) {
                return r.result == Result::Win;
        });
    }

    unsigned int Match::oppsScore() const
    {
        return count_if( begin(results) , end(results) ,
            [=](const Round& r) {
                return r.result == Result::Lose;
        });
    }

    string Match::nextRound( const string& myMove , const string& oppsMove )
    {
        if( !in_progress )
            return "Match has already finished.\n";

        stringstream output;
        output << "Round " << results.size()+1 << ": ";
        bool parseSuccessful = true;
        auto getMove = [&]( const string& s ) {
            if( s.length() < 2 ) {
                output << "\nError: Move " << s << " does not have enough characters.";
                return Move();
            }
            Action a = Action::UNITIALIZED;
            switch( s[0] )
            {
            case 'a':
            case 'A':
                a = Action::Attack;
                break;
            case 'b':
            case 'B':
                a = Action::Block;
                break;
            case 'l':
            case 'L':
                a = Action::Lunge;
                break;
            case 'p':
            case 'P':
                a = Action::Parry;
                break;
            default:
                parseSuccessful = false;
                output << "\nFailed to parse action part (" << s[0] << ") of " << s;
                break;
            }

            Height h = Height::UNITIALIZED;
            switch( s[1] )
            {
            case 'h':
            case 'H':
                h = Height::Head;
                break;
            case 'c':
            case 'C':
                h = Height::Chest;
                break;
            case 'f':
            case 'F':
                h = Height::Feet;
                break;
            default:
                parseSuccessful = false;
                output << "\nFailed to parse height part (" << s[1] << ") of " << s;
                break;
            }

            if( a == Action::UNITIALIZED || h == Height::UNITIALIZED )
                return Move();
            else
                return Move( a , h );
            };

        Round thisRound( getMove( myMove ),  getMove( oppsMove ) );

        if ( parseSuccessful ) {
            output << "Previous round: " << myMove << " vs " << oppsMove << " - ";
            switch( thisRound.result )
            {
            case Result::Win:
                output << myMove + " Wins! ";
                break;
            case Result::Lose:
                output << oppsMove + " Wins! ";
                break;
            case Result::Tie:
                output << "Tie! ";
                break;
            default:
                assert( false );
                break;
            }

            results.push_back( thisRound );
            const auto score_me = myScore();
            const auto score_opp = oppsScore();
            output << "Score is now " << score_me << "-" << score_opp << ".";

            if( score_me >= winning_score ) {
                output << "\n\tI win! ";
                in_progress = false;
            }
            if( score_opp >= winning_score ) {
                output << "\n\tI lose. ";
                in_progress = false;
            }
            if( results.size() >= n_rounds ) {
                output << "\n\tTime's up. ";
                if( score_me == score_opp )
                    output << "Match drawn. ";
                else
                    output << "I " << (score_me > score_opp ? "win! " : "lose. " );
                in_progress = false;
            }

            if (!in_progress ) {
                output << "Final score: " << score_me << "-" << score_opp << endl;
            }
        }
        return output.str();
    }

1
เพียงแค่สังเกตเห็นข้อบกพร่องของรหัสที่เป็นไปได้ - เมื่อคุณเขียนโค้ดสำหรับบล็อกมันจะยังคงส่งคืนการพุ่งเข้าใส่! - โปรดจำไว้ว่าตามกฎแล้วห้ามทำการแก้ไขจนกว่าคุณจะพ่ายแพ้
NRGdallas

1
จุดดี. นั่นอาจหมายถึง AI พยายามเคลื่อนไหวอย่างผิดกฎหมาย เกิดอะไรขึ้นในสถานการณ์นั้น
Arkady

ฉันต้องการเพิ่มว่าฉันพิจารณาเฟรมเวิร์กสาธารณะและทุกคนที่ต้องการยืมและเพียงแค่เขียนฟังก์ชัน AI ทั้งสองนั้นมีอิสระที่จะทำ
Arkady

การเคลื่อนไหวที่ผิดกฎหมายใด ๆ เป็นการสูญเสียรอบทันที
NRGdallas

UNITIALIZED?!
Soham Chowdhury
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.