Tabela liderów
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
Dostępne jest archiwum najnowszego dopasowania, w tym dziennik i wszystkie pliki wyjściowe.
Zwycięzcą jest kalkulator Brilliand! Jego odpowiedź została zaakceptowana, ale to nie znaczy, że wyzwanie się skończyło. Nie krępuj się przesyłać nowych wpisów lub edytować swoje obecne i spróbować zrzucić go z tronu. Pod koniec miesiąca przyznam nagrodę liderowi.
Zasady gry
Zamach stanu to gra karciana przeznaczona dla 2-6 graczy, w którą będziemy grać z dwoma. Składa się ze skarbca monet (nieskończonego dla naszych celów) i talii 15 kart, zawierającej 3 każdego z następujących typów: Ambasador, Zabójca, Kapitan, Contessa, Książę. Na początku gry każdy gracz otrzymuje jedną monetę i losowo otrzymuje dwie karty, które trzymają w tajemnicy, dopóki nie będą konieczne. Celem jest bycie ostatnim graczem z kartami w ręku.
W swojej turze gracz może wykonać jedną z następujących akcji niezależnie od swoich kart:
- Dochód: weź 1 monetę ze skarbca. Odblokowalne i niepodważalne.
- Pomoc zagraniczna: weź 2 monety ze skarbca. Może zostać zablokowany przez gracza z księciem. Nie do zakwestionowania.
- Zamach stanu: Usuń z gry kartę jednego wybranego przeciwnika. Kosztuje 7 monet. Ofiara może wybrać, którą kartę odrzucić. Jeśli gracz ma 10 lub więcej monet na początku swojej tury, musi dokonać przewrotu. Odblokowalne i niepodważalne.
W zależności od swoich kart gracze mogą również wykonać jedną z następujących akcji w swojej turze:
- Wymiana: gracz z Ambasadorem może wziąć dwie karty z talii. Następnie mogą wybrać z ręki i wylosowanych kart tyle kart, ile pierwotnie posiadały. (To znaczy, jeśli mieli tylko jedną kartę, mogą ją wymienić na jedną z losowanych kart lub zatrzymać ją, a jeśli mieli dwie karty, mogą wybrać dowolne dwie z czterech kart.) Dwie niepożądane karty są zwracane do talii . Można go odblokować, ale można go zakwestionować.
- Zabójstwo: gracz z Zabójcą może wydać 3 monety, aby usunąć kartę przeciwnika z gry. Ofiara może wybrać, którą kartę odrzucić. Może zostać zablokowany przez gracza posiadającego Contessa, w którym to przypadku monety nie są zwracane. Wyzwanie, w którym to przypadku monety są zwracane.
- Kradzież: Gracz z kapitanem może wziąć od swojego przeciwnika dwie monety. Jeśli przeciwnik ma jedną monetę, weźmie tę jedną monetę. Jeśli przeciwnik ma zero monet, nie może kraść. Może zostać zablokowany przez gracza z Ambasadorem lub Kapitanem. Wyzwanie
- Podatek: Gracz z księciem może wziąć 3 monety ze skarbca. Można go odblokować, ale można go zakwestionować.
Trudna część zamachu polega na tym , że gracze mogą kłamać na temat posiadanych kart! Nie trzeba mieć karty, aby spróbować wykonać akcję lub blok z nią związany.
Kiedy gracz wykonuje akcję karty, każdy przeciwnik (nawet ten, który nie ucierpiał w wyniku tej akcji) może rzucić wyzwanie aktorowi i powiedzieć, że nie wierzy, że ma kartę dla tej akcji. Jeśli pretendent ma rację, akcja zostaje anulowana, a aktor musi odrzucić jedną wybraną kartę (w razie potrzeby odzyskać wydane monety). Jeśli nie, akcja jest podejmowana, aktor zwraca kartę, której dotyczy wyzwanie, i dobiera nową, a pretendent musi odrzucić jedną ze swoich kart. Gracze muszą być prawdomówni co do tego, jakie karty posiadają podczas wyzwania.
Karty wyeliminowane z gry Assassinate, Coup i przegrane wyzwania nie są zwracane do talii, ale karty odkryte w ramach wygranego wyzwania są zwracane do talii.
Bloki mogą być kwestionowane podobnie jak akcje. Na przykład, jeśli gracz A żąda pomocy zagranicznej, a gracz B mówi „Mam księcia, a ja blokuję twoją pomoc zagraniczną”, A może powiedzieć „Nie wierzę, że masz księcia”. Jeśli to twierdzenie jest prawidłowe, B traci kartę za złapanie w kłamstwo, a A bierze 2 monety; jeśli tak nie jest, A traci kartę i nie otrzymuje monet, a B musi zwrócić księcia do talii i dobrać nową kartę.
Sposób, w jaki bloki i wyzwania działają w Assassinate, musi zostać dopracowany. Załóżmy, że gracz A mówi „Mam zabójcę i zabijam gracza B”. Jeśli B nie podejmie wyzwania ani nie zablokuje A, zabójstwo przechodzi: B traci kartę, a A płaci 3 monety.
Alternatywnie B może rzucić wyzwanie, mówiąc „Nie wierzę, że masz zabójcę”. Jeśli to prawda, A odrzuca kartę, a ich monety są zwracane, podczas gdy B pozostaje nienaruszony, a tura A się kończy. Jeśli wiara B jest nieprawidłowa, a A trzyma Zabójcę, B traci obie swoje karty i ponosi porażkę, jedną za nieprawidłowe wyzwanie, a drugą od Zabójstwa.
Zamiast rzucić wyzwanie, B mógłby powiedzieć „Mam Contessę i blokuję Zabójcę”. Jeśli A uważa B, tura A kończy się, a ich monety nie są zwracane. Ale A może rzucić wyzwanie blokowi i powiedzieć: „Nie wierzę, że masz Contessę”. Jeśli B faktycznie posiada Contessę, A traci kartę za nieprawidłowe wyzwanie. Ale jeśli B nie, to B traci jedną kartę za złapanie w kłamstwo, a drugą z Zabójstwa.
Podobna logika do powyższego wyjaśnienia dotyczy umiejętności Kradzieży Kapitana, w której akcja lub blok mogą zostać zakwestionowane.
Można stracić obie karty i zostać wyeliminowanym w jednej turze, jeśli bezskutecznie rzucisz wyzwanie Zabójcy lub zostaniesz przyłapany na fałszywym twierdzeniu, że masz Contessę do zablokowania Zabójstwa. Tracisz jedną kartę z wyzwania i jedną kartę z Zabójstwa.
Wyzwanie
Twoim zadaniem jest napisanie programu, który zagra zamach stanu. Zostanie podany jako argumenty wiersza poleceń:
- Nazwa pliku zawierającego listę dotychczasowych działań jego i przeciwników.
- Liczba całkowita od 0 do 12 wskazująca liczbę monet przeciwnika.
- Liczba całkowita od 0 do 12 wskazująca liczbę monet.
- Ciąg od jednego do czterech znaków wskazujący jego karty. Zwykle będzie to po prostu jedna lub dwie karty, które ma Twój program, ale jeśli twój program właśnie zakończył się sukcesem na wymianie, będzie miał długość n + 2 znaków, gdzie n to liczba pozostałych kart. Twój program musi następnie wypisać n kart, które chce zachować do STDOUT. (Programy nie mogą odczytywać ani uzyskiwać dostępu do STDOUT inaczej niż w tym celu - jeśli chcesz wygenerować wyjście debugowania, napisz do STDERR.)
- Jeden lub więcej argumentów wskazujących na legalne ruchy, które może wykonać.
(Przykładowe wywołanie: yourprogram file.txt 1 7 '~!' a c p q
oznacza „Twój przeciwnik ma 1 monetę. Masz 7 monet, Ambasadora i Contessę. Napisz do pliku.txt do wyboru a, c, p lub q, biorąc pod uwagę historię gry i aktualny stan gry. „)
Twój program musi dołączyć jeden lub (w dwóch określonych sytuacjach) dwa znaki do dostarczonego pliku, wskazując jego działanie. Nie może inaczej zmieniać istniejącej zawartości pliku. Może tworzyć dowolne nowe pliki, ale tylko w katalogu, w którym jest uruchomiony. Podaj wszystkie niezbędne polecenia, aby skompilować i uruchomić program.
Podałem poniżej dwa przykłady konkurentów, napisane w języku Go.
Format wyjściowy to:
I\n
: Dochód. Odpowiedzi prawne: każda akcja tury (zakładając, że masz monety za Zabójstwo / Zamach stanu).F
: Pomoc zagraniczna. Odpowiedzi prawne:d
(blok jako książę),p
(pozwól mu przejść).C
: Pucz. Odpowiedzi prawne: w zależności od_
,'
,<
,=
,0
jest w twojej dłoni.E
: Wymieniać się. Odpowiedzi prawne:q
(wyzwanie, nie wierząc, że gracz ma ambasadora)p
.T
: Podatek. Odpowiedzi prawne:q
(wyzwanie, nie wierząc, gracz ma Duke)p
.A
: Zabójstwo. Odpowiedzi prawne:s
(blok jako Contessa),q
(challenge), oraz w zależności od_
,'
,<
,=
,0
to w dłoni.S
: Skraść. Odpowiedzi prawne:a
(blok jako ambasador),c
(blok jako kapitan),q
(wyzwanie, nie wierząc, gracz ma kapitanie)p
.d
: blok Pomoc zagraniczna jako książę. Odpowiedzi prawne:\n
(zaakceptuj blok),q
(wyzwanie, nie wierząc, że gracz ma księcia).a
: zablokuj kradzież jako ambasador. Odpowiedzi prawne:\n
(zaakceptuj blok),q
(wyzwanie, nie wierząc, że gracz ma ambasadora).c
: zablokuj kradzież jako kapitan.\n
(zaakceptuj blok),q
(wyzwanie, nie wierząc, że gracz ma kapitana).s
: zablokuj Assassinate jako Contessa. Odpowiedzi prawne:\n
(zaakceptuj blok),q
(wyzwanie, nie wierząc, że gracz ma Contessę).p
: zaliczaj wyzwanie wymiany / podatku / kradzieży, gdy nie jest twoja kolej. Nieużywany zA
; odmówić zakwestionowania Zabójstwa napisz jeden z nich_'<=0
. Odpowiedź prawna:\n
(zakończ swoją turę), a jeśli właśnie odniosłeś sukces na wymianie, wypisz karty, które chcesz zachować, z argumentu z czwartego wiersza poleceń do STDOUT.q
: kwestionuj najnowszą akcję lub blok. Odpowiedź prawna: jeśli masz kartę do działania, które zostało zakwestionowane, cokolwiek~^*!$
to było. Jeśli tego nie zrobisz, to cokolwiek_'<=0
z ręki, którą chcesz zrezygnować, po którym następuje nowa linia, jeśli tylko twoja kolej.~
,^
,*
,!
,$
: Ujawniać, że mówienie prawdy o gospodarstwo, odpowiednio, ambasadorem, zabójca, kapitan, o Contessa i Duke (również używane do reprezentowania tych kart w argumenty wiersza poleceń, a stdout w wymianie ). Odpowiedzi prawne: w zależności od_
,'
,<
,=
,0
masz w ręku._
,'
,<
,=
,0
: Zrezygnować za karę, odpowiednio, ambasadora oraz Assassin, kapitan, a Contessa i Duke'a bo straciłeś wyzwanie lub zostali zamordowani / couped. Odpowiedź prawna:\n
.\n
: zakończ swoją turę, odmawiając rzucić wyzwanie blokowi, jeśli dotyczy. Odpowiedzi prawne: każda akcja z użyciem dużej litery (zakładając, że ktoś ma monety za Zabójstwo / Zamach stanu, a przeciwnik ma monety za Kradzież).
Format ma następujące przydatne właściwości:
- Tury zaczynają się od dużej litery.
- Linie mają wzór: wielkie litery, małe litery, opcjonalnie znaki interpunkcyjne lub 0 dla odkrytych kart, nowa linia.
- Plik kończący się znakiem nowej linii lub pusty plik wskazuje, że jest to początek tury twojego programu i musi wybrać akcję wielką literą.
- Czynności prawne, które możesz podjąć w związku z wywołaniem, są zazwyczaj jednoznacznie określone przez ostatni znak w pliku. Wyjątkiem jest
q
, z którą będzie związana pewna logika. Zobacz funkcjęget_legal_actions
arbitra, aby to zrozumieć. Lub możesz po prostu użyć czynności prawnych podanych w wierszu poleceń. - Parzysta liczba znaków w linii wskazuje, że twoja tura jest twoja, a twój program jest proszony o wybranie akcji, wyzwanie bloku lub zakończenie jego tury.
- Dziwna liczba znaków w linii wskazuje, że kolej nie jest twoja, a twój program jest proszony o zablokowanie, zakwestionowanie lub ujawnienie / oddanie karty.
Podam przykład każdej akcji.
I\n
jest najłatwiejszy do zrozumienia. Program bierze jedną monetę Dochodu, a następnie kończy swoją turę. Jest to jeden z dwóch przypadków, w których programy muszą wydrukować dwie postacie, ponieważ dochód jest jedyną czynnością, w której przeciwnik jest jednocześnie nietknięty i nie może blokować ani rzucać wyzwania.
Fp\n
oznacza, że jeden program wziął pomoc zagraniczną, a następnie przeciwnik odmówił zablokowania ( p
). Przy następnym wywołaniu pierwszy program zauważył, że przez ostatnią małą literę p
i / lub parzystą liczbę znaków w tym wierszu zabrał tę kolejkę, która jeszcze się nie skończyła, więc wie, że może zakończyć swoją obecną kolejkę, drukując nowy wiersz.
C=\n
oznacza, że jeden program uruchomił zamach stanu. Przeciwnik, wiedząc, że został wywołany nieparzystą liczbą liter na linii, zrezygnował z Contessy. Ponownie, pierwszy program wiedział, że to jego niepełna kolejka przy następnym wywołaniu przez parzystą liczbę znaków w linii, więc napisał nowy wiersz, aby zakończyć swoją kolej.
Eq~<\n
oznaczałoby, że jeden program podjął próbę wymiany ( E
), a jego przeciwnik zakwestionowany ( q
). Program wymiany ujawnił, że zgodnie z prawdą ma ambasadora ( ~
), a pretendent podał kapitana za karę ( <
). Po wyjściu pretendenta program wymiany jest ponownie wywoływany z czteroznakowym łańcuchem jako czwartym argumentem wiersza poleceń (lub trzema znakami, jeśli miał tylko jedną kartę). Zapisuje znaki reprezentujące karty, które chce zachować, do STDOUT i nową linię do pliku.
Tq'\n
oznacza, że jeden program podjął próbę niezgodnego z prawdą podatku, został zakwestionowany i zrezygnował z zabójcy. To ilustruje inny przypadek, w którym napisane są dwie postacie: jeśli to twoja kolej i jesteś zmuszony zrezygnować z karty - albo z prawidłowego wyzwania przeciwnika (jak tutaj), albo z niewłaściwego wyzwania bloku - musisz napisać oba kartę, którą rezygnujesz i nową linię, aby zakończyć swoją turę.
Asq!'\n
oznaczałoby to, że Gracz B próbował zabić gracza A ( A
), ale A twierdził, że ma Contessę, aby go zablokować ( s
). B nie uwierzył A i zakwestionował ( q
). Ujawniono, że w rzeczywistości mieli Contessa ( !
). B poddał Zabójcę karą, tracąc monety i zakończył swoją turę ( '\n
), pisząc dwie postacie, jak w tym szczególnym przypadku. (Gdyby A zdecydował się nie blokować ani nie rzucać wyzwania, mógłby napisać =
, a wtedy jego przeciwnik zobaczyłby, że kolej się skończyła i napisał nową linię. Linia przeczytałaby A=\n
, podobnie jak przykład Zamachu.)
Sq*0\n
oznacza, że jeden program próbuje ukraść; przeciwnik rzuca wyzwanie, nie wierząc, że złodziej ma kapitana; a oryginalny program ujawnia kapitana, więc wyzwanie nie powiodło się, a pretendent poddaje księcia jako karę. (Inną opcją dla jego przeciwnika byłoby przyjęcie Kradzieży przez napisanie p
. Jego przeciwnik wykryłby koniec swojej tury i napisał \n
, co spowodowałoby linię Sp\n
.)
Arbiter
Programy będą wywoływane przez ten skrypt w języku Python. Prowadzi dziesięć rund, w których każdy zawodnik zmierzy się z każdym innym zawodnikiem podczas pierwszego i drugiego. Śledzi liczbę kart i monet i określa przegranego przez pierwszy program, który dwukrotnie kończy linię ze znakiem interpunkcyjnym. Programy, które wychodzą z niezerowym statusem, modyfikują plik, zapisują nielegalne przeniesienie do pliku lub próbują nielegalnej wymiany, automatycznie przepadną. Jeśli każdy gracz podejmie ponad 100 akcji, w tym bloków i wyzwań, bez zwycięzcy, oba programy przegrywają. Zwycięzca otrzymuje jeden punkt. Gracz, którego program zdobędzie najwięcej punktów, wygrywa.
Sugeruję przeczytanie kodu źródłowego Arbiter, zwłaszcza get_legal_actions
funkcji. Pomoże Ci to zrozumieć specyfikację i napisać własne programy.
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)
Różne
Jeden program nie może mieć kodu specyficznego dla innego programu, a programy nie mogą sobie nawzajem pomagać. (Możesz mieć wiele programów, ale nie mogą one ze sobą w żaden sposób współdziałać).
Jeśli twój program traci obie karty w tej samej turze, wystarczy napisać tylko jedną. Arbiter wykryje, że został wyeliminowany.
Jest możliwe i zalecane, ale nie wymagane, aby programy badały historię gry w pliku. W ten sposób mogą ustalić, jakie karty twierdził przeciwnik, i złapać je w kłamstwie.
W prawdziwej grze zamachu możesz rzucić wyzwanie akcji, a następnie spróbować zablokować ją w tej samej turze. Nie mogłem sprawić, by specyfikacja działała, jeśli na to pozwoliłem, więc możesz albo zakwestionować, albo zablokować dane działanie, ale nie jedno i drugie.
Przepraszam @PeterTaylor, który przy poprzednim opublikowaniu tego sugerował, że opublikuję go w piaskownicy i przerobię protokół przesyłania danych wyjściowych w obie strony w STDOUT / STDIN. Tak bardzo się starałem, aby ta praca działała cały dzień (kiedy już spędziłem cały dzień na pisaniu oryginalnego wyzwania). Jednak wymiana okazała się bardzo skomplikowana w realizacji w ten sposób, a ponadto zwiększyłaby złożoność zgłoszeń, wymagając od nich śledzenia własnej liczby monet. Więc opublikowałem wyzwanie mniej więcej tak, jak było pierwotnie.
źródło
S
, program B blokuje piszącc
, A odmawia zakwestionowania pisząc\n
. Udane wyzwanie Kradzieży poszedłoby: A piszeS
, B wyzwania piszącq
, A przyznaje wyzwanie pisząc np._\n
Możesz wykonać tylko jedną akcję na turę, w tym Wymianę. Odpowiedzi prawne na Exchange są pozytywne i stanowią wyzwanie.Odpowiedzi:
Kalkulator
Planuje swoją zwycięską serię ruchów i rzuca wyzwanie wszystkim, co uniemożliwiłoby mu zwycięstwo.
Zdrajca
Najpierw mówi prawdę, ale zaczyna kłamać, kiedy przestaje być wyzwaniem. Ma także pewne zachowanie solvera. (Przybliżenie tego, jak się zachowuję, grając w tę grę z ludźmi)
Bandyta
Próbuje pozbyć się ambasadorów i kapitanów przeciwnika i wygrać poprzez kradzież.
Krwawe Morderstwo
Jest to odpowiednik strategii Bandit, który wchodzi w skład strategii Duke + Assassin.
źródło
Solver
Solver stara się zapamiętać, jakie karty zostały zagrane wcześniej i jakie były poprzednie ruchy przeciwnika.
to druga wersja jeszcze nieukończona (i teraz jest wielki bałagan)
aby działał na węźle 10 dodaj
competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))
jeśli węzeł 12
competitors.append(Player("Solver", ["node", "./solver.js"]))
bądź ostrożny z typem pliku
źródło
Prawnik
Prawnik ostrożnie przedziera się przez świat, nigdy nie kłamie, blokując, gdy to możliwe, wyzwaniem, gdy nie jest to jego bezpośrednia szkoda. Nie atakuje, chyba że jest to wymagane przez przewrót, ale bierze monety tak często, jak to możliwe, aby szybko przewrócić. Jest wystarczająco sprytny, by poświęcić karty, których najpierw nie używa, ale nie jest wystarczająco sprytny, aby użyć ich, aby się ich pozbyć i zdobyć nowe.
Prawdopodobnie w tym programie są błędy. Kiedy je znajdziesz, daj mi znać.
źródło
Losowy
Random nie wie, co robić, więc losowo wybiera coś legalnego.
Pretendent
Pretendent nie ufa nikomu w tej grze oszustwa. Jeśli zrobisz coś wymagającego, on rzuci ci wyzwanie. W przeciwnym razie po prostu zbiera dochód co turę i próbuje Cię przewrócić, jeśli ma monety.
Skompiluj te programy za
go build random.go/challenger.go
pomocą./random
lub./challenger
.źródło
Podatnik
Podatek jest tutaj, aby pobrać podatek. Używa zabójcy, jeśli go ma. Blokuje tylko, jeśli ma kartę do zablokowania. Losowe wyzwania.
Napisane w języku c # spędziłem zbyt długo na budowaniu hierarchii klas dla wszystkich różnych działań, które można podjąć.
Edycja: Teraz z ulepszoną logiką, taką jak brak pretensji do posiadania księcia, gdy zrezygnowali z księcia po rzuceniu wyzwania. Również nie próbuje już ciągle zabijać, jeśli przeciwnik blokuje contessa (i nie jest kwestionowany).
źródło
determine_turn_effects()
akcji Kradzież bierze wszystkie monety przeciwnika. Powinno zabrać najwyżej dwie monety.Prawnik Rando Aggro
Podobnie jak prawnik, zajmuje się wyłącznie czynnościami prawnymi. Jednak zabija, przewraca się wcześniej i wybiera losowo niektóre akcje (np. Kiedy Rzuć wyzwanie).
źródło
Maska
Maska jest mistrzem przebrania. Uniemożliwia przeciwnikom śledzenie jego kart poprzez wymianę za każdym razem, gdy działa lub blokuje. Jego zwycięską strategią jest zabranie 3 monet jako książę, a następnie zabójstwo.
Kompiluj z
go build mask.go
, uruchamiaj z./mask
.źródło
Gracz
Gracz ma rozbudowaną strategię, ale ufa sobie, gdy sytuacja nie jest uwzględniona w jego zwycięskiej strategii. Próbuje dużo ukraść i zamach stanu / zabójstwo, gdy tylko jest to możliwe.
Napisane w Python3:
Statystyk
Zna swoją zwycięską strategię, podobnie jak hazardzista, ale zawsze ufa maksymalnym prawdopodobieństwom, zamiast losowego próbkowania z nich.
źródło
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
.\n
zamiast karty, którą chcą zrezygnować. W takiej sytuacji lepiej jest walczyć z blokiem lub wyzwaniem. Gdyby Gambler wygrał w 5 tak utraconych grach, zająłby pierwsze miejsce.