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
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")
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:
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")
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 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))
```
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.