# Each player keeps a record of what happened in their game. This # class holds that information and prints it in a nice way. from misc import * class Record: def __init__(self): self.records = [] # a list of day and night records for a player def __repr__(self): return self.records.__repr__() def new_record(self, day): if self.records != [] and self.records[-1].is_day() == day: raise ValueError, \ 'Tried to add two records of the same type in a row' if day: self.records.append(DayRecord()) else: # night self.records.append(NightRecord()) # Get most recently added DayRecord def today(self): if self.records == []: return None if self.records[-1].is_night(): raise ValueError, 'Tried to access "today" during nightime (dawn)' return self.records[-1] # Get most recently added NightRecord def tonight(self): if self.records == []: return None if self.records[-1].is_day(): raise ValueError, 'Tried to access "tonight" during daytime (dawn)' return self.records[-1] # Just get the most recent record regardles of day/night def recent(self): return self.records[-1] # displays most recent day/night def disp(self): if self.records != []: indented_table_begin() self.records[-1].disp() indented_table_end() # Abstract superclass for DayRecord and NightRecord class AnyRecord: # To be overloaded def __init__(self): # dict: peon_name -> peon_status self.peon_statuses = {} def is_day(self): raise NotImplementedError def is_night(self): return not self.is_day() def disp(self, verbose): raise NotImplementedError # Fine the way they are def day_or_night(self): return ('Night','Day')[self.is_day()] def __repr__(self): return self.day_or_night() class DayRecord(AnyRecord): def __init__(self): AnyRecord.__init__(self) self.votes = {} # dict: (alive) peon_name -> who_they_voted_for self.zombie_votes = {} # dict: necro_name -> # [zombie_names who voted like the necro] self.victim = '' # name of person hung; can also be SLEEP # Useful functions for distinguishing day records from night records def is_day(self): return True def is_night(self): return False def add_zombie_vote(self, necro_name, zombie_name): dict_add(self.zombie_votes, necro_name, zombie_name) def disp(self, verbose = True): # Affix verb to victim if self.victim == SLEEP: victim_str = 'Sleep prevails over bloodlust (so sad!)' else: victim_str = 'Townspeople hung ' + self.victim print "Day's Outcome: %s" % victim_str if not verbose: return # skip table print '

' print """ """ % COL_SPACER for voter, vote in self.votes.items(): print '' \ % (voter + COL_SPACER, vote) if voter in self.zombie_votes: for zombie in self.zombie_votes[voter]: print '' \ % zombie print '
Player:%s Voted for:
%s %s
' + \ '"assisted" by zombie %s
' class NightRecord(AnyRecord): def __init__(self): AnyRecord.__init__(self) self.pointed = {} # dict: (alive) peon_name -> who_they_pinted at self.mafia_votes = {} # dict: mafia_name -> who_they_want_to_kill self.mafia_victim = '' # poor sap targeted by mafia (can be None) self.mafia_succeed = False # Toggled True if they kill their victim self.medic_votes = {} # dict: medic_name -> who_they_tried_to_save self.necro_raises = {} # dict: necro_name -> (who_was_raised, success?) self.priest_exorcises = {} # priest_name -> (who_exorcise, success?) # Useful functions for distinguishing day records from night records def is_day(self): return False def is_night(self): return True # Takes: list of medics (names, and list of medic targets (also names) # (indices line up b/w the 2) # Sets: medic_votes: medic_name -> who_they_tried_to_save # (Basically combines two lists into a dictionary) def add_medic_votes(self, medics, medic_targets): if len(medics) != len(medic_targets): raise ValueError, '# of medics (%s) != # of medic targets (%s)' \ % (len(medics), len(medic_targets)) for i in range(len(medics)): self.medic_votes[medics[i]] = medic_targets[i] def disp(self, verbose = True): if self.mafia_victim == None: self.mafia_victim = NOBODY # -- Mafia Results -- if self.mafia_succeed: print 'Mafia killed:', else: print 'Mafia tried to kill:', print '%s
' % self.mafia_victim quick_table(self.mafia_votes, 'wanted to kill', verbose = verbose) # -- Medic Results -- print 'Medics:', # Did Medics save someone? if (not self.mafia_succeed) \ and (self.mafia_victim in self.medic_votes.values()): # Who saved him? (can be multiple medics) first_medic = True for medic_name, patient_name in self.medic_votes.items(): if patient_name == self.mafia_victim: if first_medic: first_medic = False else: print 'and', print medic_name, print 'saved %s from the mafia' % self.mafia_victim elif self.mafia_victim == NOBODY: print 'All quiet on the western front' else: print 'Failed to save %s' % self.mafia_victim print '
' quick_table(self.medic_votes, 'tried to save', verbose = verbose) # -- Necro Results -- print 'Necromancers: Animated %d zombies
' \ % count_successes(self.necro_raises) quick_table(self.necro_raises, 'animated', 'vainly chanted over', \ verbose = verbose) # -- Priest Results -- print 'Priests: Exorcised %d zombies
' \ % count_successes(self.priest_exorcises) quick_table(self.priest_exorcises, 'exorcised', \ 'inappropriately moistened', verbose = verbose) # Helper function for NightRecord.disp() # # Takes - dict: subject_name -> target_name # or: subject_name -> (target_name, success?) # - action: what the subjects did to the targets (on success) # - alt_action: same but on failure # - verbose: tables are only printed in verbose mode def quick_table(subj_target_dict, action, alt_action = None, verbose = True): if not verbose: return indented_table_begin(spacer = LIST_SPACER) for subj, poss_pair in subj_target_dict.items(): if alt_action == None: target = poss_pair success = True else: (target, success) = poss_pair print """ %s %s %s%s %s """ % (COL_SPACER, subj + COL_SPACER, \ (alt_action, action)[success], COL_SPACER, target) indented_table_end() # Takes - dict: subj_name -> (target_name, success?) def count_successes(subj_target_dict): return len([True for (target_name, success) in subj_target_dict.values() \ if success])