Постановіть переворот, щоб стати королем пагорба!


14

Таблиця лідерів

  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

Доступний архів останньої відповідності, включаючи журнал та всі вихідні файли.

Калькулятор, Brilliand, переможець! Його відповідь прийнята, але це не означає, що виклик закінчений. Не соромтеся надсилати нові записи чи редагувати свої поточні та намагайтеся збити його з трону. Я присуджую нагороду лідеру наприкінці місяця.

Правила гри

Купон - карткова гра, розрахована на 2-6 гравців, в яку ми будемо грати з двома. Він складається із скарбниці монет (нескінченна для наших цілей) та колоди з 15 карт, що містять 3 кожного з наступних типів: посол, вбивця, капітан, Контеса, герцог. На початку гри кожному гравцеві дають одну монету і роздають дві картки навмання, які вони зберігають у секреті до необхідності. Об'єкт - бути останнім гравцем з картами в руці.

Своєю чергою, гравець може вчинити одну з наступних дій незалежно від своїх карт:

  • Дохід: візьміть 1 скарбничку з скарбниці. Неблокований і незаперечний.
  • Іноземна допомога: візьміть із скарбниці 2 монети. Може бути заблокований гравцем з герцогом. Беззаперечний.
  • Переворот: вийміть з гри гру одного гравця, який ви обрали. Коштує 7 монет. Потерпілий може вибрати, яку карту викинути. Якщо у гравця є 10 і більше монет на початку своєї черги, він повинен провести купон. Неблокований і незаперечний.

Залежно від своїх карт, гравці також можуть виконувати одну з наступних дій як свою чергу:

  • Обмін: гравець з послом може взяти дві карти з колоди. Тоді вони можуть вибирати зі своєї руки та намальованих карт стільки карток, скільки раніше мали. (Тобто, якщо вони мали лише одну карту, вони можуть обміняти її на одну з намальованих карт або зберегти її, а якщо у них дві карти, вони можуть вибрати будь-яку дві з чотирьох карт.) Дві небажані картки повертаються на колоду . Розблокування, але складне.
  • Вбивця: гравець з Assassin може витратити 3 монети, щоб вийняти з гри карту противника. Потерпілий може вибрати, яку карту викинути. Може бути заблокований гравцем із Contessa, і в цьому випадку монети не повертаються. Подлагется, в цьому випадку монети будуть повернуті.
  • Викрасти: Гравець з капітаном може взяти у суперника дві монети. Якщо опонент має одну монету, він візьме цю одну монету. Якщо опонент має нульові монети, він може не красти. Може бути заблокований гравцем з послом або капітаном. Виклик.
  • Податок: Гравець з герцогом може взяти з казни 3 монети. Розблокування, але складне.

Хитра частина перевороту полягає в тому, що гравцям дозволяється брехати про те, які у них карти! Не потрібно мати карту для спроби виконати дію або блок, пов'язаний з нею.

Коли гравець виконує дії картки, будь-який противник (навіть той, кому ця дія не пошкоджений) може кинути виклик актору і сказати, що він не вірить, що має карту для цієї дії. Якщо претендент правильний, дія скасовується, і актор повинен викинути одну карту за власним вибором (повернення будь-яких монет, які вони витратили, якщо це застосовується). Якщо ні, то дія робиться, актор повертає на палубу карту, яку вони оскаржили, і витягує нову, а претендент повинен відкинути одну зі своїх карт. Гравці повинні бути правдивими щодо того, які карти вони тримають, коли їх оскаржують.

Карти, вилучені з гри з Assassinate, Coup та програлими завданнями, не повертаються на колоду, але картки, виявлені як частина виграного виклику, повертаються на колоду.

Блоки можуть бути оскаржені, як і дії. Наприклад, якщо гравець А претендує на Іноземну допомогу, а гравець В каже: "У мене є герцог, і я блокую вашу іноземну допомогу", А може сказати: "Я не вірю, що у вас є герцог". Якщо це твердження правильне, Б втрачає карту за те, що потрапив у брехню, а А бере 2 монети; якщо його немає, А втрачає карту і не отримує монет, і Б повинен повернути свого герцога на колоду і оформити нову карту.

Те, як блоки та завдання працювати з Assassinate, повинні бути чітко розроблені. Припустимо, гравець A каже: "У мене є вбивця, і я вбиваю гравця B". Якщо B не намагається кинути виклик чи блокувати A, то вбивство проходить через: B втрачає карту, а A платить 3 монети.

Як варіант, Б може кинути виклик, сказавши: "Я не вірю, що у вас є вбивця". Якщо це правда, тоді A скидає картку та їх монети повертаються, тоді як B не впливає, і черга А закінчується. Якщо віра В невірна і А тримає вбивцю, то Б втрачає як свої картки, так і невдачу, одну за неправильне виклик та одну від Вбивства.

Замість того, щоб кинути виклик, Б міг би сказати: "Я маю Контесу, і я блокую Заступника". Якщо А вірить В, то поворот А закінчується, а їхні монети не повертаються. Але A може кинути виклик блоку і сказати: "Я не вірю, що ти маєш Contessa". Якщо B насправді тримає Contessa, то A втрачає карту за неправильне виклик. Але якщо Б цього немає, то Б втрачає одну карту за те, що її спіймали у брехні, а другу - від Вбивства.

Аналогічна логіка до вищезгаданого пояснення стосується здатності капітана до викрадення, де може бути оскаржено дії або блок.

Можна втратити обидві картки і бути ліквідованими за один виток, якщо ви невдало киньте виклик вбивці або вас помилково заявляють, що у вас є Contessa для блокування вбивства. Ви втрачаєте одну карту від виклику та одну карту від Вбивства.

Виклик

Ваше завдання - написати програму, яка буде грати Coup. Він буде наведений як аргументи його командного рядка:

  • Назва файлу, що містить перелік його дій та дій його опонентів до цього часу.
  • Ціле число від 0 до 12, що вказує кількість монет противника.
  • Ціле число від 0 до 12, що вказує на його кількість монет.
  • Рядок від одного до чотирьох символів із зазначенням його карт. Зазвичай це просто одна чи дві картки у вашій програмі, але якщо ваша програма щойно перейшла на біржу, вона буде мати n + 2 символи, де n - ваша кількість карт. Потім ваша програма повинна вивести n карт, які вона хоче зберегти в STDOUT. (Програми не повинні читати або отримувати доступ до STDOUT, окрім як для цієї мети - якщо ви хочете отримати вихід налагодження, будь ласка, напишіть на STDERR.)
  • Один або кілька аргументів, які вказують на юридичні кроки, які він може зробити.

(Приклад виклику:, що yourprogram file.txt 1 7 '~!' a c p qозначає "У вашого суперника є 1 монета. У вас є 7 монет, посол і Contessa. Напишіть у file.txt свій вибір а, с, р або q з урахуванням історії гри та поточного стану гри. ")

Ваша програма повинна додати один або (у двох конкретних ситуаціях) два символи до наданого файлу із зазначенням його дії. Він інакше не повинен змінювати наявний вміст файлу. Він може створювати будь-які нові файли, які бажає, але лише в каталозі, в якому він запущений. Будь ласка, надайте всі необхідні команди для складання та запуску програми.

Я подав два приклади конкурентів нижче, написані на Go.

Формат виводу:

  • I\n: Дохід. Юридичні відповіді: будь-які поворотні дії (якщо припустимо, що в них є монети за вбивство / переворот).
  • F: Іноземна допомога. Юридичні відповіді: d(блокуй як герцог), p(нехай проходить).
  • C: Переворот. Юридичні відповіді: в залежності від того з _, ', <, =, 0знаходиться в ваших руках.
  • E: Обмін. Юридичні відповіді: q(виклик, не рахуючи того , як гравець посла), p.
  • T: Податок. Юридичні відповіді: q(виклик, не рахуючи , що гравець має Duke), p.
  • A: Вбивця. Юридичні відповіді: s(блок як графині), q(виклик), і в залежності від того з _, ', <, =, 0в ваших руках.
  • S: Вкрасти. Юридичні відповіді: a(блок в якості посла), c(блок , як капітан), q(виклик, не рахуючи , що гравець має капітан), p.
  • d: блокувати іноземну допомогу як герцог. Юридичні відповіді: \n(прийміть блок), q(киньте виклик, не віривши, що у гравця є герцог).
  • a: заблокувати крадіжку як посол. Юридичні відповіді: \n(прийміть блок), q(киньте виклик, не віривши, що у гравця є посол).
  • c: заблокувати крадіжку як капітан. \n(прийміть блок), q(киньте виклик, не вірячи, що у гравця є Капітан).
  • s: заблокувати вбивцю як Contessa. Юридичні відповіді: \n(прийміть блок), q(киньте виклик, не віривши, що гравець має Contessa).
  • p: пройдіть виклик біржі / податку / крадіжці, коли не ваша черга. Не використовується з A; відмовитися від оскарження вбивства написати один із _'<=0. Юридична відповідь: \n(завершіть свою чергу), і якщо ви тільки що досягли успіху на біржі, написайте картки, які ви хочете зберегти, від аргументу четвертого командного рядка до STDOUT.
  • q: киньте виклик останній дії або блоку. Юридична відповідь: якщо у вас є картка для дії, яка була оскаржена, залежно від того, яка ~^*!$вона була. Якщо ви цього не зробите, то, від кого б _'<=0ви не хотіли відмовитись, слідуйте за новим рядком, якщо і тільки, якщо ваша черга.
  • ~, ^, *, !, $: Показує , що ви говорили правду про проведення, відповідно, посол, вбивця, капітан, Contessa, і Duke (також використовується для представлення цих карт в аргументах командного рядка, і STDOUT виходу в Обміну ). Юридичні відповіді: в залежності від того з _, ', <, =, у 0вас є у вашій руці.
  • _, ', <, =, 0: Відмовитися в якості покарання, відповідно, посол, і вбивцю, а капітан, графиня, і герцог , тому що ви втратили виклик або були вбиті / Couped. Правова характеристика: \n.
  • \n: завершіть свою чергу, тим самим відмовляючись оскаржувати блок, якщо це застосовно. Юридичні відповіді: будь-які дії з великої літери (якщо припустити, що в них є монети за вбивство / переворот, а опонент має монети для крадіжки).

Формат має такі корисні властивості:

  • Повороти починаються з великої літери.
  • Рядки дотримуються шаблону: великі літери, малі літери, необов'язково розділові знаки або 0 для виявлених карток, новий рядок.
  • Файл, що закінчується новим рядком, або порожній файл, вказує, що це початок черги вашої програми, і він повинен вибрати велику літеру.
  • Юридичні дії, дозволених здійснити виклик, зазвичай однозначно визначаються останнім символом у файлі. Виняток - це те q, що з нею буде пов'язана певна логіка. Дивіться функцію get_legal_actionsарбітра, щоб допомогти зрозуміти це. Або ви можете просто скористатися юридичними діями, які вам надано в командному рядку.
  • Рівна кількість символів у рядку вказує на те, що черга за вами, і програму пропонують вибрати дію, оскаржити блок або закінчити свою чергу.
  • Непарна кількість символів у рядку вказує на те, що черга не ваша, і вашу програму пропонується заблокувати, оскаржити або відкрити / здати карту.

Я наведу приклад для кожної дії.

I\nє найпростішим для розуміння. Програма бере одну монету доходу, а потім закінчує свою чергу. Це один з двох випадків, коли програми повинні надрукувати два символи, оскільки дохід - це єдине дію, коли опонент не впливає і не може блокувати чи кинути виклик.

Fp\nозначає, що одна програма взяла Foreign Aid, тоді її противник відмовився від блокування ( p). Під час свого наступного виклику перша програма зазначила, що підсумковим pрядком та / або парною кількістю символів у цьому рядку вона пройшла цей поворот, який ще не закінчився, тому знає закінчити свій поточний поворот, надрукувавши новий рядок.

C=\nозначає, що одна програма запустила переворот. Його опонент, знаючи, що його покликали реагувати непарною кількістю літер на лінії, відмовився від Contessa. Знову ж таки, перша програма знала, що це її неповна черга при наступному виклику парною кількістю символів на рядку, тому вона написала новий рядок, щоб закінчити свою чергу.

Eq~<\nозначало б, що одна програма намагалася обміняти обмін ( E), а його противник ( q). Програма обміну виявила, що в ній правдиво був посол ( ~), а претендент відмовився від капітана як покарання ( <). Після виходу виклику програма Обмін знову викликається чотирьох символьним рядком як четвертий аргумент командного рядка (або три символи, якщо вона мала лише одну карту). Він записує символи, що представляють картки, які він хоче зберегти в STDOUT, та новий рядок у файл.

Tq'\nозначає, що одна програма спробувала неправдивий податок, була оскаржена і відмовилася від вбивці. Він ілюструє інший випадок, коли написано два символи: якщо вам черга, і ви змушені відмовитись від картки - або від правильного виклику опонента (як тут), або від неправильного виклику блоку - тоді ви повинні написати обидва карту, яку ви віддаєте, і новий рядок, щоб закінчити свою чергу.

Asq!'\nозначатиме, що Гравець В намагався вбити гравця A ( A), але А стверджував, що має Contessa, щоб заблокувати його ( s). Б не повірив А і кинув виклик ( q). Виявлено, що вони насправді мали Contessa ( !). Б відмовився від вбивці як покарання, втративши монети, і закінчив свою чергу ( '\n), написавши двох символів, як у тому спеціальному випадку. (Якби A вирішив не блокувати чи кидати виклик, це могло б написати =, і тоді його опонент побачив би, що черга закінчилася і написала новий рядок. Потім рядок прочитав A=\nби, як приклад перевороту.)

Sq*0\nозначає, що одна програма намагається викрасти; супротивник кидає виклик, не вірячи, що у злодія є Капітан; і оригінальна програма розкриває капітана, тому виклик не вдається, і претендент відмовляється герцогу в якості покарання. (Іншим варіантом для його опонента було б прийняти крадіжку, написавши письмово p. Потім її противник виявить кінець своєї черги та напише \n, в результаті чого вийде рядок Sp\n.)

Арбітр

Програми будуть викликані цим сценарієм Python. Він проводить десять раундів, в яких кожен учасник стикається з кожним іншим учасником, переходячи як перший, так і другий. Він відслідковує підрахунки карт і монет і визначає програв першою програмою, щоб закінчити рядок з розділовим знаком двічі. Програми, які виходять із ненульовим статусом, змінюють файл, записують незаконне переміщення у файл або намагаються незаконно обмінятися, Exchange автоматично втрачається. Якщо кожен гравець виконує більше 100 дій, включаючи блоки та виклики, без переможця, то обидві програми програють. Переможцю надається один бал. Виграє гравець, програма якого набрала найбільше балів.

Я пропоную вам прочитати вихідний код арбітра, особливо get_legal_actionsфункцію. Це може допомогти вам зрозуміти специфікацію та написати власні програми.

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)

Різне

Одна програма не може мати код, специфічний для іншої програми, і програми не можуть допомогти один одному. (У вас може бути кілька програм, але вони ніяк не можуть взаємодіяти між собою.)

Якщо ваша програма втрачає обидві картки за один і той же поворот, їй потрібно написати лише одну. Арбітр виявить, що його було ліквідовано.

Програми можуть вивчати історію гри у файлі та заохочувати її, але не потрібно, але це не потрібно. Роблячи це, вони можуть визначити, які картки претендував їхній опонент, і впіймати їх у брехні.

У реальній грі на перевороті ви можете оскаржити дію, а потім спробувати заблокувати її тим же ходом. Я не міг зробити так, щоб специфікація працювала, якщо я дозволив це, тому ви можете або оскаржити, або заблокувати певну дію, але не обидва.

Мої вибачення у @PeterTaylor, який попереднього разу я опублікував це, запропонував відправити його в пісочну скриньку і переробити протокол, щоб виводити трубку назад і назад в STDOUT / STDIN. Я постарався так, так важко зробити цю роботу, витративши на неї цілий день (коли я вже витратив цілий день на написання оригінального виклику). Але Біржі виявилися дуже складними для здійснення цього шляху, плюс це збільшило б складність подань, вимагаючи від них відстежувати свій рахунок монет. Тому я виклав виклик більш-менш, як це було спочатку.


Я не зовсім зрозумів, як закінчилася черга. З посту успішний виклик / блок завершить поворот. А як щодо інших? Може хтось обміняється нескінченністю раз по черзі, поки опоненти не оскаржуватимуть?
TSH

@tsh Програма завжди закінчує свою чергу, написавши новий рядок, але вона може записати символ перед цим, якщо вона отримує дохід або втрачає карту самостійно. Успішний виклик / блок справді закінчить поворот. Успішний блок Steal пішов би: програма A пише S, програма B блокується письмом c, A відмовляється кинути виклик написанням \n. Успішний виклик крадіжки піде: A пише S, B кидає виклики письмово q, A визнає виклик, написавши, наприклад _\n, Ви можете вживати лише одну дію за поворот, включаючи обмін. Юридичні відповіді на біржі є прийнятими та складними.
Фіолетовий P

2
@jaaq Я ще не визначився з терміном. Я принаймні буду тримати його відкритим, поки ви не подасте :)
Purple P

1
@jaaq Арбітр проводить 10 раундів c P2 матчів у кожному, де c - кількість конкурентів. В даний час є 13 конкурентів, в результаті чого 10 (13P2) = 10 (13! / 11!) = 10 (13 * 12) = 1560 матчів.
Фіолетовий P

1
@jaaq Мене не було. Я повернувся. Оновлено.
Фіолетовий P

Відповіді:


4

Калькулятор

Планує свою переможну серію рухів і кидає виклик усім, що заважало б йому виграти.

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")

Пальто

Спочатку говорить правду, але починає брехати, коли перестає бути оскарженим. Також має певну рішучу поведінку. (Наближення того, як я поводжусь, граючи в цю гру з людьми)

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")

Бандит

Намагається позбутися опонентів і капітанів противника і перемагати, вкравши.

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

Криваве вбивство

Цей аналог Бандіту, який входить до складу стратегії герцога + Вбивця.

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

Все додано до лідерів, і це дуже добре! Я можу запропонувати перейменувати «Премію» на «Поверну»? Це робить трохи драматичнішим :)
Purple P

@PurpleP Перейменовано! "Зрада" була трохи поспішним вибором; воно насправді було названо своїм іменем під час розробки, але це не здавалося правильним, коли у мене було кілька учасників.
Brilliand

Калькулятор додано до таблиць лідерів.
Фіолетовий P

1
Вітаємо, калькулятор - Король гори!
Фіолетовий П

4

Сольвер

Сольвер намагайся пригадати, за які карти грали раніше і якими були попередні ходи опонента.

це друга версія ще не закінчена (і зараз це великий безлад)

щоб він працював на вузлі 10 дод competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))

якщо вузол 12 competitors.append(Player("Solver", ["node", "./solver.js"]))

будьте обережні з типом файлу

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))


```

Оскільки ви ніколи не оскаржуєте біржу супротивника, ви, можливо, захочете врахувати її, оскільки це приводить до недійсності ваших знань про їхні картки.
Фіолетовий P

Нова версія працює. Це
Пітер

1
Я оновлю таблицю лідерів, коли опублікую готову версію.
Фіолетовий P

Дякую, я щойно звільнив, якщо гравець покаже свою картку, ідентифікатор картки видалить з його руки і додав назад до колоди. Це робить половину моєї логіки неправильною: DI потрібно це виправити. (Я здивований, як я зробив такий хороший бал із поганою логікою) pastebin.com/AXGJ9v5Q <--- останні 2 черги! була видалена моя рука. Або це клоп?
Пітер

Це не помилка. Коли ви виявите карту, щоб виграти виклик, вона виймається з вашої руки, і вам видається нова з колоди.
Фіолетовий P

3

Юрист

Юрист обережно пробирається по світу, ніколи не бреше, блокує, коли це можливо, кидає виклик, коли не на його шкоду. Він не атакує, за винятком випадків, коли вимагає купінгу, але буде брати монети якомога частіше, щоб швидко перевороту. Він досить розумний, щоб пожертвувати картками, які він спочатку не використовує, але недостатньо розумний, щоб використовувати їх, щоб позбутися від них та отримати нові.

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")

Напевно, в цій програмі є помилки. Коли ви їх знайдете, будь ласка, повідомте мене про це.


@PurpleP Добрий момент. Я це зафіксував. Навички прийняття рішень дуже важливі для хорошого юриста.
Хіацу

Ви перевірили, що файл насправді не закінчується новим рядком? (наприклад, відкрити файл і побачити велику літеру в середині рядка?) Я розглядаю причини цього і хочу переконатися, що це виключено.
Хіацу

@PurpleP Чи можу я завантажувати налагоджувальну версію, яка використовує STDOUT для необмінних цілей, і чи надіслали ви мені результати?
Хіацу


Маск і Адвокат можуть потрапити в цикл, який змушує їх обох втрачати. Якщо у Адвоката є одна картка, яка не є герцогом, вона завжди намагатиметься викрасти. Тоді Маск завжди буде вимагати від Посла, щоб заблокувати його, і Обміняти, щоб покрити його сліди. Приклад гри. Я не скаржуюся і не прошу вас це виправити; Я просто хотів, щоб ти знав, бо це щось смішно.
Фіолетовий P

2

Випадкові

Випадковий не знає, що робити, тому він випадковим чином вибирає щось легальне.

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)
    }
}

Челленджер

Челленджер нікому не довіряє в цій грі обману. Якщо ви зробите щось складне, він кине вам виклик. В іншому випадку він просто бере дохід на кожному кроці і намагається купірувати вас, якщо у нього є монети.

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'})
    }
}

Скомпілюйте ці програми go build random.go/challenger.goта запускайте з ./randomабо ./challenger.


Рекомендую не присвоювати гендерну інформацію комп'ютерним програмам. У спільнотах, що програмують, вже достатньо гендерної упередженості, а дефолтні займенники чоловічої статі ще більше свідчать про те, що жінки не бажають.
Грег Мартін

2

Податкові

Таксист тут збирає податок. Використовує вбивцю, якщо вони є. Блокуйте лише, якщо у них є картка для блокування. Випадково виклики.

Написаний в c #, я витратив занадто довго, будуючи ієрархію класів для всіх різних дій, які можна вжити.

Редагувати: Тепер з покращеною логікою, як, наприклад, не вимагаючи герцога, коли вони відмовилися від герцога після виклику. Також більше не намагається постійно вбивати, якщо противник блокує команду contessa (і не оскаржується).

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; } }

Я не можу коментувати оригінальний пост, але я хотів вказати на помилку в арбітрі, в тому determine_turn_effects(), що крадіжка займає всі монети противника. Це має брати щонайменше дві монети.
Дисконім

Коли ця програма намагається здійснити обмін, вона втрачає, виводячи порожній рядок. Приклад ігор проти випадкових.
Фіолетовий P

Я компілював це з візуальною студією на windows. Коли я вдома, я переконаюсь, що це працює і з Моно. Exchange використовує Console.WriteLine (), щоб записати для std out. Це спрацювало, коли я тестував його, я буду його досліджувати далі та оновити.
Дисконім

1
Я думаю, що проблема полягає в тому, що ви перевіряєте "lastArg", але обмінні картки вам видаються в індексі 3, як і інші ваші картки.
Фіолетовий P

1
Додано до лідерів.
Фіолетовий P

1

Адвокат Рендо Агро

Подібно до юриста, він робить лише юридичні речі. Однак він вбиває, перетворюється на купівлю раніше, і він вибирає деякі дії випадковим чином (наприклад, коли робити виклик).

#! /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())

Я організував функцію give_card, щоб відмовитись від карт, які адвокат використовує не в першу чергу. Якщо ви фактично використовуєте Assassin, можливо, ви захочете переставити цю функцію, щоб довше зберегти її.
Хіацу

Дякую за те, що помітили, що я вибрав це розпорядження, очікуючи, що воно буде використовувати посол, але не вистачило часу. Я змінив наказ про відмову, щоб зробити більше сенсу, а також зробив його більш агрогромадженим шляхом крадіжки перед оподаткуванням.
gggg

1

Маска

Маска - майстер маскування. Він заважає супротивникам відслідковувати свої картки, обмінюючись кожен раз, коли він діє чи блокує. Його стратегія виграшу - взяти 3 монети як герцог, а потім вбивство.

Компілюйте go build mask.go, запускайте з ./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")
    }
}

Рекомендую не присвоювати гендерну інформацію комп'ютерним програмам. У спільнотах, що програмують, вже достатньо гендерної упередженості, а дефолтні займенники чоловічої статі ще більше свідчать про те, що жінки не бажають.
Грег Мартін

3
@GregMartin Якщо будь-яка жінка сказала, що моє примхливе статеве представлення моїх подань, уявляючи їх як підступні придворні, як у картковій грі, змусило її почути себе ображеною чи не бажаною, то я би змінив це серцебиттям. Але ти не жінка, Грег. І мені не подобається, що ви надіслали негативам відповідь, на яку я доклав найбільше зусиль, і та, яка найкраще справляється у моєму виклику - не тому, що це не має значення чи погана відповідь на питання, а через незначну соціальну невдачу .
Фіолетовий P

1

Азартний гравець

Азартний гравець має чітко розроблену стратегію, але довіряє своїй кишці, коли ситуація не враховується в його стратегії виграшу. Він намагається вкрасти багато і перевороти / вбивці, коли це можливо.

Написано в 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)

Статистик

Знає свою стратегію виграшу, як і азартний гравець, але завжди довіряє максимальні ймовірності замість випадкової вибірки з них.

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
Ця програма виходить з ладу на порожній файл, коли він виходить першим. Коли він йде другим, він падає з повідомленням на кшталт: 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.
Фіолетовий P

вдалося виправити цю помилку. вибачте, я розмістив це якось поспіхом. Я переконуюсь, щоб протестувати його з вашим арбітром до завтра, але одна очевидна помилка була виправлена. Вибачте знову.
jaaq

1
Хороша новина, обмін коштами працює на моїй машині! Він все одно виходить з ладу, якщо його опонент спробує іноземну допомогу, і у неї немає герцога, але він був доданий до лідерів.
Фіолетовий P

1
@jaaq Він все-таки втрачає, якщо його противник намагається зарубіжної допомоги, а у неї немає герцога; на це потрібно відповісти пропуском, а не закінченням розвороту.
Brilliand

1
@jaaq Я виправив помилку, про яку згадує Брілліанд, і додав статистику до таблиці лідерів. Коли ваші записи вбиті, залишившись однією карткою, вони втрачають свою силу, написавши \nзамість картки, яку вони хочуть здати. У такій ситуації краще боротися з блоком або викликом. Якби Гамблер виграв 5 ігор, яких він програв так, він зайняв би перше місце.
Фіолетовий P
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.