#The Logician
 
 #!/usr/bin/env python3
 import sys
 import os
 import re
 import random
 from types import SimpleNamespace
 def chooseSet(set):
 return random.choice(list(set))
 sys.stdin = open("from_server")
 sys.stdout = open("to_server","w")
 def saveData(data):
 with open("gameData.txt", "w") as datafile:
 datafile.write(repr(data.__dict__))
 MY_NAME = os.path.basename(os.getcwd())
 opener = input()
 DATABASES = ("targets","herd","mafiosos","guilty","innocent","unlikely", "requests",
 "selfvotes","players","used_roles")
 ALLOW_SELF = ("players", "mafiosos")
 LIESPERROLE = {"cop": ("I am the cop",
 "I investigated this player and found that they were mafia-aligned",
 "I investigated this player and found that they were village-aligned"),
 "doctor": ("I am the doctor",
 "I tried to save this player",
 "I successfully saved this player"
 )
 }
 #1: At the beginning of the game, parse beginning of day 0
 if opener == "Rise and shine! Today is day 0.":
 #Next two lines are completely predetermined and hold no data
 assert input() == "No voting will occur today."
 assert input() == "Be warned: Tonight the mafia will strike."
 data = SimpleNamespace(cop=False, doctor=False, queued=[],askers={})
 for datum in DATABASES:
 setattr(data, datum, set())
 try:
 nextline = input()
 if nextline == "You are a member of the mafia.":
 data.mafiosos.add(MY_NAME)
 assert input() == "Your allies are:"
 while True:
 data.mafiosos.add(input())
 elif nextline == "You are the doctor":
 data.doctor = True
 data.used_roles.add("doctor")
 elif nextline == "You are the cop":
 data.cop = True
 data.used_roles.add("cop")
 except EOFError:
 #villager, or ran out of mafiosos to add
 pass
 with open("players") as playersfile:
 data.players = set(playersfile.read().strip().splitlines())
 saveData(data)
 exit()
 with open("gameData.txt") as datafile:
 data = SimpleNamespace(**eval(datafile.read().strip()))
 #2: Beginning of day nonzero
 if opener.startswith("Dawn of day"):
 data.requests.clear()
 data.selfvotes.clear()
 data.askers.clear()
 data.voted = False
 try:
 while True:
 nextline = input()
 victim = re.match("Last night, (.*) was killed. They were (?:a|the) (.*).", nextline)
 if victim:
 victim, role = victim.groups()
 #remove dead people from lists
 for datum in DATABASES:
 getattr(data, datum).discard(victim)
 if role == "cop" or role == "doctor":
 data.used_roles.add(role)
 continue
 investigated = re.match("Investigations showed that (.*) is (.*)-aligned.", nextline)
 if investigated:
 assert data.cop
 who = investigated.group(1)
 if investigated.group(2) == "mafia":
 data.guilty.add(who)
 data.unlikely.discard(who)
 else:
 data.targets.discard(who)
 data.herd.discard(who)
 data.innocent.add(who)
 data.unlikely.add(who)
 continue
 except EOFError:
 pass
 #3: We're being told some messages / news
 elif " says " in opener or " voted " in opener:
 message = opener
 acted = question = False
 try:
 while True:
 if " voted " in message:
 message = "<vote against>"
 speaker, subject = re.match("(.*) has voted to lynch (.*)", message).groups()
 target = None
 else:
 speaker, target, message, subject = \
 re.match("(.*) says \"(?:(.*), )?([^:\?]+)(?:[:\?]\s*(.*))?\"",
 message).groups()
 if speaker == MY_NAME:
 continue
 BAD_MESSAGES = ("<vote against>", "I think this player is mafia",
 "I investigated this player and found that they were mafia-aligned",
 "I think this player is suspicious")
 GOOD_MESSAGES = ("I think this player is the cop",
 "I think this player is the doctor",
 "I think this player is a normal villager",
 "I trust this player",
 "I investigated this player and found that they were village-aligned")
 OUTS = "I am the cop", "I am the doctor"
 LIES = ()
 for role in data.used_roles:
 LIES += LIESPERROLE[role]
 if message == "Yes" or message == "No":
 if question and not target:
 target = chooseSet(data.askers)
 if target in data.askers:
 BAD_MESSAGES += "Yes",
 GOOD_MESSAGES += "No",
 subject = data.askers[target]
 if message in LIES and speaker not in data.mafiosos:
 # What you just said is false, and I know it!
 data.unlikely.discard(speaker)
 data.targets.add(speaker)
 if subject and subject not in (data.unlikely.union(data.mafiosos)):
 data.targets.add(subject)
 elif message in BAD_MESSAGES:
 if speaker in data.guilty:
 #mafiosos rarely turn on eachother
 data.unlikely.add(subject)
 data.targets.discard(subject)
 elif speaker in data.unlikely:
 #believe the herd, especially people who we trust
 data.herd.add(subject)
 elif subject in data.unlikely:
 #how dare you speak against players likely to be village-aligned!
 data.targets.add(speaker)
 elif subject == MY_NAME or subject in data.mafiosos:
 #DON'T ATTACK ME (or my fellow mafiosos)
 data.targets.add(speaker)
 else:
 #believe the herd
 data.herd.add(subject)
 if not acted and message == "<vote against>":
 if subject == MY_NAME:
 data.selfvotes.add(speaker)
 if len(data.selfvotes) >= (len(data.players)-len(data.mafiosos)/3):
 if data.cop:
 print("say 2")
 #give a data point to prove it
 if random.random() > .5 and data.guilty:
 data.queued.append("say 14 %s" % chooseSet(data.guilty))
 elif data.innocent:
 data.queued.append("say 15 %s" % chooseSet(data.innocent))
 else:
 print("say 4") #Don't out myself if I'm the doctor
 # and just lie if I'm a mafioso
 acted = True
 else:
 data.selfvotes.discard(speaker)
 elif message in OUTS and data.mafiosos and speaker not in data.unlikely:
 data.targets.add(speaker) #Kill the fools who boast!
 elif message in GOOD_MESSAGES:
 chance = random.random() < .1 - (speaker in data.targets) / 20
 if speaker in data.guilty: #Mafia liars
 if subject not in data.unlikely:
 data.targets.add(subject)
 elif subject == MY_NAME and chance:
 if speaker in data.targets:data.targets.remove(speaker)
 data.unlikely.add(speaker)
 elif speaker in data.unlikely or chance:
 data.unlikely.add(subject)
 elif message == "Do you think this player is mafia":
 if subject == MY_NAME:
 data.targets.append(speaker)
 if target == MY_NAME or not target:
 if speaker in data.guilty:
 data.queued.append("say 14 %s %s" % (subject, speaker))
 elif speaker in data.innocent:
 data.queued.append("say 15 %s %s" % (subject, speaker))
 elif subject in data.targets or subject in data.herd:
 data.queued.append("say 1 %s" % (speaker))
 elif subject in data.unlikely:
 data.queued.append("say 0 %s" % (speaker))
 if data.cop:
 data.requests.add(subject)
 data.askers[speaker] = subject
 question = True
 elif target == MY_NAME and message == "Will you please use your power on this player tonight":
 data.requests.add(subject)
 message = input()
 except EOFError:
 pass
 for datum in DATABASES:
 if datum in ALLOW_SELF: continue
 getattr(data, datum).discard(MY_NAME)
 chance = random.random()
 if data.queued:
 print(data.queued.pop())
 elif chance < .1:
 target = chooseSet(data.targets or data.players)
 if target != MY_NAME:
 print("say 10 %s" % target)
 data.askers[MY_NAME] = target
 elif chance < .3 and data.targets:
 print("say 6 %s" % chooseSet(data.guilty or data.targets))
 elif chance < .5 and data.unlikely:
 print("say 5 %s" % chooseSet(data.innocent or data.unlikely))
 elif chance < .6 and not data.voted:
 target = chooseSet(data.guilty or data.targets or data.herd or data.players)
 if target not in data.mafiosos and target != MY_NAME:
 print("vote %s" % target)
 data.voted = True
 elif chance < .8:
 #do nothing
 pass
 elif chance < .9:
 #Confuse everybody
 print("say 1")
 data.queued.append("say 0")
 ######################
 #4: End of day
 elif "has killed" in opener:
 victim = re.match("The town has killed (.*)!", opener)
 if not victim:
 exit()
 victim = victim.group(1)
 #remove dead people from lists
 for datum in DATABASES:
 getattr(data, datum).discard(victim)
 role = input()
 role = re.match("They were (?:a|the) (.*)", role).group(1)
 if role == "cop" or role == "doctor":
 data.used_roles.add(role)
 #Misc: purge people from lists if too large
 for list in data.unlikely, data.targets, data.herd:
 while len(list) > len(data.players)/3:
 list.pop()
 elif opener == "The town opted to lynch no one today.":
 #Do nothing
 pass
 #5: Night
 elif "night" in opener:
 if not data.mafiosos and data.requests and random.random() > .5:
 print(chooseSet(data.requests))
 if data.doctor:
 print(chooseSet(data.unlikely or data.players))
 else:
 while True:
 try:
 target = (data.targets or data.herd).pop()
 except KeyError:
 target = chooseSet(data.players)
 if target in data.mafiosos or target == MY_NAME:
 continue
 print(target)
 break
 else:
 raise ValueError("Unknown message")
 saveData(data)

Fancy, long bunch of python code that I'm not going to explain (although it isn't golfed), other than that it keeps lists of "friends" and "enemies" that are originally populated based on chance and/or cop investigation. Warning: do not lie in the logician's presence.