save/load and initial merlin detection

This commit is contained in:
Barak Michener 2013-07-30 20:14:21 -04:00
parent 32c040f2c2
commit da4cfc8213
3 changed files with 543 additions and 33 deletions

297
games/field1.gm Normal file
View file

@ -0,0 +1,297 @@
[
{
"player_names": {},
"game_size": 7
},
{
"votes": [
1,
0,
0,
0,
0,
0,
0
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 1,
"team": [
1,
2
]
},
{
"votes": [
1,
0,
0,
1,
0,
1,
1
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 1,
"team": [
3,
6
]
},
{
"fails": 0,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
3,
6
],
"must fail": false,
"round": 1
},
{
"votes": [
1,
1,
0,
1,
1,
0,
1
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 2,
"team": [
3,
4,
6
]
},
{
"fails": 0,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
3,
4,
6
],
"must fail": false,
"round": 2
},
{
"p2": 6,
"is good": false,
"p1": 1,
"type": "lady",
"print_order": [
"p1",
"p2",
"is good"
]
},
{
"votes": [
0,
0,
0,
1,
1,
1,
0
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 3,
"team": [
3,
4,
5
]
},
{
"votes": [
0,
0,
0,
0,
0,
0,
1
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 3,
"team": [
2,
5,
6
]
},
{
"votes": [
1,
1,
1,
0,
1,
0,
0
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 1,
"round": 3,
"team": [
0,
3,
4
]
},
{
"fails": 1,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
0,
3,
4
],
"must fail": true,
"round": 3
},
{
"p2": 3,
"is good": true,
"p1": 6,
"type": "lady",
"print_order": [
"p1",
"p2",
"is good"
]
},
{
"votes": [
1,
1,
0,
0,
0,
0,
0
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 2,
"round": 4,
"team": [
0,
1,
2,
3
]
},
{
"votes": [
1,
0,
1,
1,
0,
0,
1
],
"print_order": [
"team",
"votes",
"round"
],
"type": "vote",
"fails required": 2,
"round": 4,
"team": [
2,
3,
4,
5
]
},
{
"fails": 1,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
2,
3,
4,
5
],
"must fail": true,
"round": 4
},
{
"is good": true,
"player": 6,
"print_order": [
"player",
"is good"
],
"type": "known_side"
}
]

157
games/test.gm Normal file
View file

@ -0,0 +1,157 @@
[
{
"player_names": {},
"game_size": 5
},
{
"fails required": 1,
"votes": [
0,
1,
1,
0,
1
],
"print_order": [
"team",
"votes",
"round"
],
"team": [
1,
2
],
"type": "vote",
"round": 1
},
{
"fails": 0,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
1,
2
],
"must fail": false,
"round": 1
},
{
"fails required": 1,
"votes": [
1,
1,
1,
0,
1
],
"print_order": [
"team",
"votes",
"round"
],
"team": [
0,
1,
2
],
"type": "vote",
"round": 2
},
{
"fails": 1,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
0,
1,
2
],
"must fail": false,
"round": 2
},
{
"fails required": 1,
"votes": [
0,
0,
1,
1,
1
],
"print_order": [
"team",
"votes",
"round"
],
"team": [
3,
4
],
"type": "vote",
"round": 3
},
{
"fails": 0,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
3,
4
],
"must fail": false,
"round": 3
},
{
"fails required": 1,
"votes": [
0,
0,
1,
1,
1
],
"print_order": [
"team",
"votes",
"round"
],
"team": [
3,
4
],
"type": "vote",
"round": 4
},
{
"fails": 1,
"type": "mission",
"print_order": [
"team",
"fails",
"must fail",
"round"
],
"team": [
0,
3,
4
],
"must fail": false,
"round": 4
}
]

122
tim.py
View file

@ -2,10 +2,12 @@ import itertools
from collections import defaultdict as dd from collections import defaultdict as dd
import pprint import pprint
import progressbar import progressbar
import os
import readline import readline
import random import random
import sys import sys
import colorama import colorama
import json
from colorama import Fore, Style from colorama import Fore, Style
@ -61,7 +63,7 @@ class DeceptionGame(object):
def player_is_good(self, deal, player): def player_is_good(self, deal, player):
return deal[player][1] return deal[player][1]
def player_is_role(self, deal, player): def player_role(self, deal, player):
return deal[player][0] return deal[player][0]
def add_known_alliance(self, player_id, is_good): def add_known_alliance(self, player_id, is_good):
@ -85,7 +87,7 @@ class DeceptionGame(object):
transaction = [] transaction = []
def obs(deal): def obs(deal):
if self.player_is_role(deal, player_id) == role_str: if self.player_role(deal, player_id) == role_str:
return True return True
else: else:
return None return None
@ -120,8 +122,6 @@ class DeceptionGame(object):
return True return True
transaction.append(obs) transaction.append(obs)
self.observations.append(transaction) self.observations.append(transaction)
self.seen.append(
["Lady:", p1, "says", p2, "is", "Good" if claim else "Evil"])
self.seen.append({"type": "lady", self.seen.append({"type": "lady",
"p1": p1, "p1": p1,
"p2": p2, "p2": p2,
@ -170,7 +170,7 @@ class DeceptionGame(object):
"round"]}) "round"]})
self.tid += 1 self.tid += 1
def do_vote(self, team, votes, r): def do_vote(self, team, votes, fail_req, r):
transaction = [] transaction = []
rnd = r - 1 rnd = r - 1
@ -183,7 +183,9 @@ class DeceptionGame(object):
if player in team: if player in team:
continue continue
elif self.player_is_good(deal, player): elif self.player_is_good(deal, player):
if n_spies > 0: if n_spies > fail_req - 1:
if self.player_role(deal, player) == "Merlin":
continue
if vote == 1: if vote == 1:
if self.ignorance_on_round[rnd].rand(): if self.ignorance_on_round[rnd].rand():
continue continue
@ -196,7 +198,7 @@ class DeceptionGame(object):
else: else:
return False return False
else: else:
if n_spies == 0: if n_spies < fail_req:
if vote == 1: if vote == 1:
if self.ignorance_on_round[rnd].rand(): if self.ignorance_on_round[rnd].rand():
continue continue
@ -216,12 +218,40 @@ class DeceptionGame(object):
"team": team, "team": team,
"votes": votes, "votes": votes,
"round": r, "round": r,
"fails required": fail_req,
"print_order": ["team", "votes", "round"]}) "print_order": ["team", "votes", "round"]})
self.tid += 1 self.tid += 1
def eval(self, length=10): def load_save(self, input_list):
for statement in input_list:
type = statement["type"]
if type == "vote":
self.do_vote(statement["team"],
statement["votes"],
statement["fails required"],
statement["round"])
elif type == "mission":
self.do_mission(statement["team"],
statement["fails"],
statement["must fail"],
statement["round"])
elif type == "lady":
self.player_sees_player_and_claims(statement["p1"],
statement["p2"],
statement["is good"])
elif type == "known_side":
self.add_known_alliance(statement["player"],
statement["is good"])
elif type == "known_role":
self.add_known_role(statement["player"],
statement["role"])
def eval(self, length=10, with_merlin=False):
random.seed() random.seed()
deck = self.all_permutations[:] if not with_merlin:
deck = self.all_permutations[:]
else:
deck = list(itertools.permutations(AvalonGame(self.n_players)))
new_deck = [] new_deck = []
trace = [] trace = []
progress = progressbar.ProgressBar( progress = progressbar.ProgressBar(
@ -321,6 +351,14 @@ def repl_report(report, namemap, ngood):
print(Fore.CYAN + Style.BRIGHT + row) print(Fore.CYAN + Style.BRIGHT + row)
else: else:
print(Fore.RED + Style.BRIGHT + row) print(Fore.RED + Style.BRIGHT + row)
roles = sorted([(v, k) for k, v in report[i]["role"].iteritems()],
reverse=True)
row = " "
for score, role in roles:
row += "%2.1f%% %s " % (
score * 100, role)
print(row)
still_good += 1 still_good += 1
@ -339,7 +377,7 @@ def display_statement(statement, namemap):
def main(): def main():
colorama.init(autoreset=True) colorama.init(autoreset=True)
print(Fore.GREEN + Style.BRIGHT + "Welcome to Tim the Enchanter v1.0") print(Fore.GREEN + Style.BRIGHT + "Tim the Enchanter v1.0")
game = None game = None
namemap = {} namemap = {}
@ -351,26 +389,27 @@ def main():
command = command_list[0] command = command_list[0]
if command == "quit" or command == "q" or command == "exit": if command == "quit" or command == "q" or command == "exit":
sys.exit(0) sys.exit(0)
if (command != "newgame" and command != "testgame") \ if game is None:
and game is None: if command == "newgame":
print(Fore.RED + "Need to create a game") nplayers = raw_input("How many players? ")
continue game = DeceptionGame(ResistanceGame(int(nplayers)))
elif command == "newgame": namemap = {}
nplayers = raw_input("How many players? ") elif command == "load":
game = DeceptionGame(ResistanceGame(int(nplayers))) if len(command_list) < 2:
namemap = {} print(Fore.RED + "Need an input file")
continue continue
elif command == "testgame": inpath = os.path.expanduser(command_list[1])
game = DeceptionGame(ResistanceGame(5)) with open(inpath, "r") as savefile:
game.do_vote([1, 2], [0, 1, 1, 0, 1], 1) observations = json.load(savefile)
game.do_mission([1, 2], 0, False, 1) metadata = observations[0]
game.do_vote([0, 1, 2], [1, 1, 1, 0, 1], 2) data = observations[1:]
game.do_mission([0, 1, 2], 1, False, 2)
game.do_vote([3, 4], [0, 0, 1, 1, 1], 3) game = DeceptionGame(
game.do_mission([3, 4], 0, False, 3) ResistanceGame(int(metadata["game_size"])))
game.do_vote([3, 4], [0, 0, 1, 1, 1], 4) namemap = metadata["player_names"]
game.do_mission([0, 3, 4], 1, False, 4) game.load_save(data)
namemap = {} else:
print(Fore.RED + "Need to create a game")
continue continue
elif command == "ls": elif command == "ls":
for i, statement in enumerate(game.seen): for i, statement in enumerate(game.seen):
@ -381,7 +420,8 @@ def main():
team = [int(x) for x in input] team = [int(x) for x in input]
votes = [int(x) for x in raw_input("Votes? ").strip()] votes = [int(x) for x in raw_input("Votes? ").strip()]
round = int(raw_input("Round? ").strip()) round = int(raw_input("Round? ").strip())
game.do_vote(team, votes, round) fail_req = int(raw_input("# Fails Required? ").strip())
game.do_vote(team, votes, fail_req, round)
game.trace = [] game.trace = []
continue continue
@ -414,8 +454,24 @@ def main():
if len(command_list) > 1: if len(command_list) > 1:
times = int(command_list[1]) times = int(command_list[1])
game.eval(times) game.eval(times)
elif command == "merlineval":
times = 200 / (game.n_players - 4) * 2
if len(command_list) > 1:
times = int(command_list[1])
game.eval(times, with_merlin=True)
elif command == "report": elif command == "report":
repl_report(game.report(), namemap, game.n_good) repl_report(game.report(), 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": elif command == "name":
if len(command_list) < 3: if len(command_list) < 3:
print(Fore.RED + "No args?") print(Fore.RED + "No args?")
@ -429,8 +485,8 @@ def main():
else: else:
print(Fore.RED + "Unknown command: %s" % command) print(Fore.RED + "Unknown command: %s" % command)
continue continue
except Exception: except Exception, e:
print "\n" print str(e)
continue continue