def main(self): self.num_players = 4 self.available_roles = roles.ROLES self.removed_roles = None self.game_over = False self.districts = DistrictDeck() self.initialize_players() self.starting_player = random.choice(self.players) self.start_game()
class Game(object): STARTING_GOLD = 2 STARTING_CARDS = 4 def main(self): self.num_players = 4 self.available_roles = roles.ROLES self.removed_roles = None self.game_over = False self.districts = DistrictDeck() self.initialize_players() self.starting_player = random.choice(self.players) self.start_game() def start_game(self): for player in self.players: player.gold += Game.STARTING_GOLD cards = self.districts.draw(Game.STARTING_CARDS) for card in cards: player.add_to_hand(card) while not self.game_over: self.game_loop() self.end_game() def game_loop(self): self.start_turn() self.do_drafting() self.do_player_turns() self.do_end_of_turn() def initialize_players(self): self.players = [UserPlayer()] self.players.extend([RandomPlayer() for _ in range(self.num_players - 1)]) for i, player in enumerate(self.players, 1): player.num = i last_player = self.players[0] for player in reversed(self.players): player.next_player = last_player last_player = player def do_drafting(self): self.roles, self.removed_roles = self.make_role_pack() self.update_board(None) current_player = self.starting_player self.role_players = dict() started = False while current_player != self.starting_player or not started: started = True self.draft_role(current_player) current_player = current_player.next_player def do_player_turns(self): for role in self.available_roles: self.update_board(None) self.send_message('Calling role {}', role) if role.name in self.role_players: current_player = self.role_players[role.name] if role == self.assassinated_role: # Silently skip this player's turn continue if role == self.thieved_role: self.send_message('{}, the Thief, steals the gold of {}', self.role_players['Thief'], current_player) self.role_players['Thief'].gold += current_player.gold current_player.gold = 0 if role.name == 'King': self.send_message( '{} is crowned King and is now starting player', current_player) self.starting_player = current_player self.do_turn(current_player) def do_end_of_turn(self): self.update_board(None) self.send_message('Turn over') if (self.assassinated_role and self.assassinated_role.name in self.role_players): self.send_message('{}, the {}, was assassinated this turn', self.role_players[self.assassinated_role.name], self.assassinated_role) if self.assassinated_role.name == 'King': king_player = self.role_players['King'] self.send_message('{} is heir to the assassinated king and ' 'is now starting player', king_player) self.starting_player = king_player def make_role_pack(self): roles = list(self.available_roles) random.shuffle(roles) roles = roles[1:] num_removed = max(6 - self.num_players, 0) for role in roles: if role.name == 'King': roles.remove(role) roles.append(role) return roles[num_removed:], roles[:num_removed] def draft_role(self, player): choice = player.pick_role(self.roles) player.role = self.roles.pop(choice) self.role_players[player.role.name] = player def do_turn(self, player): player.reset_powers() self.get_resource(player) played_district = False while not played_district or player.cards_with_unused_powers(): self.update_board(player) choice = player.choose_action(played_district) if choice == Player.CHOICE_PLAY_DISTRICT: played_district = self.may_play_district(player) elif choice == Player.CHOICE_END_TURN: break else: choice.power.used = choice.power(player, self) self.end_turn(player) def get_resource(self, player): self.update_board(player) choice = player.choose_resource() if choice == Player.CHOICE_GOLD: self.send_message('{} chose to take gold', player) NUM_GOLD = 2 player.gold += NUM_GOLD else: self.send_message('{} chose to take a card', player) NUM_CARDS_DRAW = 2 NUM_CARDS_KEEP = 1 if player.has_district('Observatory'): NUM_CARDS_DRAW += 1 if player.has_district('Library'): NUM_CARDS_KEEP += 1 cards = self.districts.draw(NUM_CARDS_DRAW) for _ in range(NUM_CARDS_KEEP): kept_card = player.choose_district(cards, True) cards.remove(kept_card) player.add_to_hand(kept_card) self.districts.put_on_bottom(cards) if player.role.name == 'Merchant': player.gold += 1 if player.role.name == 'Architect': cards = self.districts.draw(2) for card in cards: player.add_to_hand(card) def may_play_district(self, player): ALLOWED_TO_PLAY = 1 if player.role.name == 'Architect': ALLOWED_TO_PLAY += 2 played = 0 while played < ALLOWED_TO_PLAY: choice = player.choose_district_from_hand() if choice == Player.CHOICE_CANCEL: if played == 0: return False else: break elif choice == Player.CHOICE_NONE: break else: if player.can_play(choice): player.remove_from_hand(choice) player.gold -= choice.cost self.play_district(player, choice) played += 1 return True def play_district(self, player, district): player.add_to_city(district) if district.name == 'Haunted City': district.played_this_turn = True self.send_message('{} playing {}', player, district) self.update_board(player) if not self.game_over and player.finished_city(): self.send_message('Game will end at the end of this round') self.game_over = True player.first_to_finish = True def end_turn(self, player): if player.role.name == 'Warlord': used_extra_power = False while not used_extra_power: self.update_board(player) used_extra_power = roles.warlord_extra_power(player, self) def end_game(self): self.send_message('Game over') scores = list() for player in self.players: score = sum([card.cost for card in player.city]) if player.first_to_finish: score += 4 elif player.finished_city(): score += 2 if self.has_all_colors(player.city): score += 3 score += player.bonus_points() scores.append((score, player)) scores.sort(reverse=True) self.send_score_message(scores) def has_all_colors(self, city): NEEDED_COLORS = 5 districts = list(city) for district in city: if district.name == 'Haunted City' and not district.played_this_turn: districts.remove(district) NEEDED_COLORS -= 1 break return len(set([district.color for district in districts])) == NEEDED_COLORS def start_turn(self): self.assassinated_role = None self.thieved_role = None for player in self.players: player.role = None for district in player.city: if district.name == 'Haunted City': district.played_this_turn = False def update_board(self, current_player): for player in self.players: player.update_board(self.players, current_player, self.starting_player, self.removed_roles) def send_message(self, message, *args): for player in self.players: player.send_message(message, *args) def send_score_message(self, scores): self.send_message('Winner is {}!', scores[0][1]) self.send_message( '\n'.join(['Scores:'] + ['{}: '+ str(score[0]) for score in scores]), *[score[1] for score in scores])
class Game(object): STARTING_GOLD = 2 STARTING_CARDS = 4 def main(self): self.num_players = 4 self.available_roles = roles.ROLES self.removed_roles = None self.game_over = False self.districts = DistrictDeck() self.initialize_players() self.starting_player = random.choice(self.players) self.start_game() def start_game(self): for player in self.players: player.gold += Game.STARTING_GOLD cards = self.districts.draw(Game.STARTING_CARDS) for card in cards: player.add_to_hand(card) while not self.game_over: self.game_loop() self.end_game() def game_loop(self): self.start_turn() self.do_drafting() self.do_player_turns() self.do_end_of_turn() def initialize_players(self): self.players = [UserPlayer()] self.players.extend( [RandomPlayer() for _ in range(self.num_players - 1)]) for i, player in enumerate(self.players, 1): player.num = i last_player = self.players[0] for player in reversed(self.players): player.next_player = last_player last_player = player def do_drafting(self): self.roles, self.removed_roles = self.make_role_pack() self.update_board(None) current_player = self.starting_player self.role_players = dict() started = False while current_player != self.starting_player or not started: started = True self.draft_role(current_player) current_player = current_player.next_player def do_player_turns(self): for role in self.available_roles: self.update_board(None) self.send_message('Calling role {}', role) if role.name in self.role_players: current_player = self.role_players[role.name] if role == self.assassinated_role: # Silently skip this player's turn continue if role == self.thieved_role: self.send_message('{}, the Thief, steals the gold of {}', self.role_players['Thief'], current_player) self.role_players['Thief'].gold += current_player.gold current_player.gold = 0 if role.name == 'King': self.send_message( '{} is crowned King and is now starting player', current_player) self.starting_player = current_player self.do_turn(current_player) def do_end_of_turn(self): self.update_board(None) self.send_message('Turn over') if (self.assassinated_role and self.assassinated_role.name in self.role_players): self.send_message('{}, the {}, was assassinated this turn', self.role_players[self.assassinated_role.name], self.assassinated_role) if self.assassinated_role.name == 'King': king_player = self.role_players['King'] self.send_message( '{} is heir to the assassinated king and ' 'is now starting player', king_player) self.starting_player = king_player def make_role_pack(self): roles = list(self.available_roles) random.shuffle(roles) roles = roles[1:] num_removed = max(6 - self.num_players, 0) for role in roles: if role.name == 'King': roles.remove(role) roles.append(role) return roles[num_removed:], roles[:num_removed] def draft_role(self, player): choice = player.pick_role(self.roles) player.role = self.roles.pop(choice) self.role_players[player.role.name] = player def do_turn(self, player): player.reset_powers() self.get_resource(player) played_district = False while not played_district or player.cards_with_unused_powers(): self.update_board(player) choice = player.choose_action(played_district) if choice == Player.CHOICE_PLAY_DISTRICT: played_district = self.may_play_district(player) elif choice == Player.CHOICE_END_TURN: break else: choice.power.used = choice.power(player, self) self.end_turn(player) def get_resource(self, player): self.update_board(player) choice = player.choose_resource() if choice == Player.CHOICE_GOLD: self.send_message('{} chose to take gold', player) NUM_GOLD = 2 player.gold += NUM_GOLD else: self.send_message('{} chose to take a card', player) NUM_CARDS_DRAW = 2 NUM_CARDS_KEEP = 1 if player.has_district('Observatory'): NUM_CARDS_DRAW += 1 if player.has_district('Library'): NUM_CARDS_KEEP += 1 cards = self.districts.draw(NUM_CARDS_DRAW) for _ in range(NUM_CARDS_KEEP): kept_card = player.choose_district(cards, True) cards.remove(kept_card) player.add_to_hand(kept_card) self.districts.put_on_bottom(cards) if player.role.name == 'Merchant': player.gold += 1 if player.role.name == 'Architect': cards = self.districts.draw(2) for card in cards: player.add_to_hand(card) def may_play_district(self, player): ALLOWED_TO_PLAY = 1 if player.role.name == 'Architect': ALLOWED_TO_PLAY += 2 played = 0 while played < ALLOWED_TO_PLAY: choice = player.choose_district_from_hand() if choice == Player.CHOICE_CANCEL: if played == 0: return False else: break elif choice == Player.CHOICE_NONE: break else: if player.can_play(choice): player.remove_from_hand(choice) player.gold -= choice.cost self.play_district(player, choice) played += 1 return True def play_district(self, player, district): player.add_to_city(district) if district.name == 'Haunted City': district.played_this_turn = True self.send_message('{} playing {}', player, district) self.update_board(player) if not self.game_over and player.finished_city(): self.send_message('Game will end at the end of this round') self.game_over = True player.first_to_finish = True def end_turn(self, player): if player.role.name == 'Warlord': used_extra_power = False while not used_extra_power: self.update_board(player) used_extra_power = roles.warlord_extra_power(player, self) def end_game(self): self.send_message('Game over') scores = list() for player in self.players: score = sum([card.cost for card in player.city]) if player.first_to_finish: score += 4 elif player.finished_city(): score += 2 if self.has_all_colors(player.city): score += 3 score += player.bonus_points() scores.append((score, player)) scores.sort(reverse=True) self.send_score_message(scores) def has_all_colors(self, city): NEEDED_COLORS = 5 districts = list(city) for district in city: if district.name == 'Haunted City' and not district.played_this_turn: districts.remove(district) NEEDED_COLORS -= 1 break return len(set([district.color for district in districts])) == NEEDED_COLORS def start_turn(self): self.assassinated_role = None self.thieved_role = None for player in self.players: player.role = None for district in player.city: if district.name == 'Haunted City': district.played_this_turn = False def update_board(self, current_player): for player in self.players: player.update_board(self.players, current_player, self.starting_player, self.removed_roles) def send_message(self, message, *args): for player in self.players: player.send_message(message, *args) def send_score_message(self, scores): self.send_message('Winner is {}!', scores[0][1]) self.send_message( '\n'.join(['Scores:'] + ['{}: ' + str(score[0]) for score in scores]), *[score[1] for score in scores])