# Stage a Coup to become king of the hill!

## Calculator

Plans out his winning series of moves, and challenges anything that would prevent him from winning.

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
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'
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()
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':
elif line == 'S' or line == 'Sc':
elif line == '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")  ## Turncoat Tells the truth at first, but starts lying when it stops being challanged. Also has some solver-behavior. (An approximation of how I behave when playing this game with humans) 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:
if len(line) > 2 and line.endswith('\n') and line[-2] in lossActions:
if len(line) > 2 and line.endswith('\n') and (line.startswith('Ep') or line.startswith('Eq~')):
othercaughtlies = set()
if '*' in flags:
if line[-1] not in 'qdacs':
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'
if '~' in mycards:
if action.strip("\n") in lossActions:
if line[-1] == 'q':
# Also stop claiming what we were challenged for
if action == 'q':
# We challenged it.  One way or another, they will not have this card later.
if action in actions_dict:
history.write(action)

if len(mycards) > 2:
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:
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")


## Bandit

Tries to get rid of the opponent's Ambassadors and Captains, and win by stealing.

import sys
import random

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

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

def getFavoriteCards():
return ['*', '!', '~', '$', '^'] def pickCardToLose(): # Losing a card. Decide which is most valuable. favoriteCards = getFavoriteCards() cardToLose = '' for k in favoriteCards: if k in mycards: cardToLose = k for k in mycards: if not k in favoriteCards: cardToLose = k return reveal_to_punishment[cardToLose] with open(filename, "r+") as history: line = "\n" turn = 0 for a in history: line = a turn += 1 action = legalActions[0] if set(obviousActions).intersection(legalActions): # Always take these actions if possible for a in set(obviousActions).intersection(legalActions): action = a elif 'p' in legalActions and turn == 1 and line == "E": # Let this pass... once action = 'p' elif 'q' in legalActions and line[-1] in 'SEac': # These get in the way of stealing, get rid of them even if it costs us a card action = 'q' elif 'E' in legalActions and '~' in mycards and '*' not in mycards: action = 'E' elif 'S' in legalActions: action = 'S' elif 's' in legalActions: if '!' in mycards: action = 's' elif len(mycards) == 1: action = random.choice('sq') else: action = pickCardToLose() elif 'p' in legalActions: action = 'p' elif line == 'A' or line == 'C': # Taking damage action = pickCardToLose() elif len(line) == 2 and line[1] == 'q': # My base action was successfully challenged action = pickCardToLose()+"\n" elif len(line) == 3 and line[1] == 'q': # I failed challenging a base action action = pickCardToLose() elif len(line) == 3 and line[2] == 'q': # My block was successfully challenged action = pickCardToLose() elif len(line) == 4 and line[2] == 'q': # I failed challenging a block action = pickCardToLose()+"\n" history.write(action) if len(mycards) > 2: # Losing two cards. Decide which is most valuable. favoriteCards = getFavoriteCards() possibleCards = [k for k in favoriteCards if k in mycards] if mycards.count('*') > 1: # Hooray captains! possibleCards = ['*'] + possibleCards if len(possibleCards) < len(mycards) - 2: possibleCards = list(mycards) random.shuffle(possibleCards) mycards = ''.join(possibleCards[:(len(mycards)-2)]) print mycards  ## Bloody Murder A counterpart to Bandit, this one goes all-in on a Duke+Assassin strategy. 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


## Solver

Solver try to remember what cards are played before and what was the previous moves of the opponent.

this is the 2nd version not finished yet (and it is a big mess now)

to make it work on node 10 add competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))

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

be carefull with the file type

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

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

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.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(
);
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)) $$$$  ## Lawyer The Lawyer makes his way cautiously through the world, never lying, blocking when possible, challenging when not to his immediate detriment. He does not attack except when required by couping, but will take coins as often as possible in order to coup quickly. He is smart enough to sacrifice cards he does not use first, but not smart enough to use them to get rid of them and get new ones. 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")
`

There are probably bugs in this program. When you find them, please let me know.