tim-the-enchanter/tim.py

220 lines
8.2 KiB
Python

import os
import readline
import sys
import colorama
import json
from colorama import Fore, Style
from models.default_model import DefaultModel
from models.data_model import DataModel
from game_evaluator import DeceptionGame, AvalonGame
def repl_report(report, top_k, namemap, ngood):
sort_order = sorted(
[(report[i]["side"].get(True, 0.0), i)
for i in range(len(report))],
reverse=True)
still_good = 0
for goodness, i in sort_order:
row = "%s: %2f%% Good %2f%% Evil" % (
namemap.get(i, "") + " (%s)" % str(i),
goodness * 100,
(1.0 - goodness) * 100)
if still_good < ngood:
print(Fore.CYAN + Style.BRIGHT + row)
else:
print(Fore.RED + Style.BRIGHT + row)
roles = sorted([(v, k) for k, v in report[i]["role"].iteritems()],
reverse=True)
row = " "
has_roles = True
for score, role in roles:
if role == "":
has_roles = False
break
row += "%2.1f%% %s " % (
score * 100, role)
if has_roles:
print(row)
still_good += 1
for prob, deal in top_k:
print prob
print deal
def display_statement(statement, namemap):
out = ""
out += Fore.MAGENTA + Style.BRIGHT
out += statement["type"].title()
out += Style.RESET_ALL + " -- "
for key in statement["print_order"]:
out += Fore.YELLOW
out += key.title() + ": "
out += Style.RESET_ALL
out += str(statement[key]).title() + " "
return out
def help():
print(Fore.GREEN + "Initial Commands:")
print("load <filename> -- Loads a savefile")
print("newgame -- Starts a new game")
print("\n")
print(Fore.GREEN + "Game Commands:")
print("save <filename> -- Saves a game to file")
print("ls -- Lists current assertions")
print("disb <index> -- Delete (disbelieve) an assertion")
print("name -- Name a player index for pretty printing")
print("side -- Assert that someone must be good or evil")
print("lady -- Assert that one player saw another and made a claim")
print("vote -- Assert a voted-on team and the votes"
" (whether it succeeded or not)")
print("switch -- Good and Evil Lancelots switch")
print("mission -- Assert the results of a team and a mission")
print("eval <repetitions> -- Quick eval, discounting special roles")
print("fulleval <repetitions> -- Eval, counting special roles")
print("report -- Show last report again")
def main():
colorama.init(autoreset=True)
readline.get_history_length()
print(Fore.GREEN + Style.BRIGHT + "Tim the Enchanter v1.0")
game = None
namemap = {}
while True:
try:
command_str = raw_input("%s> " % game)
command_list = command_str.strip().split(" ")
command = command_list[0]
if command == "quit" or command == "q" or command == "exit":
sys.exit(0)
if command == "help":
help()
continue
if game is None:
if command == "newgame":
nplayers = raw_input("How many players? ")
game = DeceptionGame(
AvalonGame(int(nplayers)), DataModel)
namemap = {}
elif command == "load":
if len(command_list) < 2:
print(Fore.RED + "Need an input file")
continue
inpath = os.path.expanduser(command_list[1])
with open(inpath, "r") as savefile:
observations = json.load(savefile)
metadata = observations[0]
data = observations[1:]
game = DeceptionGame(
AvalonGame(int(metadata["game_size"])),
DataModel)
namemap = metadata["player_names"]
game.load_save(data)
else:
print(Fore.RED + "Need to create a game")
continue
elif command == "ls":
for i, statement in enumerate(game.seen):
print "%d: %s" % (i, display_statement(statement, namemap))
continue
elif command == "vote":
proposer = int(raw_input("Proposer? ").strip())
input = raw_input("Team? ").strip()
team = [int(x) for x in input]
votes = [int(x) for x in raw_input("Votes? ").strip()]
round = int(raw_input("Round? ").strip())
voten = int(raw_input("Vote Number? ").strip())
fail_req = game.get_fail_req(round)
game.do_vote(team, votes, fail_req, round, voten, proposer)
game.trace = {}
continue
elif command == "mission":
team = [int(x) for x in raw_input("Team? ").strip()]
fails = int(raw_input("# of Fails? ").strip())
must = int(raw_input("Spys must fail? ").strip()) == 1
round = int(raw_input("Round? ").strip())
game.do_mission(team, fails, must, round)
game.trace = {}
continue
elif command == "lady" or command == "lol":
p1 = int(raw_input("ID For Lady? ").strip())
p2 = int(raw_input("ID For Target? ").strip())
claim = int(raw_input("Claim? ").strip()) == 1
round = int(raw_input("Round? ").strip()) == 1
game.player_sees_player_and_claims(p1, p2, claim, round)
game.trace = {}
continue
elif command == "side":
p1 = int(raw_input("ID For Assertion? ").strip())
claim = int(raw_input("Good? ").strip()) == 1
game.add_known_alliance(p1, claim)
game.trace = {}
continue
elif command == "switch":
r = int(raw_input("Starting in round?").strip())
game.switch_lancelots(r)
game.trace = {}
continue
elif command == "eval":
times = 200 / (game.n_players - 4) * 2
if len(command_list) > 1:
times = int(command_list[1])
game.eval(times, quick=True)
players, top_k = game.report()
repl_report(players, top_k, namemap, game.n_good)
elif command == "fulleval":
times = 200 / (game.n_players - 4) * 2
if len(command_list) > 1:
times = int(command_list[1])
game.eval(times)
players, top_k = game.report()
repl_report(players, top_k, namemap, game.n_good)
elif command == "report":
players, top_k = game.report()
repl_report(players, top_k, namemap, game.n_good)
elif command == "save":
if len(command_list) < 2:
print(Fore.RED + "Need an output file")
continue
metadata = [{
"game_size": game.n_players,
"player_names": namemap
}]
outpath = os.path.expanduser(command_list[1])
with open(outpath, "w") as savefile:
json.dump(metadata + game.seen, savefile, indent=2)
elif command == "name":
if len(command_list) < 3:
print(Fore.RED + "No args?")
continue
namemap[int(command_list[1])] = command_list[2]
elif command == "disb" or command == "disbelieve":
if len(command_list) < 2:
print(Fore.RED + "No args?")
continue
game.disbelieve(int(command_list[1]))
else:
print(Fore.RED + "Unknown command: %s" % command)
continue
except EOFError:
print "Canceled"
continue
except Exception, e:
print str(e)
continue
if __name__ == '__main__':
main()