wygraj wirtualny mecz szermierki (przeciwko innym wymiennym stosom)

16

UWAGA: jest to dość skomplikowany problem, w stylu walki na wzgórzu, z dodatkową losowością, najlepszy kod nie zawsze może wygrać. Przeczytaj wszystkie zasady w całości, ponieważ jest to dość skomplikowane!

FLAVOR TEXT

Bill i Steve zdecydowali się na „przyjazny” pojedynek, jednak będąc tak bogatym i sprytnym, postanowili pozwolić swoim najlepszym programistom spróbować znaleźć kod, aby się wzajemnie pokonać. Mówi się, że jest programistą.

OBJECTIVE

W szermierce Twoim celem jest zdobycie jak największej liczby trafień przeciwnika, przy najmniejszym trafieniu

MOVES

Twój kod będzie miał następujące opcje „ruchów”

Atak
Parry
Blok
lonży
I
Głowa
Skrzynia
Feet

SCORING POINTS

Atakowanie uderzeń Parowanie, za 1 punkt
Naciskanie rytmów Blokowanie, za 1 punkt
Parowanie rytmów Rzucanie, za 1 punkt
Blokowanie rytmów Atakowanie, za 1 punkt
Krawaty do rzucania Atakowanie, z tym , że gracz rzucający nie może zablokować lub sparować następnej rundy, a atakujący gracz nie może zaatakować lub zaatakować następną rundę
Wiązanie blokujące Parowanie, gracz parujący nie może zablokować lub sparować następnej rundy, a gracz blokujący nie może zaatakować lub zaatakować następnej rundy

HEIGHT OF ACTION

wybierzesz również „wysokość” akcji, przy czym powyższe wyniki będą miały miejsce tylko wtedy, gdy wysokość obu graczy będzie odpowiadać wysokości ataku. jeśli wysokości się nie zgadzają, obaj gracze nie mogą już wybierać tej samej akcji (wysokość nie jest ograniczona) jak w poprzednich rundach wiązania, aż do zdobycia punktu lub wykonania wszystkich 4 akcji (po rozstrzygnięciu remisu wszystkie akcje są ponownie dostępne)

CODE REQUIREMENTS

dla każdej rundy powinien on nakazać ruch przeciwnikowi poprzedniej rundy (z wyjątkiem rundy 1), porównać go z własną, określić wynik poprzedniej rundy, a następnie podać numer następnej rundy, wynik oraz jej wybór / pozycję dla tej rundy

np .:
WEJŚCIE: LC (klatka piersiowa)
WYJŚCIE: poprzednia runda: PM vs LC - wyniki PM! wynik jest teraz 2-1, akcja w następnej rundzie to AH (głowa ataku)

WINNER

gra kończy się po 50 rundach lub po zdobyciu 3 punktów

AGAINST OTHER PLAYERS

pierwsza odpowiedź otrzyma natychmiastową gwarancję wygranej, pod warunkiem, że faktycznie działa / gra. Każda odpowiedź zostanie oceniona, w kolejności wysłania, względem poprzedniego zwycięzcy, a jeśli wygra, zostanie ogłoszony nowym zwycięzcą. Proszę, aby wygrywając lub czekając na współzawodnictwo, NIE zmieniasz kodu. Po pokonaniu nie możesz już konkurować o status mistrzowski z tym samym językiem, możesz jednak przesłać odpowiedź w innym języku (musi być znacząco różny, bez używania odmian tego samego podstawowego materiału).

Spróbuję uruchomić każde wyzwanie i opublikować wyniki w komentarzach mistrza i pretendenta, a także ogłosić nowego zwycięzcę - ponieważ mogę nie być w stanie posługiwać się każdym językiem, zwłaszcza niektórymi bardziej niejasnymi, pytam należy wziąć pod uwagę wszelką możliwą pomoc, aby upewnić się, że odpowiedź zostanie udzielona. Dziękuję Ci!

NRGdallas
źródło
1
Uwaga: ukierunkowanie algorytmu na zwycięzców, aby przeciwdziałał temu graczowi, polega na szermierce, a to jest król wzgórza, więc taka akcja jest nie tylko dozwolona, ​​ale także ZACHĘTA! - spróbuj wymyślić jakąś metodę generowania wyników, zaciemniania kodu lub inny sposób „strzeżenia” siebie i wymyśl najlepszy sposób na „zaatakowanie” kodu drugiego gracza! - PROSZĘ PRZECHOWYWAĆ
CAŁĄ DYSKUSJĘ CYWILNĄ
raz pokonany, jeśli chcesz zaoferować wgląd w to, jak to zrobiłeś, dlaczego zrobiłeś to w określony sposób, itd., w komentarzach lub zmieniając odpowiedź, nie krępuj się. Podczas gdy kod jest zgodny, proszę powstrzymać się od edycji :)
NRGdallas,
Czy twój przykład jest poprawny? Wydaje się, że wpaja wejście LC w działanie LM.
Peter Taylor,
Co z przypadkowością w rozwiązaniu? Czy dopasowanie musi być deterministyczne? Jeśli nie, w jaki sposób sędzia wybierze ziarno i ile gier będzie rozgrywanych między dwoma programami, tylko jednym? Zawody robocode mają zwykle 10, aby ograniczyć efekty ślepej szansy.
vsz
3
Nie podoba mi się, jak to jest zaprojektowane. Myślę, że powinieneś wymyślić kod, aby uruchomić mecz, uruchamiając 2 przesłane programy, przekazując ruchy i obliczając wyniki. Programy szermiercze powinny po prostu wydrukować swoje ruchy na standardowe wejście i odczytać ruchy przeciwnika ze standardowego wejścia.
aditsu

Odpowiedzi:

5

Pyton

En garde!

Mój wojownik łączy nieprzewidywalność z bystrym okiem słabości w postawie przeciwnika. Jest całkiem pewny, że będzie w stanie pozbyć się agresywnych wrogów, ale jego trener (ja) mógł nie przewidzieć pewnych scenariuszy lub, co bardziej niepokojące, mógł źle interpretować zasady (błędy !!).

W każdym razie jestem nowy, więc mam nadzieję, że jest to odpowiedni format kodu:

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()
ejrb
źródło
uwielbiam tekst smaku! miejmy nadzieję, że uda mi się je zdobyć, żeby je tutaj wygrzebać w ten weekend. Niestety, minęło bardzo dużo czasu, odkąd został opublikowany i właśnie zyskuje przyczepność, więc jestem teraz trochę źle przygotowany do zrobienia, ale powinienem być w stanie tutaj w ciągu kilku dni!
NRGdallas
1
Bez obaw. Szczerze mówiąc, nie sprawdziłem dat powyższych postów. Barbarzyńca @Arkady musi czuć się pewnie zarozumiały / samotny na tym wzgórzu przez 8 tygodni. Wykorzystam to na swoją korzyść!
ejrb
Sprawdzę to później (nie mam interpretera Pythona w pracy) i prawdopodobnie później skontruje. Bądźcie czujni, jak mogliby powiedzieć we Francji.
Arkady
2

Odbieram wzgórze!

Obejmuje to strukturę, która zajmuje się dopasowaniem, wejściem i wyjściem. Wszystko, co musisz zrobić, to zdefiniować własne wersje dwóch funkcji w nagłówku „AIh”, które określają pierwszy ruch i każdy inny ruch.

Kompiluje się w VS2012 (wersja darmowa). Zgodnie z moją najlepszą wiedzą skompiluje się w dowolnym kompilatorze zgodnym ze standardami.

Nazywam to AI „niewyszukanym barbarzyńcą”. Jestem pewien, że ktoś nie zajmie długo.

// 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();
    }
Arkady
źródło
1
po prostu zauważam potencjalną wadę kodu - kiedy kodujesz blok, nadal zwraca ruch rzutu! - pamiętaj, zgodnie z zasadami, edycja nie jest dozwolona, ​​dopóki nie zostaniesz pokonany
NRGdallas
1
Słuszna uwaga. Może to oznaczać, że AI próbuje nielegalnych ruchów. Co dzieje się w tej sytuacji?
Arkady
Chciałbym również dodać, że uważam platformę za publiczną i wszyscy, którzy chcą ją pożyczyć, i po prostu przepisali dwie funkcje AI, mogą to zrobić.
Arkady
każdy nielegalny ruch to natychmiastowa utrata rundy.
NRGdallas,
UNITIALIZED?!
Soham Chowdhury