Metti in scena un colpo di stato per diventare il re della collina!


14

Classifica

  154 Calculator
  144 Taxman
  138 Statistician
  137 Solver
  137 RandoAggroLawyer
  136 Gambler
  134 Turncoat
  119 Lawyer
  119 BloodyMurder
  113 Bandit
   79 Challenger
   74 Mask
   64 Random

È disponibile un archivio dell'ultima corrispondenza, incluso il registro e tutti i file di output.

Calculator, di Brilliand, è il vincitore! La sua risposta è accettata, ma ciò non significa che la sfida sia finita. Sentiti libero di inviare nuove voci o modificare quelle attuali e provare a farlo cadere dal suo trono. Alla fine del mese assegnerò un premio al leader.

Regole di gioco

Coup è un gioco di carte progettato per 2-6 giocatori, che giocheremo con due. Consiste in un tesoro di monete (infinito per i nostri scopi) e un mazzo di 15 carte, contenente 3 ciascuno dei seguenti tipi: Ambasciatore, Assassino, Capitano, Contessa, Duca. All'inizio del gioco, a ogni giocatore viene data una moneta e distribuite due carte a caso, che mantengono segrete fino al momento necessario. L'oggetto deve essere l'ultimo giocatore con le carte in mano.

Nel loro turno, un giocatore può effettuare una delle seguenti azioni indipendentemente dalle proprie carte:

  • Entrate: prendi 1 moneta dal tesoro. Non bloccabile e insindacabile.
  • Aiuti esteri: prendi 2 monete dal tesoro. Può essere bloccato da un giocatore con un Duca. Insindacabile.
  • Coup: Rimuovi dal gioco una carta di un avversario a tua scelta. Costa 7 monete. La vittima può scegliere quale carta scartare. Se un giocatore ha 10 o più monete all'inizio del proprio turno, deve Coup. Non bloccabile e insindacabile.

A seconda delle loro carte, i giocatori possono anche effettuare una delle seguenti azioni come loro turno:

  • Scambio: un giocatore con un Ambasciatore può prendere due carte dal mazzo. Quindi possono scegliere tra la loro mano e le carte pescate quante carte originariamente possedevano. (Cioè, se avessero una sola carta, potrebbero scambiarla con una delle carte pescate o tenerla, e se avessero due carte, potranno scegliere una qualsiasi delle quattro carte.) Le due carte indesiderate vengono rimesse nel mazzo . Non bloccabile, ma sfidabile.
  • Assassinare: un giocatore con un Assassino può spendere 3 monete per rimuovere la carta di un avversario dal gioco. La vittima può scegliere quale carta scartare. Può essere bloccato da un giocatore con una Contessa, nel qual caso le monete non vengono restituite. Sfidabile, nel qual caso le monete vengono restituite.
  • Ruba: un giocatore con un Capitano può prendere due monete dal proprio avversario. Se l'avversario ha una moneta, prenderà quella moneta. Se l'avversario ha zero monete, non può rubare. Può essere bloccato da un giocatore con un ambasciatore o un capitano. Impugnabile.
  • Imposta: un giocatore con un Duca può prendere 3 monete dal tesoro. Non bloccabile, ma sfidabile.

La parte difficile di Coup è che i giocatori possono mentire su quali carte hanno! Non è necessario disporre di una carta per tentare di eseguire l'azione o il blocco ad essa associati.

Quando un giocatore esegue un'azione di una carta, qualsiasi avversario (anche uno che non è danneggiato da quell'azione) può sfidare l'attore e dire di non credere di avere la carta per quell'azione. Se lo sfidante ha ragione, l'azione viene annullata e l'attore deve scartare una carta a sua scelta (riprendendo le monete che ha speso, se applicabile). Altrimenti, l'azione viene intrapresa, l'attore restituisce al mazzo la carta sulla quale erano stati sfidati e ne pesca una nuova, e lo sfidante deve scartare una delle sue carte. I giocatori devono essere sinceri su quali carte possiedono quando vengono sfidati.

Le carte eliminate dal gioco con Assassinato, Colpo e sfide perse non vengono restituite al mazzo, ma le carte rivelate come parte di una sfida vinta vengono restituite al mazzo.

I blocchi possono essere sfidati proprio come le azioni. Ad esempio, se il giocatore A richiede un aiuto straniero e il giocatore B dice "Ho un duca e blocco il tuo aiuto straniero", A potrebbe dire "Non credo che tu abbia un duca". Se tale affermazione è corretta, B perde una carta per essere catturato in una bugia e A prende 2 monete; in caso contrario, A perde una carta e non ottiene monete, e B deve riportare il proprio Duca sul mazzo e pescare una nuova carta.

Il modo in cui blocchi e sfide funzionano con Assassinate deve essere chiarito. Supponiamo che il Giocatore A dica "Ho un Assassino e Assassino il Giocatore B". Se B non tenta di sfidare o bloccare A, l'assassinio subisce: B perde una carta e A paga 3 monete.

In alternativa, B può sfidare dicendo "Non credo che tu abbia un Assassino". Se questo è vero, allora A scarta una carta e le loro monete vengono restituite, mentre B non viene influenzato e il turno di A termina. Se la convinzione di B è errata e A detiene un Assassino, allora B perde entrambe le carte e fallisce, una per la sfida errata e una per Assassinio.

Invece di sfidare, B potrebbe dire "Ho una contessa e blocco l'assassinio". Se A crede a B, il turno di A termina e le loro monete non vengono restituite. Ma A può sfidare il blocco e dire "Non credo che tu abbia una Contessa." Se B detiene effettivamente una contessa, allora A perde una carta per la sfida errata. Ma se B non lo fa, allora B perde una carta per essere catturato in una bugia e un'altra dall'assassinio.

Una logica simile alla spiegazione precedente si applica all'abilità Rubare del Capitano, in cui l'azione o il blocco possono essere sfidati.

È possibile perdere entrambe le carte ed essere eliminati in un turno, se si sfida un Assassinato senza successo o si viene sorpresi a sostenere che si ha una Contessa per bloccare un Assassinio. Perdi una carta dalla sfida e una carta dall'assassinio.

Sfida

Il tuo compito è quello di scrivere un programma che riprodurrà Coup. Verrà fornito come argomento della riga di comando:

  • Il nome di un file contenente l'elenco delle sue azioni e quelle dei suoi avversari finora.
  • Un numero intero compreso tra 0 e 12 che indica il conteggio delle monete dell'avversario.
  • Un numero intero compreso tra 0 e 12 che indica il conteggio delle monete.
  • Una stringa lunga da uno a quattro caratteri che indica le sue carte. Normalmente questa sarà semplicemente una o due carte del tuo programma, ma se il tuo programma è appena riuscito in uno scambio, avrà una lunghezza di n + 2 caratteri, dove n è il tuo numero di carte rimanenti. Il tuo programma deve quindi emettere le n carte che desidera conservare su STDOUT. (I programmi non devono leggere o accedere a STDOUT se non per questo scopo - se si desidera produrre output di debug, scrivere a STDERR.)
  • Uno o più argomenti che indicano le mosse legali che può effettuare.

(Esempio di invocazione:, che yourprogram file.txt 1 7 '~!' a c p qsignifica "Il tuo avversario ha 1 moneta. Hai 7 monete, un Ambasciatore e una Contessa. Scrivi su file.txt la tua scelta di a, c, p o q data la storia del gioco e lo stato di gioco attuale. ")

Il programma deve aggiungere uno o (in due situazioni specifiche) due caratteri al file fornito che indica la sua azione. In caso contrario, non deve modificare il contenuto esistente del file. Può creare tutti i nuovi file che desidera, ma solo all'interno della directory in cui viene eseguito. Fornisci tutti i comandi necessari per compilare ed eseguire il tuo programma.

Di seguito ho fornito due esempi di concorrenti, scritti in Go.

Il formato di output è:

  • I\n: Reddito. Risposte legali: qualsiasi azione di turno (supponendo che uno abbia le monete per Assassinare / Colpo di stato).
  • F: Aiuti esteri. Risposte legali: d(blocca come duca), p(lascialo passare).
  • C: Colpo di stato Risposte legali: a seconda di quale di _, ', <, =, 0è nelle tue mani.
  • E: Scambio. Risposte legali: q(sfida, non credendo il giocatore ha un ambasciatore), p.
  • T: Imposta. Risposte legali: q(sfida, non credendo il giocatore ha un Duke), p.
  • A: Assassinare. Risposte giuridiche: s(a blocchi come Contessa), q(sfida), e seconda di quale di _, ', <, =, 0è in mano.
  • S: Rubare. Risposte giuridiche: a(a blocchi come un ambasciatore), c(blocco come un capitano), q(sfida, non credendo il giocatore ha un capitano), p.
  • d: blocca gli aiuti esteri come duca. Risposte legali: \n(accetta il blocco), q(sfida, non credere che il giocatore abbia un Duca).
  • a: blocca un furto come ambasciatore. Risposte legali: \n(accetta il blocco), q(sfida, non credere che il giocatore abbia un Ambasciatore).
  • c: blocca un furto come capitano. \n(accetta il blocco), q(sfida, non credere che il giocatore abbia un Capitano).
  • s: blocca un Assassinato come Contessa. Risposte legali: \n(accetta il blocco), q(sfida, non credere che il giocatore abbia una contessa).
  • p: passa sfidando uno Scambio / Tasse / Ruba quando non è il tuo turno. Non utilizzato con A; rifiutare di sfidare un Assassinio scrivere uno di _'<=0. Risposta legale: \n(termina il tuo turno), e se hai appena avuto successo in uno scambio, scrivi le carte che desideri conservare dal quarto argomento della riga di comando su STDOUT.
  • q: sfida l'azione o il blocco più recenti. Risposta legale: se hai la carta per l'azione che è stata contestata, qualunque ~^*!$essa fosse. Se non lo fai, qualunque sia la _'<=0tua mano a cui vuoi rinunciare, seguita da una nuova linea se e solo se è il tuo turno.
  • ~, ^, *, !, $: Rivelano che si stava dicendo la verità circa la detenzione, rispettivamente, un ambasciatore, un Assassino, un capitano, un Contessa, e un Duca (utilizzato anche per rappresentare queste carte in argomenti della riga di comando, e STDOUT uscita in scambio ). Risposte legali: a seconda di quale di _, ', <, =, 0che avete in mano.
  • _, ', <, =, 0: Rinunciare, come punizione, rispettivamente, un ambasciatore, e assassino, un capitano, un Contessa, e un Duca perché hai perso una sfida o sono stati ASSASSINATO / couped. Risposta giuridica: \n.
  • \n: termina il tuo turno, in tal modo diminuendo per sfidare un blocco, se applicabile. Risposte legali: qualsiasi azione in maiuscolo (supponendo che uno abbia le monete per Assassinare / Colpo e l'avversario abbia le monete per Rubare).

Il formato ha le seguenti proprietà utili:

  • Le svolte iniziano con una lettera maiuscola.
  • Le linee seguono il modello: lettere maiuscole, lettere minuscole, segni di punteggiatura opzionali o 0 per le carte rivelate, riga nuova.
  • Un file che termina con una nuova riga o un file vuoto indica che è l'inizio del turno del programma e deve scegliere un'azione in maiuscolo.
  • Le azioni legali che è consentito intraprendere su un'invocazione sono generalmente determinate in modo univoco dall'ultimo carattere nel file. L'eccezione è q, a cui sarà associata una logica. Vedi la funzione get_legal_actionsnell'arbitro per capire questo. Oppure puoi semplicemente usare le azioni legali che ti vengono fornite sulla riga di comando.
  • Un numero pari di personaggi su una linea indica che il turno è tuo e al tuo programma viene chiesto di scegliere un'azione, sfidare un blocco o terminare il suo turno.
  • Un numero dispari di personaggi su una linea indica che il turno non è tuo e al tuo programma viene chiesto di bloccare, sfidare o rivelare / consegnare una carta.

Farò un esempio per ogni azione.

I\nè il più facile da capire. Un programma prende una moneta del reddito, quindi termina il suo turno. Questo è uno dei due casi in cui i programmi devono stampare due personaggi, poiché il reddito è l'unica azione in cui l'avversario non è influenzato e non può bloccare o sfidare.

Fp\nsignifica che un programma ha preso aiuti esteri, quindi il suo avversario ha rifiutato di bloccare ( p). Alla sua successiva invocazione, il primo programma ha notato che dalla lettera minuscola finale pe / o dal numero pari di caratteri su questa linea ha preso questo turno, che non è ancora terminato, quindi sa di terminare il suo turno corrente stampando una nuova riga.

C=\nsignifica che un programma ha lanciato un colpo di stato. Il suo avversario, sapendo che era chiamato a reagire per il numero dispari di lettere sulla linea, rinunciò a una Contessa. Ancora una volta, il primo programma sapeva che questa era la sua svolta incompleta alla sua successiva invocazione dal numero pari di caratteri sulla linea, quindi ha scritto una nuova riga per terminare la sua svolta.

Eq~<\nsignificherebbe che un programma ha tentato uno scambio ( E) e il suo avversario ha sfidato ( q). Il programma di Scambio ha rivelato che aveva davvero un Ambasciatore ( ~) e lo sfidante ha rinunciato a un Capitano come punizione ( <). Dopo che lo sfidante è uscito, il programma di Scambio viene nuovamente invocato con una stringa di quattro caratteri come quarto argomento della riga di comando (o tre caratteri, se avesse solo una carta). Scrive i personaggi che rappresentano le carte che desidera conservare su STDOUT e una nuova riga nel file.

Tq'\nsignifica che un programma ha tentato una tassa non veritiera, è stato sfidato e ha rinunciato a un assassino. Illustra l'altro caso in cui sono scritti due personaggi: se è il tuo turno e sei costretto a rinunciare a una carta - dalla sfida corretta di un avversario (come qui) o dalla sfida errata di un blocco - allora devi scrivere entrambi la carta che abbandoni e una nuova riga per terminare il tuo turno.

Asq!'\nsignificherebbe che il giocatore B ha tentato di assassinare il giocatore A ( A), ma A ha affermato di avere una Contessa per bloccarlo ( s). B non credeva in A e lo sfidava ( q). A ha rivelato che in effetti avevano una Contessa ( !). B rinunciò a un Assassino come punizione, perdendo le monete e finì il loro turno ( '\n), scrivendo due personaggi come in quel caso speciale. (Se A avesse deciso di non bloccare o sfidare, avrebbe potuto scrivere =, e quindi il suo avversario avrebbe visto che il turno era finito e avrebbe scritto una nuova riga. La riga avrebbe quindi letto A=\n, come nell'esempio Coup.)

Sq*0\nsignifica che un programma tenta un furto; l'avversario sfida, non credendo che il ladro abbia un Capitano; e il programma originale rivela un Capitano, quindi la sfida non ha successo e lo sfidante rinuncia a un Duca come punizione. (Un'altra opzione per il suo avversario sarebbe quella di accettare lo Steal scrivendo p. Il suo avversario rileverebbe quindi la fine del suo turno e scriverà \n, risultando in una riga di Sp\n.)

The Arbiter

I programmi saranno richiamati da questo script Python. Conduce dieci round, in cui ogni concorrente affronta tutti gli altri concorrenti, andando sia al primo che al secondo. Tiene traccia delle carte e del conteggio delle monete e determina il perdente dal primo programma per terminare due volte una linea con un segno di punteggiatura. I programmi che escono con uno stato diverso da zero, modificano il file, scrivono una mossa illegale nel file o tentano uno scambio illegale perderanno automaticamente. Se ogni giocatore esegue più di 100 azioni, inclusi blocchi e sfide, senza vincitori, entrambi i programmi perdono. A un vincitore viene assegnato un punto. Vince il giocatore il cui programma segna il maggior numero di punti.

Ti suggerisco di leggere il codice sorgente dell'Arbiter, in particolare la get_legal_actionsfunzione. Può aiutarti a capire le specifiche e scrivere i tuoi programmi.

import itertools
import os
import random
import subprocess

class Player:
    def __init__(self, name, command):
        self.name = name
        self.command = command
        self.score = 0
        self.coins = 1
        self.cards = ""

actions_dict = {
    'E': '_', 'T': '0', 'A': "'", 'S': '<',
    'd': '0', 'a': '_', 'c': '<', 's': '='
}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {
    punishment_to_reveal[k]: k for k in punishment_to_reveal
}

def get_legal_actions(history, player, opponent):
    c = history[-1]
    result = ""
    # Our turn begins; choose an action.
    if c == '\n':
        if player.coins >= 10:
            return ["C"]
        ret = ['I\n'] + list("FET")
        if player.coins >= 3:
            ret.append("A")
        if player.coins >= 7:
            ret.append('C')
        if opponent.coins > 0:
            ret.append("S")
        return ret
    # Opponent attempted foreign aid; can pass or claim Duke to block.
    elif c == 'F':
        return list('dp')
    # We have been Couped; must surrender a card.
    elif c == 'C':
        return player.cards
    # We failed a challenge; must surrender a card and print a newline
    # if it is our turn.
    elif c in '~^*!$':
        if history[-3] in 'acds':
            return [card + '\n' for card in player.cards]
        return player.cards
    # Opponent attempted Exchange or Tax; can pass or challenge.
    elif c == 'E' or c == 'T':
        return list('pq')
    # Opponent attempted an Assassination; can block, challenge, or give in.
    elif c == 'A':
        return list('sq') + player.cards
    # Opponent attempted to Steal; can pass, block as Ambassador/Captain,
    # or challenge.
    elif c == 'S':
        return list('acpq')
    # Opponent blocked; can challenge or withdraw.
    elif c in 'acds':
        return list('q\n')
    # Opponent passed on blocking Foreign Aid/Tax/Exchange or they gave up a
    # card as punishment, must end turn.
    elif c in "p_'<=0":
        return ['\n']
    # Opponent challenged us.
    elif c == 'q':
        challenged_action = history[-2]
        # If we have the card they challenged us over, must reveal it.
        necessary_card = actions_dict[challenged_action]
        if necessary_card in player.cards:
            return [punishment_to_reveal[necessary_card]]
        # Otherwise, we can give up either of our cards, writing a newline
        # if it is our turn.
        if challenged_action in 'acds':
            return list(player.cards)
        else:
            return [card + '\n' for card in player.cards]
    else:
        return None

deck = ['_', "'", '<', '=', '0'] * 3
random.shuffle(deck)

def determine_turn_effects(line, output, cards, current_player, opponent):
    last_action = line[-2]
    # Only operate if the opponent declined to challenge (p) or the
    # program successfully challenged their block
    if last_action in "p_'<=0":
        primary_action = line[0]
        # Foreign Aid
        if primary_action == 'F':
            print current_player.name, "received 2 coins of Foreign Aid"
            current_player.coins += 2
        # Tax
        elif primary_action == 'T':
            print current_player.name, "received 3 coins of Tax"
            current_player.coins += 3
        # Steal
        elif primary_action == 'S':
            stolen_coins = 1 if opponent.coins == 1 else 2
            print current_player.name,\
                    "stole %d coins from %s" % (stolen_coins, opponent.name)
            current_player.coins += stolen_coins
            opponent.coins -= stolen_coins
        # Exchange, store desired cards and replace undesired ones
        elif primary_action == 'E':
            print current_player.name, "tried to take %r" % output, "from", cards
            legal_outputs = [''.join(p) for p in itertools.permutations(
                    cards, len(current_player.cards))]
            if output not in legal_outputs:
                print current_player.name, "forfeits by illegal exchange"
                return opponent
            current_player.cards = [
                reveal_to_punishment[c] for c in output
            ]
            undesired_cards = list(cards)
            for c in output:
                undesired_cards.remove(c)
            for card in undesired_cards:
                deck.append(reveal_to_punishment[card])
            random.shuffle(deck)
    # Coins are not returned from a successful Contessa block
    elif last_action == 's':
        print current_player.name, "lost 3 coins from a Contessa block"
        current_player.coins -= 3
    return None

def play_game(player1, player2, round_number, game_number):
    outfilename = os.path.abspath(__file__)[:-len(__file__)] + '_'.join([
        player1.name, player2.name, str(round_number), str(game_number)
    ]) + '.txt'
    print outfilename
    f = open(outfilename, 'w')
    f.close()
    players_list = [player1, player2]
    player1.cards = [deck.pop(), deck.pop()]
    player2.cards = [deck.pop(), deck.pop()]
    current_player_index = 0
    for i in range(200):
        current_player = players_list[current_player_index]
        opponent = players_list[(current_player_index+1) % 2]
        legal_actions = []
        original_contents = []
        original_contents_joined = ""
        with open(outfilename, 'r') as outfile:
            original_contents = outfile.readlines()
            original_contents_joined = ''.join(original_contents)
            if len(original_contents) == 0:
                legal_actions = ['I\n'] + list("FEST")
            else:
                legal_actions = get_legal_actions(
                        original_contents[-1], current_player, opponent)
        if not legal_actions:
            print "Error: file ended in invalid character"
            return current_player
        # Has the player completed an Exchange? Pass them new cards if so.
        exchange_cards = ""
        old_last_line = original_contents[-1] if len(original_contents) > 0 else '\n'
        if old_last_line[-1] != '\n' and old_last_line[0] == 'E' and \
                len(old_last_line) % 2 == 0 and old_last_line[-1] in "p_'<=0":
            exchange_cards = punishment_to_reveal[deck.pop()] + \
                    punishment_to_reveal[deck.pop()]

        cards = exchange_cards + ''.join(
                    punishment_to_reveal[card] for card in current_player.cards)
        args = current_player.command + [
            outfilename,
            str(opponent.coins),
            str(current_player.coins),
            cards
        ] + legal_actions
        print ' '.join(args)
        output = ""
        os.chdir(current_player.name)
        try:
            output = subprocess.check_output(args)
        # Competitors that fail to execute must forfeit
        except subprocess.CalledProcessError:
            print current_player.name, "forfeits by non-zero exit status"
            return opponent
        finally:
            os.chdir('..')

        new_contents = []
        new_contents_joined = ""
        with open(outfilename, 'r') as outfile:
            new_contents = outfile.readlines()
            new_contents_joined = ''.join(new_contents)
        if original_contents_joined != new_contents_joined[:-2] and \
                original_contents_joined != new_contents_joined[:-1]:
            print current_player.name, "forfeits by modifying the file"
            print "old:", original_contents
            print "new:", new_contents
            return opponent
        new_last_line = new_contents[-1]
        the_move_made = ""
        for action in legal_actions:
            if new_last_line.endswith(action):
                the_move_made = action
                break
        # Competitors that make an illegal move must forfeit
        if not the_move_made:
            print current_player.name, "forfeits with an illegal move,",\
                    "last line: %r" % new_last_line
            print opponent.name, "wins!"
            return opponent
        print current_player.name, "played %r" % the_move_made
        # Side effects of moves.
        #
        # Income, give the current player a coin.
        if the_move_made == "I\n":
            print current_player.name, "received 1 coin of income"
            current_player.coins += 1
        # The program surrendered a card on its turn; take it away. 
        elif len(the_move_made) == 2:
            print current_player.name, "lost a card from being challenged"
            current_player.cards.remove(the_move_made[0])
            # Coins are not returned from a successful Contessa block
            if new_last_line[-3] == '!':
                print current_player.name, "lost 3 coins from a Contessa block"
                current_player.coins -= 3
        # The program surrendered a card when it was not its turn.
        elif the_move_made in "_'<=0":
            print current_player.name, "gave up a", the_move_made
            current_player.cards.remove(the_move_made)
            if new_last_line[0] == 'C':
                opponent.coins -= 7
            elif new_last_line[0] == 'A':
                opponent.coins -= 3
            # Did the program unsuccessfully challenge an Assassination
            # (e.g. Aq^0\n)
            # or get caught falsely blocking with a Contessa
            # (e.g. Asq0\n)?
            # If yes, it loses right away.
            if new_last_line[0] == 'A' and new_last_line[1] in 'qs' and \
                    len(new_last_line) == 4:
                print current_player.name, "lost both cards in the same turn."
                print opponent.name, "wins!"
                return opponent
        elif the_move_made == 'S':
            print current_player.name, "attempted Steal"
        elif the_move_made == 'T':
            print current_player.name, "attempted Tax"
        elif the_move_made == 'A':
            print current_player.name, "attempted Assassinate"
        elif the_move_made == 'C':
            print current_player.name, "launched a Coup"
        elif the_move_made == 'F':
            print current_player.name, "attempted Foreign Aid"
        elif the_move_made == 'E':
            print current_player.name, "attempted Exchange"
        elif the_move_made == 'q':
            print current_player.name, "challenged"
        elif the_move_made == 'p':
            print current_player.name, "passed"
        elif the_move_made == 'a':
            print current_player.name, "blocked with an Ambassador"
        elif the_move_made == 'c':
            print current_player.name, "blocked with a Captain"
        elif the_move_made == 's':
            print current_player.name, "blocked with a Contessa"
        elif the_move_made == 'd':
            print current_player.name, "blocked with a Duke"
        # The program revealed a card from an opponent's unsuccessful challenge.
        # Give it a new card.
        # Special case: a program whose Exchange is unsuccessfully challenged
        # may keep the Ambassador it revealed in the Exchange, so give a new
        # card for a revealed Ambassador only if it was used to block a Steal.
        elif the_move_made in '^*!$' or (the_move_made == '~' and
                new_last_line[0] == 'S'):
            p = reveal_to_punishment[the_move_made]
            current_player.cards.remove(p)
            current_player.cards.append(deck.pop())
            deck.append(p)
            random.shuffle(deck)
            print current_player.name, "did have a", the_move_made
        # The program ended its turn. We must examine the rest of the line to
        # determine the side effects.
        elif the_move_made == '\n':
            potential_winner = determine_turn_effects(
                    new_last_line, output.strip(), cards, current_player,
                    opponent)
            if potential_winner:
                print potential_winner.name,\
                        "wins because their opponent made an illegal exchange!"
                return potential_winner

        # One player has lost all their cards. Victory for the opponent!
        if current_player.cards == []:
            print opponent.name, "wins by eliminating both opponent cards!"
            return opponent

        current_player_index += 1
        current_player_index %= 2
    return None

competitors = []
competitors.append(Player("Challenger", ["./challenger"]))
competitors.append(Player("Random", ["./random"]))
# ...More competitors here

for i in range(10):
    print "-- Round", i
    j = 0
    for pairing in itertools.permutations(competitors, 2):
        player1, player2 = pairing
        print '--- Game', j, ':', player1.name, 'vs.', player2.name
        winner = play_game(player1, player2, i, j)
        if not winner:
            j += 1
            continue
        winner.score += 1
        player1.coins = 1
        player1.cards = ""
        player2.coins = 1
        player2.cards = ""
        deck = ['_', "'", '<', '=', '0'] * 3
        random.shuffle(deck)
        j += 1

competitors.sort(reverse=True, key=lambda player: player.score)

for player in competitors:
    print '%5d %s' % (player.score, player.name)

miscellaneo

Un programma non può avere un codice specifico per un altro programma e i programmi non possono aiutarsi a vicenda. (Potresti avere più programmi, ma non possono interagire tra loro in alcun modo.)

Se il tuo programma perde entrambe le carte nello stesso turno, deve solo scriverne una. L'Arbiter rileverà che è stato eliminato.

È possibile e incoraggiato, ma non necessario, che i programmi esaminino la cronologia del gioco nel file. In questo modo possono determinare quali carte il loro avversario ha affermato di avere e catturarle in una bugia.

Nel vero gioco di Coup, puoi sfidare un'azione e quindi tentare di bloccarla nello stesso turno. Non potrei far funzionare le specifiche se lo consentissi, quindi potresti sfidare o bloccare una determinata azione, ma non entrambe.

Mi scuso con @PeterTaylor, che la volta precedente ho pubblicato questo suggerito di postarlo nella sandbox e rielaborare il protocollo per reindirizzare l'output avanti e indietro in STDOUT / STDIN. Ho provato così, così duramente per farlo funzionare, trascorrendo un'intera giornata (quando avevo già trascorso un'intera giornata a scrivere la sfida originale). Ma gli scambi si sono dimostrati molto complicati da implementare in quel modo, inoltre avrebbe aumentato la complessità degli invii richiedendo loro di tenere traccia del proprio conteggio delle monete. Quindi ho pubblicato la sfida più o meno com'era in origine.


Non capivo bene come fosse finita una svolta. Dal post, una sfida / blocco di successo finirebbe il turno. E gli altri? Qualcuno può scambiare un numero infinito di volte in una volta finché gli avversari non sfidano?
TSH

@tsh Un programma termina sempre il suo turno scrivendo una nuova riga, ma potrebbe scrivere prima un personaggio se prende Entrate o perde una carta nel suo turno. Una sfida / blocco di successo finirebbe davvero il turno. Un blocco di successo di un furto sarebbe andato: programma A scrive S, programma B blocchi scrivendo c, A rifiuta di sfidare scrivendo \n. Una sfida di successo di un furto sarebbe andata: A scrive S, B sfida scrivendo q, A ammette la sfida scrivendo ad es _\n. Puoi prendere solo un'azione per turno, incluso Scambio. Le risposte legali a Exchange sono pass e challenge.
Viola P

2
@jaaq Non ho ancora deciso una scadenza. Almeno lo terrò aperto fino a quando non lo invierai :)
Viola P

1
@jaaq L'Arbiter conduce 10 round di c P2 match ciascuno, dove c è il numero di concorrenti. Attualmente ci sono 13 concorrenti, risultando in 10 (13P2) = 10 (13! / 11!) = 10 (13 * 12) = 1560 partite.
Purple P,

1
@jaaq ero via. Sono tornato. Aggiornato.
Purple P,

Risposte:


4

Calcolatrice

Pianifica la sua serie di mosse vincenti e sfida qualsiasi cosa gli impedisca di vincere.

from __future__ import division
import sys
import random
import operator

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=', '0']

statefilename = './state.txt'
flags = set()
# Flags:
# 1 We went first
# $ Attacking with Duke
# * Attacking with Captain
# ^ Attacking with Assassin
# d Opponent used Duke
# c Opponent used Captain
# A Opponent used Assassin
# F Opponent used Foreign Aid

with open(statefilename, "a+") as statefile:
    statefile.seek(0)
    if statefile.readline().strip() == filename:
        flags = set(statefile.readline().strip())

with open(filename, "r+") as history:
    line = "\n"
    turn = 0
    oppcardcount = 4 - len(mycards)
    for a in history:
        line = a
        turn += 1
        if [c for c in line if c in lossActions]:
            oppcardcount -= 1
    else:
        flags.add("1")

    mycoins = int(mycoins)
    othercoins = int(othercoins)
    mycardcount = len(mycards)

    if line == 'T':
        othercoins += 3
        flags.add('d')
    elif line == 'S':
        othercoins += (2 if mycoins > 2 else mycoins)
        mycoins -= (2 if mycoins > 2 else mycoins)
        flags.add('c')
    elif line == 'A':
        othercoins -= 3
        mycardcount -= 1
        flags.add('A')
    elif line == 'F':
        flags.add('F')
    elif line == 'I\n':
        # If opponent is backing down, they're not so scary anymore
        flags.discard('d')
        flags.discard('c')
        flags.discard('F')

    # What's the least aggressive play that still wins?
    iGetStolen = ('c' in flags and not '*' in mycards and not '~' in mycards)
    iGetAssassinated = ('A' in flags and not '!' in mycards)
    incomeTimeToWin = max(0,7*oppcardcount-mycoins)+oppcardcount if not iGetStolen else 1000
    faidTimeToWin = max(0,7*oppcardcount-mycoins+1)//2+oppcardcount if not iGetStolen else 1000
    dukeTimeToWin = max(0,7*oppcardcount+(2*(oppcardcount-mycardcount) if iGetStolen else 0)-mycoins+2)//(3 if not iGetStolen else 1)+oppcardcount
    assassinTimeToWin = max(0,3*oppcardcount-mycoins)+oppcardcount if not iGetStolen else oppcardcount if mycoins >= 5*oppcardcount-2 else 1000
    captainTimeToWin = max(0,7*oppcardcount-mycoins+1)//2+oppcardcount
    faidAssassinTimeToWin = max(0,3*oppcardcount-mycoins+1)//2+oppcardcount if not iGetStolen else 1000
    dukeAssassinTimeToWin = max(0,3*oppcardcount+(2*(oppcardcount-mycardcount) if iGetStolen else 0)-mycoins+2)//(3 if not iGetStolen else 1)+oppcardcount
    captainAssassinTimeToWin = max(0,3*oppcardcount-mycoins+1)//2+oppcardcount
    opponentMoneySpeed = (2 if iGetStolen else 3 if 'd' in flags else 2 if 'F' in flags and not '$' in mycards else 1)
    opponentTimeToWin = max(0,(3 if iGetAssassinated else 7)*mycardcount-othercoins+opponentMoneySpeed-1)//opponentMoneySpeed+mycardcount
    opponentTimeToWinCaptained = max(0,(3 if iGetAssassinated else 7)*mycardcount+2*(mycardcount-oppcardcount)-(othercoins-2 if othercoins>2 else 0)+opponentMoneySpeed-3)//(opponentMoneySpeed-2)+mycardcount if opponentMoneySpeed > 2 else 1000

    def pickCardToLose():
        favoriteCards = []
        if dukeTimeToWin < opponentTimeToWin and '$' in mycards:
            favoriteCards = ['$', '!', '*', '~', '^']
        elif dukeAssassinTimeToWin < opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards:
            favoriteCards = ['^', '$', '!', '*', '~']
        elif assassinTimeToWin < opponentTimeToWin and '^' in mycards:
            favoriteCards = ['^', '!', '*', '~', '$']
        elif captainTimeToWin < opponentTimeToWinCaptained and '*' in mycards:
            favoriteCards = ['*', '!', '$', '^', '~']
        elif faidTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
            favoriteCards = ['!', '*', '~', '$', '^']
        elif faidAssassinTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
            favoriteCards = ['^', '!', '*', '~', '$']
        elif captainAssassinTimeToWin < opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
            favoriteCards = ['^', '*', '!', '$', '~']
        else:
            favoriteCards = ['!', '*', '~', '$', '^']
        # Losing a card.  Decide which is most valuable.
        for k in favoriteCards:
            if k in mycards:
                cardToLose = k
        return reveal_to_punishment[cardToLose]

    action = legalActions[0]
    if line == "\n":
        # First turn behavior
        if '$' in mycards and 'T' in legalActions:
            action = 'T'
            flags.add('$')
        elif '*' in mycards and 'S' in legalActions:
            action = 'S'
            flags.add('*')
        elif '^' in mycards and 'I\n' in legalActions:
            action = 'I\n'
            flags.add('^')
        elif '~' in mycards and 'E' in legalActions:
            action = 'E'
        elif 'T' in legalActions:
            # Contessa/Contessa?  Need to lie.
            action = 'T'
            flags.add('$')
    elif set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
        # This might change our strategy
        flags.discard(action)
    elif '$' in mycards and 'd' in legalActions:
        action = 'd'
    elif '~' in mycards and 'a' in legalActions:
        action = 'a'
    elif '*' in mycards and 'c' in legalActions:
        action = 'c'
    elif '!' in mycards and 's' in legalActions:
        action = 's'
    elif 'q' in legalActions and line[-1] in 'dacs':
        # We're committed at this point
        action = 'q'
    elif 'q' in legalActions and '*' in flags and line[-1] in 'SE':
        # Don't allow these when using a steal strategy
        action = 'q'
    elif 'q' in legalActions and turn == 1:
        if line == 'T':
            if mycards == '$$' or mycards == '^^' or mycards == '!!':
                action = 'q'
            else:
                action = 'p'
                flags.add('d')
        elif line == 'S':
            if '$' in mycards and '^' in mycards:
                action = 'p'
                flags.add('c')
            else:
                action = 'q'
        elif line == 'E':
            action = 'p'
    elif line == 'A' and len(mycards) > 1:
        # Don't challenge the first assasination.  We'll get 'em later.
        action = pickCardToLose()
        flags.add('A')
    elif line == 'A':
        # Can't let this pass
        action = 'q'
    elif line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
        # Also stop claiming what we were challenged for
        if line == "Tq":
            flags.discard('$')
        elif line == "Sq":
            flags.discard('*')
        elif line == "Aq":
            flags.discard('^')
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    else:
        if 'p' in legalActions:
            # Default to pass if no other action is chosen
            action = 'p'

        if dukeTimeToWin <= opponentTimeToWin and ('$' in mycards or '$' in flags):
            if 'C' in legalActions:
                action = 'C'
            elif 'T' in legalActions:
                action = 'T'
        elif incomeTimeToWin <= opponentTimeToWin:
            if 'C' in legalActions:
                action = 'C'
            elif 'I\n' in legalActions:
                action = "I\n"
        elif dukeAssassinTimeToWin <= opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards and mycardcount > 1:
            if 3*oppcardcount <= mycoins - (2*(oppcardcount-1) if iGetStolen else 0) and 'A' in legalActions:
                action = 'A'
            elif 'T' in legalActions:
                action = 'T'
            flags.add('^');
        elif assassinTimeToWin <= opponentTimeToWin and '^' in mycards:
            if 'A' in legalActions:
                action = 'A'
            elif 'I\n' in legalActions:
                action = 'I\n'
            flags.add('^');
        elif captainTimeToWin <= opponentTimeToWinCaptained and '*' in mycards:
            if 'C' in legalActions:
                action = 'C'
            elif 'S' in legalActions:
                action = 'S'
            elif 'I\n' in legalActions:
                action = 'I\n'
            flags.add('*');
        elif faidTimeToWin <= opponentTimeToWin and not 'd' in flags:
            if 'C' in legalActions:
                action = 'C'
            elif 'F' in legalActions:
                action = 'F'
        elif faidAssassinTimeToWin <= opponentTimeToWin and '^' in mycards and not 'd' in flags:
            if 'A' in legalActions:
                action = 'A'
            elif 'F' in legalActions:
                action = 'F'
            flags.add('^');
        elif captainAssassinTimeToWin <= opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
            if 'A' in legalActions:
                action = 'A'
            elif 'S' in legalActions:
                action = 'S'
            flags.add('^');
            flags.add('*');
        elif 'q' in legalActions:
            action = 'q'
        # No winning strategy.  Find something useful to do anyway.
        elif 'C' in legalActions and not '^' in flags:
            action = 'C'
        elif 'S' in legalActions and '*' in flags:
            action = 'S'
        elif 'A' in legalActions and '^' in flags:
            action = 'A'
        elif 'E' in legalActions and '~' in mycards and dukeAssassinTimeToWin < opponentTimeToWin:
            action = 'E'
        elif 'F' in legalActions and not 'd' in flags:
            action = 'F'
        elif 'T' in legalActions:
            action = 'T'
            flags.add('$');
    if action == 'q':
        if line == 'T' or line == 'Fd':
            flags.discard('d')
        elif line == 'S' or line == 'Sc':
            flags.discard('c')
        elif line == 'A':
            flags.discard('A')
    history.write(action)

if len(mycards) > 2:
    favoriteCards = []
    if dukeTimeToWin < opponentTimeToWin and '$' in mycards:
        favoriteCards = ['$', '!', '*', '~', '^']
    elif dukeAssassinTimeToWin < opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards:
        favoriteCards = ['^', '$', '!', '*', '~']
    elif assassinTimeToWin < opponentTimeToWin and '^' in mycards:
        favoriteCards = ['^', '!', '*', '~', '$']
    elif captainTimeToWin < opponentTimeToWinCaptained and '*' in mycards:
        favoriteCards = ['*', '!', '$', '^', '~']
    elif faidTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
        favoriteCards = ['!', '*', '~', '$', '^']
    elif faidAssassinTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
        favoriteCards = ['^', '!', '*', '~', '$']
    elif captainAssassinTimeToWin < opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
        favoriteCards = ['^', '*', '!', '$', '~']
    else:
        favoriteCards = ['!', '*', '~', '$', '^']
    # Losing two cards.  Decide which is most valuable.
    possibleCards = [k for k in favoriteCards if k in mycards]
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

with open(statefilename, "w") as statefile:
    statefile.write(filename+"\n")
    statefile.write(''.join(list(flags))+"\n")

Voltagabbana

Dice inizialmente la verità, ma inizia a mentire quando smette di essere sfidato. Ha anche un comportamento risolutore. (Un'approssimazione di come mi comporto giocando a questo gioco con gli umani)

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

statefilename = './state.txt'
myclaims = set()
otherclaims = set()
mycaughtlies = set()
othercaughtlies = set()
flags = set()
# Flags:
# * Opponent had a chance to challenge us just now
# & Opponent has stopped wildly challenging everything
# E We have exchanged at least once
# S Opponent did not block a steal.  Go for the jugular!
# _ Opponent has lost a card

with open(statefilename, "a+") as statefile:
    statefile.seek(0)
    if statefile.readline().strip() == filename:
        myclaims = set(statefile.readline().strip())
        otherclaims = set(statefile.readline().strip())
        mycaughtlies = set(statefile.readline().strip())
        othercaughtlies = set(statefile.readline().strip())
        flags = set(statefile.readline().strip())

def getFavoriteCards():
    favoriteCards = []
    if '*' in otherclaims:
        favoriteCards.append('~')
    elif not '~' in otherclaims:
        favoriteCards.append('*')
    if len(otherclaims) > (0 if '_' in flags else 1) and mycoins > 1 and not '!' in otherclaims:
        favoriteCards.append('^')
    favoriteCards.append('!')
    favoriteCards.append('$')
    if not '~' in favoriteCards:
        favoriteCards.append('~')
    return favoriteCards

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        line = a
    if 'q' in legalActions:
        otherclaims.add(punishment_to_reveal[actions_dict[line[-1]]])
    if len(line) > 2 and line.endswith('\n') and line[-2] in lossActions:
        otherclaims.discard(punishment_to_reveal[line[-2]])
        flags.add('_')
    if len(line) > 2 and line.endswith('\n') and (line.startswith('Ep') or line.startswith('Eq~')):
        othercaughtlies = set()
    if '*' in flags:
        flags.discard('*')
        if line[-1] not in 'qdacs':
            flags.add('&')
            if line[-2] == 'F':
                othercaughtlies.add('$')
            if line[-2] == 'S':
                othercaughtlies.add('*')
                othercaughtlies.add('~')
            if line[-2] == 'A':
                othercaughtlies.add('!')
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
        if action in reveal_to_punishment:
            myclaims.discard(action)
    elif '&' in flags:
        preferredActions = []
        mysafecards = myclaims.union(mycards)

        # Calculate the financial situation
        mygain = 0
        oppgain = 0
        if '*' in mysafecards and not '*' in otherclaims and not '~' in otherclaims:
            mygain += 2
            oppgain -= 2
        elif '$' in mysafecards:
            mygain += 3
        elif not '$' in otherclaims:
            mygain += 1 # This script doesn't use foreign aid
        else:
            mygain += 1
        if '*' in otherclaims and not '*' in mysafecards and not '~' in mysafecards:
            oppgain += 2
            mygain -= 2
        elif '$' in mysafecards:
            oppgain += 3
        elif not '$' in otherclaims:
            oppgain += 2
        else:
            oppgain += 1
        mydist = 7 - int(mycoins)
        oppdist = 7 - int(othercoins)
        if '^' in mysafecards and len(otherclaims) > (0 if '_' in flags else 1) and not '!' in otherclaims:
            mydist -= 4
        if '^' in otherclaims and not '!' in mysafecards:
            oppdist -= 4
        if mydist > 0 and (oppdist <= 0 or mygain <= 0 or (oppgain > 0 and ((oppdist+oppgain-1) // oppgain) < ((mydist+mygain-1) // mygain))):
            # Not winning.  Do something desperate.
            timeToLive = ((oppdist+oppgain-1) // oppgain) if oppdist > 0 else 0
            favoriteCards = getFavoriteCards()
            if timeToLive < len(otherclaims):
                preferredActions.append('q')
            if (timeToLive or len(mycards) > 1) and favoriteCards[0] not in mysafecards:
                preferredActions.append('E')
            elif mycoins >= 3 and random.randint(0,2):
                preferredActions.append('A')
            else:
                preferredActions.append('S')

        preferredActions.append('s')
        if 'a' in legalActions and ('~' in mycards or '*' in mycards) and not 's' in flags:
            # Allow the first steal, as bait
            preferredActions.append('p')
            flags.add('s')
            if '~' in mycards:
                flags.discard('E')
        if '$' in mysafecards:
            preferredActions.append('d')
        if '~' in mysafecards:
            preferredActions.append('a')
        elif '*' in mysafecards:
            preferredActions.append('c')
        else:
            preferredActions.append('c' if random.randint(0,1) else 'a')
        if not 'E' in flags:
            preferredActions.append('E')
        if not ('~' in otherclaims or '*' in otherclaims):
            preferredActions.append('S')
        if len(otherclaims) > (0 if '_' in flags else 1) and ('^' in mycards or not '_' in flags) and not '!' in otherclaims:
            preferredActions.append('A')
        preferredActions.append('T')
        if line[-1] in actions_dict and punishment_to_reveal[actions_dict[line[-1]]] in othercaughtlies:
            preferredActions.append('q')
        preferredActions += ['p', '\n']
        if len(myclaims) < len(mycards):
            # Slip a lie in before admitting all cards in hand
            preferredActions = [a for a in preferredActions
                if not a in actions_dict
                or not punishment_to_reveal[actions_dict[a]] in mysafecards]
        else:
            preferredActions = [a for a in preferredActions
                if not a in actions_dict
                or punishment_to_reveal[actions_dict[a]] in mycards
                or not punishment_to_reveal[actions_dict[a]] in mycaughtlies]
        preferredActions = [a for a in preferredActions if a in legalActions]
        if preferredActions:
            action = preferredActions[0]
        else:
            loss = pickCardToLose()
            if loss in legalActions:
                action = loss
            elif loss+"\n" in legalActions:
                action = loss+"\n"
    else:
        preferredActions = []
        if not ('~' in otherclaims or '*' in otherclaims):
            preferredActions.append('S')
        preferredActions += ['T', 'E', 'd', 'a', 'c', 's', 'p', '\n']
        if not '!' in otherclaims:
            preferredActions.append('A')
        preferredActions = [a for a in preferredActions if a in legalActions]
        # Filter out lies, provided that doesn't filter out everything
        preferredActions = [a for a in preferredActions
            if not a in actions_dict
            or punishment_to_reveal[actions_dict[a]] in mycards
        ] or [a for a in preferredActions
            if not a in actions_dict
            or not punishment_to_reveal[actions_dict[a]] in mycaughtlies
        ]
        if preferredActions:
            action = preferredActions[0]
        else:
            loss = pickCardToLose()
            if loss in legalActions:
                action = loss
            elif loss+"\n" in legalActions:
                action = loss+"\n"
        if 'a' in legalActions:
            if action not in 'acq':
                # If vulnerable to stealing, don't admit it!
                action = random.choice('acq')
            elif not 's' in flags:
                # Allow the first steal, as bait
                action = 'p'
                flags.add('s')
                if '~' in mycards:
                    flags.discard('E')
    if action.strip("\n") in lossActions:
        myclaims.discard(punishment_to_reveal[action.strip("\n")])
        if line[-1] == 'q':
            # Also stop claiming what we were challenged for
            myclaims.discard(punishment_to_reveal[actions_dict[line[-2]]])
            mycaughtlies.add(punishment_to_reveal[actions_dict[line[-2]]])
    if action == 'q':
        # We challenged it.  One way or another, they will not have this card later.
        otherclaims.discard(punishment_to_reveal[actions_dict[line[-1]]])
        othercaughtlies.add(punishment_to_reveal[actions_dict[line[-1]]])
    if action in actions_dict:
        myclaims.add(punishment_to_reveal[actions_dict[action]])
        flags.add('*')
    history.write(action)

if len(mycards) > 2:
    flags.add('E')
    mycaughtlies = set()
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    # After an exchange, we can claim what we like.  Throw in some lying for more flexibility.
    myclaims = set()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if random.randint(1,len(possibleCards)) > len(mycards) - 2:
        myclaims.add(possibleCards[0])
        possibleCards = possibleCards[1:]
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

with open(statefilename, "w") as statefile:
    statefile.write(filename+"\n")
    statefile.write(''.join(list(myclaims))+"\n")
    statefile.write(''.join(list(otherclaims))+"\n")
    statefile.write(''.join(list(mycaughtlies))+"\n")
    statefile.write(''.join(list(othercaughtlies))+"\n")
    statefile.write(''.join(list(flags))+"\n")

Bandito

Cerca di sbarazzarsi degli ambasciatori e dei capitani dell'avversario e di vincere rubando.

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

def getFavoriteCards():
    return ['*', '!', '~', '$', '^']

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    turn = 0
    for a in history:
        line = a
        turn += 1
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
    elif 'p' in legalActions and turn == 1 and line == "E":
        # Let this pass... once
        action = 'p'
    elif 'q' in legalActions and line[-1] in 'SEac':
        # These get in the way of stealing, get rid of them even if it costs us a card
        action = 'q'
    elif 'E' in legalActions and '~' in mycards and '*' not in mycards:
        action = 'E'
    elif 'S' in legalActions:
        action = 'S'
    elif 's' in legalActions:
        if '!' in mycards:
            action = 's'
        elif len(mycards) == 1:
            action = random.choice('sq')
        else:
            action = pickCardToLose()
    elif 'p' in legalActions:
        action = 'p'
    elif line == 'A' or line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    history.write(action)

if len(mycards) > 2:
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if mycards.count('*') > 1:
        # Hooray captains!
        possibleCards = ['*'] + possibleCards
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

Bloody Murder

Una controparte di Bandit, questo va all-in su una strategia Duke + Assassin.

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

def getFavoriteCards():
    return ['^', '$', '!', '*', '~']

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    stealHappened = 0
    oppcardcount = 4 - len(mycards)
    for a in history:
        line = a
        if line[0] == 'S':
            stealHappened = 1
        if [c for c in line if c in lossActions]:
            oppcardcount -= 1
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
    elif 'q' in legalActions and line[-1] in 's':
        # We need this gone
        action = 'q'
    elif 'E' in legalActions and '~' in mycards:
        action = 'E'
    elif 'A' in legalActions and (len(mycards) == 1 or mycoins >= 3*oppcardcount+(2 if stealHappened and oppcardcount>1 else 0)):
        action = 'A'
    elif 'T' in legalActions:
        action = 'T'
    elif 'd' in legalActions:
        action = 'd'
    elif 'c' in legalActions and '*' in mycards:
        action = 'c'
    elif 'a' in legalActions and '~' in mycards:
        action = 'a'
    elif 's' in legalActions:
        if '!' in mycards:
            action = 's'
        elif len(mycards) == 1:
            action = random.choice('sq')
        else:
            action = pickCardToLose()
    elif 'p' in legalActions:
        action = 'p'
    elif line == 'A' or line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    history.write(action)

if len(mycards) > 2:
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if mycards.count('^') > 1:
        # Hooray assassins!
        possibleCards = ['^'] + possibleCards
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

Tutto aggiunto alle classifiche e sta andando abbastanza bene! Potrei suggerire di rinominare Betrayer in Turncoat? Lo rende un po 'più drammatico :)
Purple P

@PurpleP Rinominato! "Traditore" fu una scelta un po 'frettolosa; in realtà è stato chiamato dopo me stesso durante lo sviluppo, ma non sembrava giusto una volta che avevo più concorrenti.
Brilliand,

Il calcolatore è stato aggiunto alle classifiche.
Viola P

1
Congratulazioni, la calcolatrice è il re della collina!
Purple P,

4

Risolutore

Il Risolutore prova a ricordare quali carte sono state giocate prima e quali erano le mosse precedenti dell'avversario.

questa è la seconda versione non ancora terminata (ed è un gran casino adesso)

per farlo funzionare sul nodo 10 aggiungere competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))

se nodo 12 competitors.append(Player("Solver", ["node", "./solver.js"]))

fare attenzione al tipo di file

import  fs from 'fs'
import { promisify } from 'util'

const appendFile = promisify(fs.appendFile)
const writeFile = promisify(fs.writeFile)
const readFile = promisify(fs.readFile)

const delay = ms => new Promise(_ => setTimeout(_, ms));

let [filename, othercoins, mycoins, mycards ] = process.argv.slice(2)
othercoins = +othercoins
mycoins = +mycoins

const move = async m => await appendFile(filename, m)
const message = m => process.stdout.write(m)
const endTurn = async _ => await move(`\n`) 

const stateFileName = `./state.json`

const defaultState = {
    inTheDeck: [],
    oponentCards: [],
    oponentMissingTempCard: "",
    oponentMissingCards: [],
    oponentDropedCards: [],
    oponentCardModifier: 0
}

const CardTypes = Object.freeze({
    Ambassador : `Ambassador`,
    Assassin : `Assassin`,
    Captain  : `Captain`,
    Contessa : `Contessa`,
    Duke     : `Duke`,
})

const revealTable = Object.freeze({
    [CardTypes.Ambassador]: `~`,
    [CardTypes.Assassin]: `^`,
    [CardTypes.Captain]: `*`,
    [CardTypes.Contessa]: `!`,
    [CardTypes.Duke]: `$`,
})

const giveUpTable = Object.freeze({
    [CardTypes.Ambassador]: `_`,
    [CardTypes.Assassin]: `'`,
    [CardTypes.Captain]: `<`,
    [CardTypes.Contessa]: `=`,
    [CardTypes.Duke]: `0`,
})

function GetRevealCardChar(cardType) {
    return revealTable[cardType]
}

function GetRevealCardType(char) {
    return Object.keys(revealTable).find(key => revealTable[key] === char)
}

function GetGiveUpCardChar(cardType) {
    return giveUpTable[cardType]
}

function GetGiveUpCardType(char) {
    return Object.keys(giveUpTable).find(key => giveUpTable[key] === char)
}

async function GiveUpCard(cardType, endTurn = false) {
    return await move(
        GetGiveUpCardChar(cardType) + `${endTurn?`\n`:``}`
    );
}

function OponentCanHave(cardType) {
    // it has it
    if (!!~state.oponentCards.indexOf(cardType)) return true

    if (state.oponentCards.length + state.oponentDropedCards.length >= 2) return false

    return true
}


function GiveCard(getOrder = false) {
    // TODO: Tactic
    const giveAwayOrder = [
        CardTypes.Captain,
        CardTypes.Ambassador,
        CardTypes.Contessa,
        CardTypes.Assassin,
        CardTypes.Duke,
    ]

    const tmp =  mycards
        .split('')
        .map(GetRevealCardType)

    let [unique, duplicate] = tmp.reduce(([unique, duplicate], item) => {
        return unique.includes(item) ? 
            [unique, [...duplicate, item]] :
            [[...unique, item], duplicate]
    }
    , [[],[]])

    unique.sort(
        (a, b) => giveAwayOrder.indexOf(a) - giveAwayOrder.indexOf(b));
    duplicate.sort(
        (a, b) => giveAwayOrder.indexOf(a) - giveAwayOrder.indexOf(b))

    const out = [...duplicate, ...unique]

    return getOrder? out: GetGiveUpCardChar(out[0]);
}

const iHaveAmbassador = !!~mycards.indexOf(`~`)
const iHaveAssassin = !!~mycards.indexOf(`^`)
const iHaveCaptain = !!~mycards.indexOf(`*`)
const iHaveContessa = !!~mycards.indexOf(`!`)
const iHaveDuke = !!~mycards.indexOf(`$`)

let state = defaultState

;(async ()=>{
    const data = (await readFile(filename, `utf8`)).replace(/\r/g, ``)

    const isNewGame = data === "" && mycoins === 1 && othercoins === 1

    if (isNewGame) {
        await writeFile(stateFileName, JSON.stringify(state))
    } else {
        state = JSON.parse(await readFile(stateFileName, `utf8`))
    }
    //console.error(state);
    let line = data.split(/\n/g).pop()

    // I am in the exchnage
    if (mycards.length >= 3) {
        const [c1, c2] = GiveCard(true).reverse()

        if (mycards.length === 3) {
            state.inTheDeck.push(c1)
            message(GetRevealCardChar(c1))
        }
        if (mycards.length === 4) {
            state.inTheDeck.push(c1, c2)
            message(`${GetRevealCardChar(c1)}${GetRevealCardChar(c2)}`)
        }
        return await move(`\n`)
    }

    const newTurn = line === ``

    if (newTurn) {
        if (mycoins >= 7) {
            return await move(`C`)
        }

        if (othercoins >= 6) {
            if (iHaveCaptain) 
                return await move(`S`)


            if (mycoins <= 6 && mycards.length <= 1) {
                // TODO: bluff 
            }
        }

        if (
            !iHaveDuke &&
            !iHaveContessa &&
            iHaveAmbassador
        ) {
            return await move(`E`)
        }

        // Assasinate if oponent has no Contessa
        if (
            mycoins >= 3 &&
            iHaveAssassin &&
            !~state.oponentCards.indexOf(CardTypes.Contessa)
        ) {
            return await move(`A`)
        }

        if (iHaveDuke) {

            return await move(`T`)
        }

        return await move(`I\n`)
    }

    // Exchange
    if (line === `Eq`) {
        if (iHaveAmbassador)
            return await move(GetRevealCardChar(CardTypes.Ambassador))

        return await GiveUpCard(GiveCard(true)[0])
    }

    // Tax Challenge
    if(line === `Tq`) {
        if (iHaveDuke)
            return await move(GetRevealCardChar(CardTypes.Duke))

        return await GiveUpCard(GiveCard(true)[0])
    }


    if (line === `Sa`) {
        if (!~state.oponentCards.indexOf(CardTypes.Ambassador)) {
            state.oponentMissingTempCard = CardTypes.Ambassador
            return await move(`q`)
        }
        return await endTurn()
    }

    if (line === `Sc`) {
        if (!~state.oponentCards.indexOf(CardTypes.Captain)) {
            state.oponentMissingTempCard = CardTypes.Captain
            return await move(`q`)
        }
        return await endTurn()
    }

    if (line=== `Saq${GetRevealCardChar(CardTypes.Ambassador)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Ambassador
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line=== `Scq${GetRevealCardChar(CardTypes.Captain)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Captain
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line === `Sq`) {
        if (iHaveCaptain)
            return await move(GetRevealCardChar(CardTypes.Captain))

        return await GiveUpCard(GiveCard(true)[0])
    }

    // Assassinate Block and Chalange it
    if (line === `As`) {
        state.oponentMissingTempCard = CardTypes.Contessa
        return await move(`q`)
    }

    // Assasint blocked by Contessa
    if (line === `Asq${GetRevealCardChar(CardTypes.Contessa)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Contessa
        )
        // Assassin useless here lets give it up
        return await GiveUpCard(CardTypes.Assassin, true)
    }

    // Assassinate challenge
    if (line === `Aq`) {
        if (iHaveAssassin)
            return await move(GetRevealCardChar(CardTypes.Assassin))

        return await GiveUpCard(GiveCard(true)[0])
    }


    // Defense Moves
    if (line === `C`) {
        return await GiveUpCard(GiveCard(true)[0])
    }


    if (line === `A`) {
        if (iHaveContessa)
            return await move(`s`)


        if (!!~state.oponentCards.indexOf(CardTypes.Assassin)) {
            // If oponent has an Assasin card lets bluff
            return await move(`s`)
        } else {
            state.oponentMissingTempCard = CardTypes.Assassin
            return await move(`q`)
        }

    }

    if (line === `Aq${GetRevealCardChar(CardTypes.Assassin)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Assassin
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line === `Asq`) {
        if (iHaveContessa)
            return await move(GetRevealCardChar(CardTypes.Contessa))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `S`) {
        if (iHaveAmbassador)
            return await move(`a`)

        if (iHaveCaptain)
            return await move(`c`)

        return await move(`p`)
    }

    if (line === `Saq`) {
        if (iHaveAmbassador)
            return await move(GetRevealCardChar(CardTypes.Ambassador))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `Scq`) {
        if (iHaveCaptain)
            return await move(GetRevealCardChar(CardTypes.Captain))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `F`) {
        if (iHaveDuke)
            return await move(`d`)

        return await move(`p`)
    }

    if (line === `Fdq`) {
        if (iHaveDuke)
            return await move(GetRevealCardChar(CardTypes.Duke))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `E`) {
        if (!OponentCanHave(CardTypes.Ambassador)) {
            return await move(`q`)
        }

        state.oponentCards = []
        state.oponentMissingCards = []
        state.oponentMissingTempCard = ''

        return await move(`p`)
    }


    if (line === `Eq${GetRevealCardChar(CardTypes.Ambassador)}`) {
        console.error(111, `THIS SHOULD NEVER HAPPEN`)
        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `T`) {
        if (!OponentCanHave(CardTypes.Duke)) {
            return await move(`q`)
        }
        return await move(`p`)
    }

    if (line === `Tq${GetRevealCardChar(CardTypes.Duke)}`) {
        console.error(111, `THIS SHOULD NEVER HAPPEN`)
        return await GiveUpCard(GiveCard(true)[0])
    }


    // remove oponents drop card from the state
    // can't detect if oponent has the same card twice
    if (!!~Object.values(giveUpTable).indexOf(line.substr(-1))) {
        // Catch the bluff
        if (state.oponentMissingTempCard !== "") {
            state.oponentMissingCards.push(state.oponentMissingTempCard)
            state.oponentMissingTempCard = ""
        }

        // maybe we should asume user doeas not has the same card?

        const cardType = GetGiveUpCardType(line.substr(-1))
        state.oponentCards.filter(c => c !== cardType)
        state.inTheDeck.push(cardType)
        state.oponentDropedCards.push(cardType)
    }

    return await endTurn()

})()
.then(async () => {
    await writeFile(stateFileName, JSON.stringify(state))
})
.catch(console.error.bind(console))


```

Dal momento che non sfidate mai lo scambio di un avversario, potreste volerne rendere conto, poiché invalida la vostra conoscenza delle loro carte.
Viola P

La nuova versione è aggiornata, è un pò un accordo con Exchange
Peter,

1
Aggiornerò la classifica quando pubblichi la versione finita.
Purple P,

Grazie, ho appena rilasciato Se il giocatore mostra alla sua carta quell'ID carta rimossa dalla sua mano e aggiunto al mazzo. Ciò rende errata metà della mia logica: DI ha bisogno di risolverlo. (Sono sorpreso di come ho fatto un punteggio così buono con una logica sbagliata) pastebin.com/AXGJ9v5Q <--- ultimi 2 turni! mi è stata tolta la mano. O è un bug?
Peter,

Questo non è un bug. Quando riveli una carta per vincere una sfida, questa viene rimossa dalla tua mano e ti viene data una nuova dal mazzo.
Purple P,

3

Avvocato

L'avvocato si fa strada cautamente nel mondo, non mentendo mai, bloccando quando possibile, sfidando quando non a suo danno immediato. Non attacca se non quando richiesto dall'accoppiamento, ma prenderà le monete il più spesso possibile per abbattere rapidamente. È abbastanza intelligente da sacrificare le carte che non usa per primo, ma non abbastanza da usarle per sbarazzarsene e ottenerne di nuove.

import sys

_, filename, othercoins, mycoins, mycards = sys.argv[:5]


def give_card():
    if "^" in mycards:
        return "'"
    if "~" in mycards:
        return "_"
    if "!" in mycards:
        return "="
    if "*" in mycards:
        return "<"
    return "0"


with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        print("line:", a)
        line = a
    if line.endswith("\n"):
        if int(mycoins) >= 10:
            history.write("C")
        elif "$" in mycards:
            history.write("T")
        elif "*" in mycards and int(othercoins) > 0:
            history.write("S")
        else:
            history.write("F")
    elif line == "F":
        if "$" in mycards:
             history.write("d")
        else:
             history.write("p")
    elif line == "C":
        history.write(give_card())
    elif line == "E":
        if len(mycards) > 1:
            history.write("q")
        else: 
            history.write("p")
    elif line == "T":
        if len(mycards) > 1:
            history.write("q")
        else: 
            history.write("p")
    elif line == "A":
        if "!" in mycards:
            history.write("s")
        else: 
            history.write(give_card())
    elif line == "S":
        if "~" in mycards:
            history.write("a")
        elif "*" in mycards:
            history.write("c")
        elif len(mycards) > 1:
            history.write("q")
        else:
            history.write("p")
    elif line.endswith("d") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("a") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("c") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("s") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("sq"):
        history.write("!")
    elif line.endswith("aq"):
        history.write("~")
    elif line.endswith("cq"):
        history.write("*")
    elif line.endswith("dq"):
        history.write("$")
    elif line.endswith("Tq"):
        history.write("$")
    elif line.endswith("Sq"):
        history.write("*")
    elif line[-1] in "~^*!$":
        history.write(give_card())
        if line[-3] in "acds":
            history.write("\n")
    else:
        history.write("\n")

Probabilmente ci sono bug in questo programma. Quando li trovi, per favore fammi sapere.


@PurpleP Buon punto. L'ho risolto. Le capacità decisionali sono molto importanti per un buon avvocato.
Hiatsu,

Hai verificato che il file in realtà non termina con una nuova riga? (es. aprendo il file e vedendo una lettera maiuscola nel mezzo della riga?) Sto esaminando le cause di ciò e voglio assicurarmi che sia escluso.
Hiatsu,

@PurpleP Posso caricare una versione di debug che utilizza STDOUT per scopi non di scambio e mi avete inviato i risultati?
Hiatsu,


Mask e Lawyer possono entrare in un circuito che li fa perdere entrambi. Se l'avvocato ha una carta che non è un duca, proverà sempre a rubare. Quindi Mask chiederà sempre a un Ambasciatore di bloccarlo e scambia per coprire le sue tracce. Esempio di gioco. Non mi lamento o ti chiedo di aggiustarlo; Volevo solo che lo sapessi perché è abbastanza divertente.
Purple P,

2

Casuale

Casuale non sa cosa fare, quindi seleziona casualmente qualcosa di legale.

package main

import (
    "fmt"
    "math/rand"
    "os"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    filename := os.Args[1]
    ourCards := os.Args[4]
    legalActions := os.Args[5:]
    file, _ := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND, 0755)
    defer file.Close()

    file.WriteString(legalActions[rand.Intn(len(legalActions))])
    switch len(ourCards) {
    case 3:
        os.Stdout.Write([]byte{ourCards[rand.Intn(3)]})
    case 4:
        i1 := 0
        i2 := 0
        for ok := true; ok; ok = i1 == i2 {
            i1 = rand.Intn(4)
            i2 = rand.Intn(4)
        }
        keptCards := []byte{ourCards[i1], ourCards[i2]}
        os.Stdout.Write(keptCards)
    }
}

Sfidante

Challenger non si fida di nessuno in questo gioco dell'inganno. Se fai qualcosa di sfidante, ti sfiderà. Altrimenti prende entrate ogni turno e cerca di farti Coup se ha le monete.

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
)

var revealToPunishment = map[byte]byte{'~': '_', '^': '\'', '*': '<', '!': '=', '$': '0'}

func main() {
    filename := os.Args[1]
    coinCount := os.Args[3]
    ourCards := os.Args[4]
    file, _ := os.OpenFile(filename, os.O_RDWR, 0755)
    defer file.Close()

    rawBytes, _ := ioutil.ReadAll(file)
    if len(rawBytes) == 0 {
        file.Write([]byte("I\n"))
        return
    }
    lines := bytes.Split(rawBytes, []byte{'\n'})
    switch rawBytes[len(rawBytes)-1] {
    case '\n':
        // Our turn, do we have enough coins for a Coup?
        if c, _ := strconv.Atoi(coinCount); c >= 7 {
            file.Write([]byte{'C'})
            // We don't, so take income.
        } else {
            file.Write([]byte("I\n"))
        }
    // Opponent did something challengeable. We don't believe them for a second.
    // Challenge it.
    case 'E', 'T', 'A', 'S', 'a', 'c', 'd', 's':
        file.Write([]byte{'q'})
    // Opponent Couped us or our challenge failed. Give up a card.
    case 'C':
        file.Write([]byte{revealToPunishment[ourCards[0]]})
    case '~', '*', '^', '!', '$':
        file.Write([]byte{revealToPunishment[ourCards[0]]})
        lastLine := lines[len(lines)-1]
        switch lastLine[len(lastLine)-3] {
        case 'a', 'c', 'd', 's':
            file.WriteString("\n")
        }
    // Our challenge succeeded or we Couped the opponent! End our turn.
    case '_', '\'', '<', '=', '0':
        file.Write([]byte{'\n'})
    default:
        // Opponent took some other action. Let it pass.
        file.Write([]byte{'p'})
    }
}

Compila questi programmi con go build random.go/challenger.go ed eseguirli con ./randomo ./challenger.


Consiglio di non assegnare il genere ai programmi per computer. Vi è già sufficiente propensione al genere nelle comunità di programmazione e i pronomi maschili inadempienti dimostrano ulteriormente che le donne non sono gradite.
Greg Martin,

2

Commercialista

Il Taxman è qui per riscuotere le tasse. Usa l'assassino se ne ha uno. Blocca solo se hanno la carta da bloccare. Sfide casuali.

Scritto in c #, ho trascorso troppo tempo a costruire una gerarchia di classi per tutte le diverse azioni che possono essere intraprese.

Modifica: ora con una logica migliorata come non pretendere di avere un duca quando hanno rinunciato a un duca dopo essere stati sfidati. Inoltre, non cerca più di assassinare continuamente se l'avversario blocca con contessa (e non è sfidato).

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

internal static class Program
{
    public static void Main(string[] args)
    {
#if DEBUG
        // Can't figure out how to pass newline as a command line arg.
        for (int i = 0; i < args.Length; i++)
        {
            if (args[i] == "I\\n")
                args[i] = "I\n";
        }
#endif
        if (!ProcessArgs(args, out string filename, out int opCoin, out int myCoin, out IEnumerable<Card> cards, out IEnumerable<Output> validOutputs))
        {
            Console.WriteLine("Error with args.");
            return;
        }

        var taxman = new Taxman(filename, opCoin, myCoin, cards, validOutputs);
        taxman.DukeEm();
    }

    private static bool ProcessArgs(string[] args, out string filename, out int opCoin, out int myCoin, out IEnumerable<Card> cards, out IEnumerable<Output> validOutputs)
    {
        if (args.Length < 4)
        {
            throw new InvalidOperationException("Error: Not enough args.");
        }
        bool success = true;

        filename = args[0];
        success &= int.TryParse(args[1], out opCoin) && opCoin >= 0 && opCoin <= 12;
        success &= int.TryParse(args[2], out myCoin) && myCoin >= 0 && myCoin <= 12;

        cards = Card.ParseSymbols(args[3]);

        IEnumerable<char> validOutputArgs = args.Skip(4).Select(outputArg => outputArg.First());
        // Income and Surrenders on our turn include \n, we use chars below so don't include the newline, hence the call to .First().
        // Code below should be smart enough to also write a newline if necessary.

        validOutputs = Output.ParseSymbols(validOutputArgs);
        return success;
    }
}

internal sealed class Taxman
{
    private const string _OustedAsDukeFileName = "MyTotallyCoolStateFile.txt";
    private const string _OppClaimsContessaFileName = "OppClaimsContess.txt";
    private readonly Random _Rand = new Random();
    private readonly List<Card> _GiveUpPreferences = new List<Card> { Card.Duke, Card.Assassin, Card.Ambassador, Card.Contessa, Card.Captain };

    private double BaseProbabilityToChallenge => 0.1d;
    private bool _Written = false;
    private bool _MyTurn;
    private bool? _OustedAsDuke = null;
    private bool? _OppClaimsContessa = null;

    private string FileName { get; }
    private int OppCoin { get; }
    private int MyCoin { get; }
    private IEnumerable<Card> Cards { get; }
    private IEnumerable<Output> ValidOutputs { get; }
    private IEnumerable<Output> GameSoFar { get; }
    private int OppCardCount { get; }
    private int MyCardCount => Cards.Count();

    private int OppScore => (10 * OppCardCount) + OppCoin;
    private int MyScore => (10 * MyCardCount) + MyCoin;

    private bool OustedAsDuke
    {
        get
        {
            if (_OustedAsDuke.HasValue)
            {
                return _OustedAsDuke.Value;
            }
            else
            {
                if (string.IsNullOrWhiteSpace(File.ReadAllText(_OustedAsDukeFileName)))
                {
                    _OustedAsDuke = false;
                    return false;
                }
                else
                {
                    _OustedAsDuke = true;
                    return true;
                }
            }
        }
        set
        {
            File.WriteAllText(_OustedAsDukeFileName, value ? "Ousted" : string.Empty);
            _OustedAsDuke = value;
        }
    }

    private bool OppClaimsContessa
    {
        get
        {
            if (_OppClaimsContessa.HasValue)
            {
                return _OppClaimsContessa.Value;
            }
            else
            {
                if (string.IsNullOrWhiteSpace(File.ReadAllText(_OppClaimsContessaFileName)))
                {
                    _OppClaimsContessa = false;
                    return false;
                }
                else
                {
                    _OppClaimsContessa = true;
                    return true;
                }
            }
        }
        set
        {
            File.WriteAllText(_OppClaimsContessaFileName, value ? "Claimed" : string.Empty);
            _OppClaimsContessa = value;
        }
    }

    public Taxman(string fileName, int oppCoin, int myCoin, IEnumerable<Card> cards, IEnumerable<Output> validOutputs)
    {
        FileName = fileName; OppCoin = oppCoin; MyCoin = myCoin; Cards = cards; ValidOutputs = validOutputs;

        GameSoFar = ReadFile();

        //calculate how many cards the opponent has.
        int giveUps = GameSoFar.Count(output => output is GiveUp);
        int myGiveUps = 2 - MyCardCount;
        var oppGiveUps = giveUps - myGiveUps;
        OppCardCount = 2 - oppGiveUps;
    }

    public void DukeEm()
    {
        if (Cards.Skip(2).Any())
        {
            Exchange();
            Write(Output.EndTurn);
            return;
        }

        var prev = GameSoFar.LastOrDefault() ?? Output.EndTurn;
        if (prev == Output.EndTurn) // Income is I\n so shows up as an EndTurn
        {
            ChooseAction();
        }
        else if (prev == Action.ForeignAid)
        {
            if (!OustedAsDuke)
                Write(Block.Duke);
            else
                Write(Output.Pass);
        }
        else if (prev == Action.Coup)
        {
            GiveUpDecide();
        }
        else if (prev == ChallengeableAction.Exchange || prev == ChallengeableAction.Tax)
        {
            if (ShouldChallenge((ChallengeableAction)prev))
                Write(Output.Challenge);
            else
                Write(Output.Pass);
        }
        else if (prev == ChallengeableAction.Assassinate)
        {
            RespondToAssassinate();
        }
        else if (prev == ChallengeableAction.Steal)
        {
            RespondToSteal();
        }
        else if (prev == Block.Duke || prev == Block.Ambassador || prev == Block.Captain || prev == Block.Contessa)
        {
            Debug.Assert(prev == Block.Contessa, "We should never take an action that a different card would block.");

            if (ShouldChallenge((Block)prev))
                Write(Output.Challenge);
            else
            {
                Write(Output.EndTurn);
                OppClaimsContessa = true;
            }
        }
        else if (prev == Output.Pass)
        {
            Write(Output.EndTurn);
        }
        else if (prev == Output.Challenge)
        {
            var challengedOutput = (IChallengeable)GameSoFar.TakeLast(2).First();
            RespondToChallenge(challengedOutput);
        }
        else if (prev is Card)
        {
            GiveUpDecide();
        }
        else if (prev is GiveUp)
        {
            if (prev == GiveUp.Contessa)
                OppClaimsContessa = false;

            Write(Output.EndTurn);
        }
        else
        {
            Debug.Fail("Should have hit one of the conditions above.");
            WriteRandomValid();
        }
    }

    private void Exchange()
    {
        int handSize = MyCardCount - 2;
        var cardsToKeep = new List<Card>();
        var workingCards = Cards.ToList();

        while (cardsToKeep.Count < handSize)
        {
            if (!cardsToKeep.Contains(Card.Duke) && workingCards.Remove(Card.Duke))
                cardsToKeep.Add(Card.Duke);
            else if (!cardsToKeep.Contains(Card.Assassin) && !OppClaimsContessa && workingCards.Remove(Card.Assassin))
                cardsToKeep.Add(Card.Assassin);
            else if (!cardsToKeep.Contains(Card.Ambassador) && workingCards.Remove(Card.Ambassador))
                cardsToKeep.Add(Card.Ambassador);
            else if (!cardsToKeep.Contains(Card.Contessa) && workingCards.Remove(Card.Contessa))
                cardsToKeep.Add(Card.Contessa);
            else if (!cardsToKeep.Contains(Card.Captain) && workingCards.Remove(Card.Captain))
                cardsToKeep.Add(Card.Captain);
            else
            {
                cardsToKeep.Add(workingCards[0]);
                workingCards.RemoveAt(0);
            }
        }
        var keptCards = new string(cardsToKeep.Select(card => card.Symbol).ToArray());
        Console.WriteLine(keptCards);
    }

    private IEnumerable<Output> ReadFile()
    {
        var text = File.ReadAllText(FileName);

        // Check if we're at the start of the game, 1 character means our opponent went first.
        if (text == null || text.Length <= 1)
        {
            // Do any start up like creating a state file.
            Debug.Assert(MyCardCount == 2 && MyCoin == 1 && OppCoin == 1, "Should always start with 2 cards in hand and have 1 coin each.");
            using (File.Create(_OustedAsDukeFileName))
            using (File.Create(_OppClaimsContessaFileName))
            { ; }
        }

        var lastLine = text.Split('\n').LastOrDefault();
        _MyTurn = lastLine == null || lastLine.Length % 2 == 0;

        return Output.ParseSymbols(text);
    }

    private void ChooseAction()
    {
        if (MyCoin >= 3 && Cards.Contains(Card.Assassin))
        {
            // If we have the coins to assasinate and have the card to assasinate then go for it.
            Write(ChallengeableAction.Assassinate);
        }
        else if (MyCoin >= 7)
        {
            // If we have the coins to coup then go for it.
            Write(Action.Coup);
        }
        else if (Cards.Contains(Card.Ambassador) && !Cards.Contains(Card.Duke))
        {
            // If we don't /actually/ have a duke but we do have ambassador and can exchange into one, then try do that.
            Write(ChallengeableAction.Exchange);
            // TODO if we've exchanged multiple times already perhaps we should try something different?
        }
        else if (!OustedAsDuke)
        {
            // Take tax because We totally always have a duke.
            // Except if we've been previously challenged and shown to not have a duke, in which case exchange to get a new Duke.
            Write(ChallengeableAction.Tax);
        }
        else
        {
            Write(ChallengeableAction.Exchange);
            // Even if we don't find a duke from the exchange we can pretend that we did.
            OustedAsDuke = false;
        }
    }

    private void RespondToAssassinate()
    {
        if (Cards.Contains(Card.Contessa))
            Write(Block.Contessa);
        else if (MyCardCount <= 1)
        {
            // We will lose if we don't challenge or block.
            if (ShouldRandomChallenge(0.5d))
                Write(Output.Challenge);
            else
                Write(Block.Contessa);
        }
        else if (ShouldChallenge(ChallengeableAction.Assassinate))
            Write(Output.Challenge);
        else
            GiveUpDecide();
    }

    private void RespondToSteal()
    {
        // prefer to block with ambassador before captain.
        if (Cards.Contains(Card.Ambassador))
            Write(Block.Ambassador);
        else if (Cards.Contains(Card.Captain))
            Write(Block.Captain);
        else if (ShouldChallenge(ChallengeableAction.Steal))
            Write(Output.Challenge);
        else
            Write(Output.Pass);
        // TODO if opp is continually stealing we need to figure out who wins the race if we keep taking Tax.
    }

    private void RespondToChallenge(IChallengeable challengedAction)
    {
        if (Cards.Contains(challengedAction.RequiredCard))
            Write(challengedAction.RequiredCard);
        else
            GiveUpDecide();

        if (challengedAction == ChallengeableAction.Tax)
            OustedAsDuke = true;
    }

    private void GiveUpDecide()
    {
        Write(Cards.OrderBy(card => _GiveUpPreferences.IndexOf(card)).Last().GiveUp);

        if (_MyTurn)
            Write(Output.EndTurn);
    }

    private bool ShouldChallenge(IChallengeable prev)
    {
        // Never challenge if we're far enough ahead, always challenge if far enough behind
        if (MyScore > (OppScore + 7))
        {
            return false;
        }
        else if (MyScore < (OppScore - 10))
        {
            return true;
        }
        else
        {
            if (prev == ChallengeableAction.Assassinate)
                return ShouldRandomChallenge(BaseProbabilityToChallenge * 0.5d);
            else if (prev is Block)
                return ShouldRandomChallenge(BaseProbabilityToChallenge * 2d);
            else if (prev == ChallengeableAction.Tax && OppCoin >= 4 && MyCardCount <= 1 && (MyCoin < 7 || OppCardCount > 1))
                return true;
            else
                return ShouldRandomChallenge(BaseProbabilityToChallenge);
        }
    }

    private bool ShouldRandomChallenge(double prob)
    {
        return _Rand.NextDouble() < prob;
    }

    private void WriteRandomValid()
    {
        int index = _Rand.Next(0, ValidOutputs.Count());
        var randomOutput = ValidOutputs.ElementAt(index);
        Write(randomOutput);
    }

    private void Write(Output output)
    {
        Debug.Assert(!_Written || (_MyTurn && output == Output.EndTurn), "If we've already written a value we shouldn't be trying to write another.");
        Debug.Assert(ValidOutputs.Contains(output), "Should only be writing valid outputs to file.");

        File.AppendAllText(FileName, output.Symbol.ToString());
        _Written = true;
    }
}

[DebuggerDisplay("{Symbol}")]
internal class Output
{
    public static readonly Output Pass = new Output() { Symbol = 'p' };
    public static readonly Output Challenge = new Output() { Symbol = 'q' };
    public static readonly Output EndTurn = new Output() { Symbol = '\n' };

    private static readonly Output[] _BaseOutputs = new Output[3] { Pass, Challenge, EndTurn };

    protected Output() { }

    public static IEnumerable<Output> AllOutputs => ChallengeableAction.Actions.Concat(Block.Blocks.Concat(Card.Cards.Concat(GiveUp.GiveUps.Concat(_BaseOutputs))));

    public static IList<Output> ParseSymbols(IEnumerable<char> symbols)
    {
        var parsedOutputs = new List<Output>();
        foreach (var symbol in symbols)
        {
            if (symbol == '\r') continue; // newlines can show up as \r\n so need to skip the \r.
            var matchingOutput = AllOutputs.FirstOrDefault(output => output.Symbol == symbol);
            if (matchingOutput == null)
            {
                throw new InvalidOperationException($"Could not parse Output symbol: \"{symbol}\"");
            }
            parsedOutputs.Add(matchingOutput);
        }
        return parsedOutputs;
    }

    public char Symbol { get; protected set; }
}

internal sealed class Card : Output
{
    public static readonly Card Ambassador = new Card() { Symbol = '~', GiveUp = GiveUp.Ambassador, AvailableAction = ChallengeableAction.Exchange, AvalableBlock = Block.Ambassador };
    public static readonly Card Assassin = new Card() { Symbol = '^', GiveUp = GiveUp.Assassin, AvailableAction = ChallengeableAction.Assassinate };
    public static readonly Card Captain = new Card() { Symbol = '*', GiveUp = GiveUp.Captain, AvailableAction = ChallengeableAction.Steal, AvalableBlock = Block.Captain };
    public static readonly Card Contessa = new Card() { Symbol = '!', GiveUp = GiveUp.Contessa, AvalableBlock = Block.Contessa };
    public static readonly Card Duke = new Card() { Symbol = '$', GiveUp = GiveUp.Duke, AvailableAction = ChallengeableAction.Tax, AvalableBlock = Block.Duke };

    private static readonly Card[] _Cards = new Card[5] { Ambassador, Assassin, Captain, Contessa, Duke };

    private Card() { }

    public static IEnumerable<Card> Cards => _Cards;

    public GiveUp GiveUp { get; private set; }
    public ChallengeableAction AvailableAction { get; private set; }//=> ChallengeableAction.ChallengeableActions.SingleOrDefault(action => action.RequiredCard == this);
    public Block AvalableBlock { get; private set; }// => Block.Blocks.SingleOrDefault(block => block.RequiredCard == this);

    new public static IEnumerable<Card> ParseSymbols(IEnumerable<char> cardSymbols)
    {
        var parsedCards = new List<Card>();
        foreach (var symbol in cardSymbols)
        {
            var matchingCard = Cards.FirstOrDefault(card => card.Symbol == symbol);
            if (matchingCard == null) throw new InvalidOperationException($"Could not parse card symbol: {symbol}");
            parsedCards.Add(matchingCard);
        }
        return parsedCards;
    }
}

internal class Action : Output
{
    public static readonly Action Income = new Action() { Symbol = 'I' };
    public static readonly Action ForeignAid = new Action() { Symbol = 'F', BlockedBy = new Block[1] { Block.Duke } };
    public static readonly Action Coup = new Action() { Symbol = 'C' };

    protected Action() : base() { }

    public IEnumerable<Block> BlockedBy { get; protected set; } = new Block[0];
}

internal sealed class ChallengeableAction : Action, IChallengeable
{
    public static readonly ChallengeableAction Tax = new ChallengeableAction() { Symbol = 'T' };
    public static readonly ChallengeableAction Assassinate = new ChallengeableAction() { Symbol = 'A', BlockedBy = new Block[1] { Block.Contessa } };
    public static readonly ChallengeableAction Exchange = new ChallengeableAction() { Symbol = 'E' };
    public static readonly ChallengeableAction Steal = new ChallengeableAction { Symbol = 'S', BlockedBy = new Block[2] { Block.Ambassador, Block.Captain } };

    private static readonly Action[] _Actions = new Action[7] { Income, ForeignAid, Coup, Tax, Assassinate, Exchange, Steal };
    private static readonly ChallengeableAction[] _ChallengeableActions = new ChallengeableAction[4] { Tax, Assassinate, Exchange, Steal };

    private ChallengeableAction() : base() { }

    public static IEnumerable<Action> Actions => _Actions;
    public static IEnumerable<ChallengeableAction> ChallengeableActions => _ChallengeableActions;

    public Card RequiredCard => Card.Cards.Single(card => card.AvailableAction == this);
}

internal sealed class Block : Output, IChallengeable
{
    public static readonly Block Duke = new Block() { Symbol = 'd' };
    public static readonly Block Ambassador = new Block() { Symbol = 'a' };
    public static readonly Block Captain = new Block() { Symbol = 'c' };
    public static readonly Block Contessa = new Block() { Symbol = 's' };

    private static readonly Block[] _Blocks = new Block[4] { Ambassador, Captain, Contessa, Duke };

    private Block() : base() { }

    public static IEnumerable<Block> Blocks => _Blocks;

    public Card RequiredCard => Card.Cards.Single(card => card.AvalableBlock == this);
    public Action ActionBlocked => ChallengeableAction.Actions.Single(action => action.BlockedBy.Contains(this));
}

internal sealed class GiveUp : Output
{
    public static readonly GiveUp Ambassador = new GiveUp() { Symbol = '_' };
    public static readonly GiveUp Assassin = new GiveUp() { Symbol = '\'' };
    public static readonly GiveUp Captain = new GiveUp() { Symbol = '<' };
    public static readonly GiveUp Contessa = new GiveUp() { Symbol = '=' };
    public static readonly GiveUp Duke = new GiveUp() { Symbol = '0' };

    private static readonly GiveUp[] _GiveUps = new GiveUp[5] { Ambassador, Assassin, Captain, Contessa, Duke };

    private GiveUp() : base() { }

    public static IEnumerable<GiveUp> GiveUps => _GiveUps;

    public Card Card => Card.Cards.Single(card => card.GiveUp == this);
}

internal interface IChallengeable { Card RequiredCard { get; } }

Non posso commentare il post originale, ma volevo segnalare un bug nell'arbitro, in determine_turn_effects(), l'azione Steal sta prendendo tutte le monete dell'avversario. Dovrebbe prendere al massimo due monete.
Dysnomian,

Quando questo programma tenta uno scambio, si perde emettendo una stringa vuota. Esempi di giochi vs. Casuali.
Purple P,

L'ho compilato con Visual Studio su Windows. Quando sarò a casa, mi assicurerò che funzioni anche con Mono. Exchange utilizza Console.WriteLine () per scrivere su STD. Questo ha funzionato quando l'ho provato, lo esaminerò ulteriormente e lo aggiornerò.
Dysnomian,

1
Penso che il problema sia che stai controllando "lastArg", ma le carte di Exchange ti vengono fornite all'indice 3 come le altre tue carte.
Purple P,

1
Aggiunto alle classifiche.
Purple P,

1

Avvocato Rando Aggro

Simile all'avvocato, fa solo cose legali. Tuttavia Assassina, colpi di stato precedenti e sceglie alcune azioni in modo casuale (come quando sfidare).

#! /usr/bin/env python3
import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]


def give_card():
    if "~" in mycards: # give up Ambassador
        return "_"
    if "!" in mycards: # give up Contessa
        return "="
    if "^" in mycards: # give up Assassin
        return "'"
    if "*" in mycards: # give up Captain
        return "<"
    return "0" # give up Duke


with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        line = a # get the last line of the file
    print("{}, {}, {}, {}".format(line, othercoins, mycoins, mycards))
    if line.endswith("\n"): # it has an endline, eg this is a new action
        if int(mycoins) >= 7:
            history.write("C") # coup if I have to
        elif int(mycoins) >= 3 and "^" in mycards:
            history.write("A") # assassinate if I can
        elif "*" in mycards and int(othercoins) > 0:
            history.write("S") # steal if i can
        elif "$" in mycards:
            history.write("T") # tax if i can
        elif random.randint(0,1):
            history.write("F") # foreign aid 50% of the time
        else:
            history.write("I\n") # income
    elif line == "F": # they tried to foreign aid
        if "$" in mycards:
             history.write("d") # block if i can
        else:
             history.write("p")
    elif line == "C": # they coup, sad
        history.write(give_card())
    elif line == "E": # they Exchange
        if random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write("p") 
    elif line == "T": # they tax
        if random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write("p") 
    elif line == "A": # they assassinate
        if "!" in mycards:
            history.write("s") # block with contessa if i can
        elif random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write(give_card()) # otherwise give up a card
    elif line == "S": # they steal
        if "~" in mycards:
            history.write("a") # block with ambassador if i can
        elif "*" in mycards:
            history.write("c") # block with captain if i can
        elif random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else:
            history.write("p")
    elif line.endswith("d") and random.randint(0,1): # they block my foreign aid
        history.write("q") # challenge 50% of the time
    elif line.endswith("a") and random.randint(0,1): # they block as ambassador
        history.write("q") # challenge 50% of the time
    elif line.endswith("c") and random.randint(0,1): # they block as captain
        history.write("q") # challenge 50% of the time
    elif line.endswith("s") and random.randint(0,1): # they block as contessa
        history.write("q") # challenge 50% of the time
    elif line.endswith("sq"): # they challenged my contessa block
        history.write("!") # reveal that i have contessa (no condition because i never lie block)
    elif line.endswith("aq"): # they challenge my Ambassador block
        history.write("~") # reveal that i have a captain (no condition because i never lie block)
    elif line.endswith("cq"): # they challenged my Captain block
        history.write("*") # reveal that I have a Captain (no condition because i never lie block)
    elif line.endswith("dq"): # they challenge my Duke block
        history.write("$") # reveal that I have a Duke (no condition because i never lie block)
    elif line.endswith("Tq"): # they challenge my Tax 
        history.write("$") # reveal that I have a Duke (no condition because i fake tax)
    elif line.endswith("Aq"): # they challenge my assassinate
        history.write("^") # reveal that I had an Assasin
    elif line.endswith("Sq"): # they challenge my steal
        history.write("*") # reveal that I have a Captain
    elif line[-1] in "~^*!$": # they respond to my challenge successfully
        history.write(give_card()) # give up card
        if line[-3] in "acds":
            history.write("\n")
    else:
        history.write("\n")
    history.seek(0)
    print("out")
    print(history.read())

Ho organizzato la funzione give_card per rinunciare alle carte che Lawyer non usa per prima. Se usi effettivamente Assassin, potresti voler riorganizzare quella funzione per mantenerla più a lungo.
Hiatsu,

Grazie per averlo notato, ho scelto quell'ordine aspettandomi di utilizzarlo con l'ambasciatore, ma a corto di tempo. Ho cambiato l'ordine di rinunciare per avere più senso e anche renderlo più aggressivo rubando prima di tassare.
gggg,

1

Maschera

La maschera è un maestro del travestimento. Impedisce agli avversari di tenere traccia delle sue carte Scambiando ogni volta che agisce o blocca. La sua strategia vincente è quella di prendere 3 monete come Duca, quindi Assassinare.

Compilare con go build mask.go, eseguire con ./mask.

package main

import (
    "bytes"
    "io/ioutil"
    "os"
    "strconv"
    "strings"
)

var revealToPunishment = map[byte]byte{'~': '_', '^': '\'', '*': '<', '!': '=', '$': '0'}
var assertedCardMap = map[byte]byte{'A': '^', 'E': '~', 'S': '*', 'T': '$', 'a': '~', 'c': '*', 's': '!', 'd': '$'}

func actWithOneCard(file *os.File, coinCount int, ourCards string) {
    if coinCount >= 7 {
        file.WriteString("C")
    } else if ourCards == "$" {
        file.WriteString("T")
    } else {
        file.WriteString("I\n")
    }
}

func mostRecentClaim(lines [][]byte) byte {
    // If we blocked and were not challenged on the opponent's last turn, return
    // what we claimed to have in the block.
    opponentsLastTurn := lines[len(lines)-1]
    switch b := opponentsLastTurn[len(opponentsLastTurn)-1]; b {
    case 'a', 'c', 's', 'd':
        return b
    }
    // Otherwise, return the first character of our last turn.
    ourLastTurn := lines[len(lines)-2]
    return ourLastTurn[0]
}

func whatWePlanToDoNext(lines [][]byte, coinCount int) string {
    if len(lines) < 2 || mostRecentClaim(lines) == 'E' {
        if coinCount >= 3 {
            return "A"
        } else {
            return "T"
        }
    } else {
        return "E"
    }
}

func ourTurn(file *os.File, coinCount int, ourCards string, lines [][]byte) {
    if len(ourCards) == 1 {
        actWithOneCard(file, coinCount, ourCards)
        return
    }
    file.WriteString(whatWePlanToDoNext(lines, coinCount))
}

func handleChallenge(file *os.File, ourCards string, lines [][]byte) {
    lastLine := lines[len(lines)-1]
    attemptedAction := lastLine[len(lastLine)-2]
    assertedCard := assertedCardMap[attemptedAction]
    for i := range ourCards {
        if ourCards[i] == assertedCard && ourCards[i] != '\x00' {
            file.Write([]byte{assertedCard})
            return
        }
    }
    cardToGiveUp := giveUpCard(ourCards)
    file.Write([]byte{revealToPunishment[cardToGiveUp]})
    switch attemptedAction {
    case 'a', 'c', 'd', 's':
    default:
        file.WriteString("\n")
    }
}

func giveUpCard(ourCards string) byte {
    // If we have a Duke, give up the other card.
    if dukeIndex := strings.Index(ourCards, "$"); -1 < dukeIndex && len(ourCards) == 2 {
        return ourCards[(dukeIndex+1)%2]
    }
    return ourCards[0]
}

func main() {
    filename := os.Args[1]
    coinCount, _ := strconv.Atoi(os.Args[3])
    ourCards := os.Args[4]
    file, _ := os.OpenFile(filename, os.O_RDWR, 0755)
    defer file.Close()

    rawBytes, _ := ioutil.ReadAll(file)
    lines := bytes.Split(rawBytes, []byte{'\n'})
    if len(lines[len(lines)-1]) == 0 {
        lines = lines[:len(lines)-1]
    }
    if len(rawBytes) == 0 {
        file.WriteString("T")
        return
    }
    // Exchange. Prioritize Ambassador, Duke, Assassin.
    if len(ourCards) > 2 {
        var has_ambassador, has_duke, has_assassin bool
        var keptCards string
        for len(ourCards) > 2 {
            var i int
            if i = strings.Index(ourCards, "~"); !has_ambassador && i > -1 {
                keptCards += "~"
                has_ambassador = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else if i = strings.Index(ourCards, "$"); !has_duke && i > -1 {
                keptCards += "$"
                has_duke = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else if i = strings.Index(ourCards, "^"); !has_assassin && i > -1 {
                keptCards += "^"
                has_assassin = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else {
                keptCards += ourCards[:1]
                ourCards = ourCards[1:]
            }
        }
        ourCards = keptCards
        os.Stdout.WriteString(ourCards)
    }
    switch rawBytes[len(rawBytes)-1] {
    case '\n':
        ourTurn(file, coinCount, ourCards, lines)
    // Opponent Couped us. Give up a card.
    case 'C':
        file.Write([]byte{revealToPunishment[giveUpCard(ourCards)]})
    // Opponent blocked, or we Assassinated/Couped them. End our turn.
    case 'a', 'c', 'd', 's', 'p', '_', '\'', '<', '=', '0':
        file.WriteString("\n")
    case 'q':
        handleChallenge(file, ourCards, lines)
    // Opponent did something blockable, block it.
    case 'F':
        file.WriteString("d")
    case 'A':
        file.WriteString("s")
    case 'S':
        if strings.Contains(ourCards, "*") {
            file.WriteString("c")
        } else {
            file.WriteString("a")
        }
    // Opponent took some other action. Let it pass.
    default:
        file.WriteString("p")
    }
}

Consiglio di non assegnare il genere ai programmi per computer. Vi è già sufficiente propensione al genere nelle comunità di programmazione e i pronomi maschili inadempienti dimostrano ulteriormente che le donne non sono gradite.
Greg Martin,

3
@GregMartin Se una donna dicesse che la mia stravagante rassegnazione delle mie osservazioni, immaginandole come cortigiani intriganti come nel gioco di carte, la faceva sentire offesa o sgradita, allora la cambierei in un batter d'occhio. Ma tu non sei una donna, Greg. E non mi piace che tu abbia inviato ai negativi la risposta in cui mi sono impegnata di più, e quella che si sta comportando meglio nella mia sfida - non perché è irrilevante o una cattiva risposta alla domanda, ma a causa di un piccolo passo falso sociale .
Purple P,

1

Giocatore

Il giocatore d'azzardo ha una strategia concreta, ma si fida del suo istinto quando una situazione non è spiegata nella sua strategia vincente. Cerca di rubare molto e colpi di stato / assassini quando possibile.

Scritto in Python3:

import sys
import random
import time

random.seed(time.time())  # lets keep it rather random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legal_actions = sys.argv[5:]

othercoins = int(othercoins)
mycoins = int(mycoins)

income = 'I\n'

foreign_aid, coup, exchange, tax, assassinate, steal, block_aid, \
block_steal_amb, block_steal_cap, block_assassinate, \
pass_challange, do_challenge = "FCETASdacspq"


loosing_actions = "_'<=0"
loose_ambassador, loose_assassin, loose_captain, loose_contessa, loose_duke = loosing_actions
have_ambassador, have_assassin, have_captain, \
have_contessa, have_duke = "~^*!$"

actions_dict = {
    exchange: loose_ambassador, tax: loose_duke, assassinate: loose_assassin, steal: loose_captain,
    block_aid: loose_duke, block_steal_amb: loose_ambassador, block_steal_cap: loose_captain, block_assassinate: loose_contessa
}


def guess_opponents_hand():
    # get number of each card still in play and not in hand
    card_counts = [3] * 5
    card_give_up = list("_'<=0")
    with open(filename, 'r') as history:
        while True:
            line = history.readline()
            if not line:
                break
            for card in card_give_up:
                if card in line:
                    card_counts[card_give_up.index(card)] -= 1

    have_cards = list("~^*!$")

    if sum(card_counts) == 15:
        num_cards = 2
    elif sum(card_counts) == 14:
        if len(mycards) == 1:
            num_cards = 2
        else:
            num_cards = 1
    else:
        num_cards = 1

    for card in mycards:
        card_counts[have_cards.index(card)] -= 1

    # randomly sample a hand for the opponent
    card_1 = sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)
    if num_cards == 1:
        return card_1
    card_counts[card_give_up.index(card_1)] -= 1
    return card_1 + sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)


def sample_from_probabilities(success_probabilities, actions):
    # weighted random
    return random.choices(actions, success_probabilities)[0]

def get_prev_char(line, x=1):
    try:
        return line[-1*x]
    except:
        return ""


def get_prev_line(lines):
    try:
        return lines[-2]
    except:
        return []


def give_card(not_swap=True):
    if have_ambassador in mycards:  # give up Ambassador
        return loose_ambassador if not_swap else have_ambassador
    if have_contessa in mycards:  # give up Contessa
        return loose_contessa if not_swap else have_contessa
    if have_assassin in mycards:  # give up Assassin
        return loose_assassin if not_swap else have_assassin
    if have_duke in mycards:  # give up duke
        return loose_duke if not_swap else have_duke
    return loose_captain if not_swap else have_captain  # give up captain


action = legal_actions[0]  # failsafe
with open(filename, 'r') as file:
    all_lines = file.readlines()
    try:
        curr_line = all_lines[-1]
    except IndexError:
        curr_line = ""

obvious_actions = ['C', '~', '^', '*', '!', '$']  # borrowed from Brilliand
obvious = list(set(obvious_actions).intersection((set(legal_actions))))


otherhand = guess_opponents_hand()


# take care of easy choices
if obvious:
    action = coup if coup in obvious else obvious[0]
elif len(set(list(loosing_actions)).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card()
elif len(set([i+'\n' for i in list(loosing_actions)]).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card() + '\n'
elif len(legal_actions) == 1:
    action = legal_actions[0]
elif assassinate in legal_actions and have_assassin in mycards:  # if we can legally assassinate, we try to
    action = assassinate
elif steal in legal_actions and othercoins > 1 and have_captain in mycards:  # we steal when we can or have to prevent a killing coup
    action = steal
elif steal in legal_actions and 7 <= othercoins <= 8 and len(mycards) == 1 and have_assassin not in mycards:
    action = steal
elif block_assassinate in legal_actions and have_contessa in mycards:
    action = block_assassinate
elif block_aid in legal_actions and have_duke in mycards:
    action = block_aid
elif block_steal_cap in legal_actions and have_captain in mycards:
    action = block_steal_cap
elif block_steal_amb in legal_actions and have_ambassador in mycards:
    action = block_steal_amb
elif tax in legal_actions and have_duke in mycards:
    action = tax
elif foreign_aid in legal_actions and foreign_aid in get_prev_line(all_lines):  # opponent wouldn't foreign aid with a duke
    action = foreign_aid
elif block_aid in legal_actions:
    if loose_duke not in otherhand and len(mycards) > 1:
        action = block_aid
    else:
        action = pass_challange if pass_challange in legal_actions else "\n"


elif do_challenge in legal_actions:
    no_challenge = pass_challange if pass_challange in legal_actions else "\n"
    action = do_challenge if len(mycards) > 1 else no_challenge  # failsafe
    if get_prev_char(curr_line) == block_aid and (not loose_duke in otherhand or len(mycards) > 1):  # we don't think opponent has a duke
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif block_assassinate in legal_actions:
        if len(mycards) == 1:
            if loose_assassin in otherhand and loose_contessa not in otherhand:
                action = block_assassinate
            elif loose_assassin not in otherhand:
                action = do_challenge
            else:
                action = random.choice([block_assassinate, do_challenge])
        else:
            action = give_card()
    elif block_steal_amb in legal_actions:
        if len(mycards) > 1 and 7 <= mycoins <= 8:
            if loose_captain in otherhand:
                probs = [0.4, 0.4, 0.2]
            else:
                probs = [0.2, 0.2, 0.6]

            action = sample_from_probabilities(probs, [block_steal_amb, block_steal_cap, do_challenge])
        elif len(mycards) == 1 and len(otherhand) == 1 and 7 <= mycoins <= 8:
            action = do_challenge  # worth the risk if we defend a winning move
        else:
            action = do_challenge if len(mycards) > 1 else pass_challange  # failsafe
            # go with default

    elif get_prev_char(curr_line) == tax and loose_duke not in otherhand and len(mycards) > 1:
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif get_prev_char(curr_line) in {block_steal_cap, block_steal_amb, block_aid, block_assassinate}:
        if get_prev_char(curr_line) == block_aid:
            action = do_challenge
        elif get_prev_char(curr_line) == block_assassinate:
            if len(otherhand) == 1 and loose_contessa not in otherhand:
                action = do_challenge
        elif get_prev_char(curr_line) == block_steal_amb:
            action = pass_challange if pass_challange in legal_actions else "\n"

# other choices shall be weighted random choices
elif len(set(legal_actions).intersection({assassinate, steal, tax, income, exchange})) >= 3:
    # decide between aggro ass, aggro steal, aggro Tax, Income, Exchange
    assumed_values = [(assassinate in legal_actions) * (loose_assassin not in otherhand) * 0.1 * len(mycards) * (len(otherhand) - 1) * (mycoins >= 3),
                      (othercoins > 1) * ((othercoins > 5 * 0.3) + othercoins * 0.05) * (len(mycards) - 1) * (loose_ambassador not in otherhand),
                      0.1 * (loose_duke not in otherhand) * (len(mycards) - 1)**(len(otherhand) - 1),
                      0.3,
                      (have_ambassador in mycards) * 0.5/len(mycards)
                      ]
    normalized_probs = [float(i) / sum(assumed_values) for i in assumed_values]
    actions = [assassinate, steal, tax, income, exchange]
    action = sample_from_probabilities(normalized_probs, actions)
elif get_prev_char(curr_line) == do_challenge or get_prev_char(curr_line) == coup:
    # we lost a challenge or coup
    card = give_card()
    action = card if card in legal_actions else action
else:
    # We missed a case. This shouldn't happen. Please tell me so I can fix it!
    # Note: A failsafe always taking a legal action is in place, so please comment out the error raising after telling me :)
    raise RuntimeError("Please tell me this happened, give me the history file, comment out this line, "
                       "and replay. THANKS!")
    pass

with open(filename, "a") as history:
    history.write(str(action))

if len(mycards) > 2:
    mycards = mycards.replace(give_card(False), "", 1)
    mycards = mycards.replace(give_card(False), "", 1)
    print(mycards)

esperto di statistica

Conosce la sua strategia vincente, proprio come il giocatore d'azzardo, ma si fida sempre delle probabilità massime invece di campionarle a caso.

import sys
import random
import time

random.seed(time.time())  # lets keep it rather random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legal_actions = sys.argv[5:]

othercoins = int(othercoins)
mycoins = int(mycoins)

income = 'I\n'

foreign_aid, coup, exchange, tax, assassinate, steal, block_aid, \
block_steal_amb, block_steal_cap, block_assassinate, \
pass_challange, do_challenge = "FCETASdacspq"


loosing_actions = "_'<=0"
loose_ambassador, loose_assassin, loose_captain, loose_contessa, loose_duke = loosing_actions
have_ambassador, have_assassin, have_captain, \
have_contessa, have_duke = "~^*!$"

actions_dict = {
    exchange: loose_ambassador, tax: loose_duke, assassinate: loose_assassin, steal: loose_captain,
    block_aid: loose_duke, block_steal_amb: loose_ambassador, block_steal_cap: loose_captain, block_assassinate: loose_contessa
}


def guess_opponents_hand():
    # get number of each card still in play and not in hand
    card_counts = [3] * 5
    card_give_up = list("_'<=0")
    with open(filename, 'r') as history:
        while True:
            line = history.readline()
            if not line:
                break
            for card in card_give_up:
                if card in line:
                    card_counts[card_give_up.index(card)] -= 1

    have_cards = list("~^*!$")

    if sum(card_counts) == 15:
        num_cards = 2
    elif sum(card_counts) == 14:
        if len(mycards) == 1:
            num_cards = 2
        else:
            num_cards = 1
    else:
        num_cards = 1

    for card in mycards:
        card_counts[have_cards.index(card)] -= 1

    # randomly sample a hand for the opponent
    card_1 = sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)
    if num_cards == 1:
        return card_1
    card_counts[card_give_up.index(card_1)] -= 1
    return card_1 + sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)


def sample_from_probabilities(success_probabilities, actions):
    # statistical max, decide randomly on equivalent probabilities
    max_prob = max(success_probabilities)
    indicies = []
    idx = 0
    for i in success_probabilities:
        if i == max_prob:
            indicies.append(idx)
        idx += 1
    choice = random.choice(indicies)
    return actions[choice]


def get_prev_char(line, x=1):
    try:
        return line[-1*x]
    except:
        return ""


def get_prev_line(lines):
    try:
        return lines[-2]
    except:
        return []


def give_card(not_swap=True):
    if have_ambassador in mycards:  # give up Ambassador
        return loose_ambassador if not_swap else have_ambassador
    if have_contessa in mycards:  # give up Contessa
        return loose_contessa if not_swap else have_contessa
    if have_assassin in mycards:  # give up Assassin
        return loose_assassin if not_swap else have_assassin
    if have_duke in mycards:  # give up duke
        return loose_duke if not_swap else have_duke
    return loose_captain if not_swap else have_captain  # give up captain


action = legal_actions[0]  # failsafe
with open(filename, 'r') as file:
    all_lines = file.readlines()
    try:
        curr_line = all_lines[-1]
    except IndexError:
        curr_line = ""

obvious_actions = ['C', '~', '^', '*', '!', '$']  # borrowed from Brilliand
obvious = list(set(obvious_actions).intersection((set(legal_actions))))


otherhand = guess_opponents_hand()


# take care of easy choices
if obvious:
    action = coup if coup in obvious else obvious[0]
elif len(set(list(loosing_actions)).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card()
elif len(set([i+'\n' for i in list(loosing_actions)]).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card() + '\n'
elif len(legal_actions) == 1:
    action = legal_actions[0]
elif assassinate in legal_actions and have_assassin in mycards:  # if we can legally assassinate, we try to
    action = assassinate
elif steal in legal_actions and othercoins > 1 and have_captain in mycards:  # we steal when we can or have to prevent a killing coup
    action = steal
elif steal in legal_actions and 7 <= othercoins <= 8 and len(mycards) == 1 and have_assassin not in mycards:
    action = steal
elif block_assassinate in legal_actions and have_contessa in mycards:
    action = block_assassinate
elif block_aid in legal_actions and have_duke in mycards:
    action = block_aid
elif block_steal_cap in legal_actions and have_captain in mycards:
    action = block_steal_cap
elif block_steal_amb in legal_actions and have_ambassador in mycards:
    action = block_steal_amb
elif tax in legal_actions and have_duke in mycards:
    action = tax
elif foreign_aid in legal_actions and foreign_aid in get_prev_line(all_lines):  # opponent wouldn't foreign aid with a duke
    action = foreign_aid
elif block_aid in legal_actions:
    if loose_duke not in otherhand and len(mycards) > 1:
        action = block_aid
    else:
        action = pass_challange if pass_challange in legal_actions else "\n"


elif do_challenge in legal_actions:
    no_challenge = pass_challange if pass_challange in legal_actions else "\n"
    action = do_challenge if len(mycards) > 1 else no_challenge  # failsafe
    if get_prev_char(curr_line) == block_aid and (not loose_duke in otherhand or len(mycards) > 1):  # we don't think opponent has a duke
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif block_assassinate in legal_actions:
        if len(mycards) == 1:
            if loose_assassin in otherhand and loose_contessa not in otherhand:
                action = block_assassinate
            elif loose_assassin not in otherhand:
                action = do_challenge
            else:
                action = random.choice([block_assassinate, do_challenge])
        else:
            action = give_card()
    elif block_steal_amb in legal_actions:
        if len(mycards) > 1 and 7 <= mycoins <= 8:
            if loose_captain in otherhand:
                probs = [0.4, 0.4, 0.2]
            else:
                probs = [0.2, 0.2, 0.6]

            action = sample_from_probabilities(probs, [block_steal_amb, block_steal_cap, do_challenge])
        elif len(mycards) == 1 and len(otherhand) == 1 and 7 <= mycoins <= 8:
            action = do_challenge  # worth the risk if we defend a winning move
        else:
            action = do_challenge if len(mycards) > 1 else pass_challange  # failsafe
            # go with default

    elif get_prev_char(curr_line) == tax and loose_duke not in otherhand and len(mycards) > 1:
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif get_prev_char(curr_line) in {block_steal_cap, block_steal_amb, block_aid, block_assassinate}:
        if get_prev_char(curr_line) == block_aid:
            action = do_challenge
        elif get_prev_char(curr_line) == block_assassinate:
            if len(otherhand) == 1 and loose_contessa not in otherhand:
                action = do_challenge
        elif get_prev_char(curr_line) == block_steal_amb:
            action = pass_challange if pass_challange in legal_actions else "\n"

# other choices shall be weighted random choices
elif len(set(legal_actions).intersection({assassinate, steal, tax, income, exchange})) >= 3:
    # decide between aggro ass, aggro steal, aggro Tax, Income, Exchange
    assumed_values = [(assassinate in legal_actions) * (loose_assassin not in otherhand) * 0.1 * len(mycards) * (len(otherhand) - 1) * (mycoins >= 3),
                      (othercoins > 1) * ((othercoins > 5 * 0.3) + othercoins * 0.05) * (len(mycards) - 1) * (loose_ambassador not in otherhand),
                      0.1 * (loose_duke not in otherhand) * (len(mycards) - 1)**(len(otherhand) - 1),
                      0.3,
                      (have_ambassador in mycards) * 0.5/len(mycards)
                      ]
    normalized_probs = [float(i) / sum(assumed_values) for i in assumed_values]
    actions = [assassinate, steal, tax, income, exchange]
    action = sample_from_probabilities(normalized_probs, actions)
elif get_prev_char(curr_line) == do_challenge or get_prev_char(curr_line) == coup:
    # we lost a challenge or coup
    card = give_card()
    action = card if card in legal_actions else action
else:
    # We missed a case. This shouldn't happen. Please tell me so I can fix it!
    # Note: A failsafe always taking a legal action is in place, so please comment out the error raising after telling me :)
    raise RuntimeError("Please tell me this happened, give me the history file, comment out this line, "
                       "and replay. THANKS!")
    pass

with open(filename, "a") as history:
    history.write(str(action))

if len(mycards) > 2:
    mycards = mycards.replace(give_card(False), "", 1)
    mycards = mycards.replace(give_card(False), "", 1)
    print(mycards)


1
Questo programma si arresta in modo anomalo su un file vuoto al primo avvio. Quando va secondo, si blocca con un messaggio del tipo: Traceback (most recent call last): File "gambler.py", line 94, in <module> otherhand = guess_opponents_hand() File "gambler.py", line 61, in guess_opponents_hand card_counts[card_give_up.index(card_1)] -= 1 ValueError: ['_'] is not in list.
Purple P,

è stato in grado di correggere quell'errore. scusa, l'ho pubblicato in una specie di fretta. Mi assicurerò di provarlo con il tuo arbitro fino a domani, ma l'unico ovvio bug è stato corretto. ancora una volta mi dispiace.
Jaaq

1
Buone notizie, gli scambi di giocatori d'azzardo funzionano sulla mia macchina! Si blocca ancora se il suo avversario tenta un aiuto estero e non ha un duca, ma è stato aggiunto alle classifiche.
Purple P,

1
@jaaq Sta ancora perdendo se il suo avversario tenta un aiuto estero e non ha un duca; deve rispondere a quello con un passaggio, non con una fine del turno.
Brilliand,

1
@jaaq Ho corretto l'errore citato da Brilliand e aggiunto Statistician alla classifica. Quando le tue voci vengono Assassinate con una carta rimasta, perdono scrivendo \ninvece della carta che desiderano rinunciare. In una situazione del genere è meglio reagire con un blocco o una sfida. Se Gambler avesse vinto le 5 partite perse in questo modo, avrebbe preso il primo posto.
Purple P,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.