def evaluate_game(room_id): n_alive_civilians = Player.num_alive_players(room_id, role=Role.CIVILIAN.name) if n_alive_civilians == 1: summary = generate_summary(room_id) clear_game(room_id) return [ GameState(Status.NON_CIVILIAN_WIN, room_id=room_id), GameState(Status.SUMMARY, data=summary), ] n_alive_players = Player.num_alive_players(room_id) if n_alive_civilians == n_alive_players: summary = generate_summary(room_id) clear_game(room_id) return [ GameState(Status.CIVILIAN_WIN, room_id=room_id), GameState(Status.SUMMARY, data=summary), ] alive_player_ids = Player.alive_player_ids(room_id) playing_order = decide_playing_order(alive_player_ids) return [GameState(Status.PLAYING_ORDER, playing_order, room_id=room_id)]
def test_get(): user_id = 1 room_id = 1 Player.insert(Player(user_id, room_id, Role.CIVILIAN.name)) player = Player.get(user_id) assert isinstance(player, Player) assert player.user_id == user_id assert player.room_id == room_id assert player.role == Role.CIVILIAN.name assert player.alive assert not player.guessing
def test_eliminate_invalid_scenario(room_id, user_id, expected_status): PlayingRole.insert(PlayingRole(2, Role.MR_WHITE.name)) Player.insert(Player(5, 2, Role.MR_WHITE.name)) kill_player(2) game_states = eliminate_player(room_id, user_id) assert len(game_states) == 1 game_state = game_states[0] assert game_state.status is expected_status PlayingRole.delete(2) Player.delete(2)
def complete_poll(room_id): tally, total_votes = count_vote(room_id) data = {"tally": tally} if total_votes == 0: terminate_poll(room_id) return [GameState(Status.NO_VOTES_SUBMITTED, data)] alive_player_ids = Player.alive_player_ids(room_id) data["players"] = alive_player_ids if total_votes < len(alive_player_ids) // 2 + 1: terminate_poll(room_id) return [GameState(Status.NOT_ENOUGH_VOTES, data)] max_votes = max(tally.values()) voted_players = [ voted_player for voted_player, votes in tally.items() if votes == max_votes ] if len(voted_players) > 1: terminate_poll(room_id) return [GameState(Status.MULTIPLE_PLAYERS_VOTED, data)] data["player"] = voted_players[0] terminate_poll(room_id) return [GameState(Status.POLL_DECIDED, data)]
def generate_summary(room_id): players = Player.get_all(room_id) civilians = [] undercovers = [] mr_whites = [] for player in players: if player.role == Role.CIVILIAN.name: civilians.append({ "user_id": player.user_id, "alive": player.alive }) elif player.role == Role.UNDERCOVER.name: undercovers.append({ "user_id": player.user_id, "alive": player.alive }) elif player.role == Role.MR_WHITE.name: mr_whites.append({ "user_id": player.user_id, "alive": player.alive }) return { "civilian_word": PlayingRole.get_word(room_id, Role.CIVILIAN).word, "undercover_word": PlayingRole.get_word(room_id, Role.UNDERCOVER).word, "civilians": civilians, "undercovers": undercovers, "mr_whites": mr_whites, }
def test_evaluate_game(killed_user_ids, expected_status, session): room_id = 1 for user_id in killed_user_ids: kill_player(user_id) game_states = evaluate_game(room_id) assert game_states[0].status is expected_status if game_states[0].status is not Status.PLAYING_ORDER: assert game_states[0].data is None else: new_playing_order = game_states[0].data["playing_order"] assert isinstance(new_playing_order, list) assert len(new_playing_order) == Player.num_alive_players(room_id) print(f"the new playing order is: {new_playing_order}") remaining_role = (session.query(PlayingRole).filter_by( room_id=room_id).first()) remaining_player = (session.query(Player).filter_by( room_id=room_id).first()) if game_states[0].status is not Status.PLAYING_ORDER: assert remaining_role is None assert remaining_player is None else: assert remaining_role is not None assert remaining_player is not None
def guess_word(user_id, word): player = Player.get(user_id) if player is None or not player.guessing: return [GameState(Status.NOT_IN_GUESSING_TURN)] civilian_word = PlayingRole.get_word(player.room_id, Role.CIVILIAN).word word = re.sub("[^a-z0-9]", "", word.lower()) civilian_word = re.sub("[^a-z0-9]", "", civilian_word.lower()) if Levenshtein.distance(word, civilian_word) <= 1: clear_game(player.room_id) return [GameState(Status.MR_WHITE_WIN, room_id=player.room_id)] Player.update(user_id, guessing=False) return evaluate_game(player.room_id)
def decide_vote_states(room_id): tally, total_votes = count_vote(room_id) num_alive_players = Player.num_alive_players(room_id) poll = Poll.get(room_id) data = {"msg_id": poll.msg_id, "tally": tally} if total_votes == num_alive_players: return [GameState(Status.TOTAL_VOTES_REACHED, data)] return [GameState(Status.VOTE_SUCCESS, data)]
def wrapper(room_id, user_id, *args, **kwargs): player = Player.get(user_id) data = {"player": user_id} if player is None or player.room_id != room_id: return [GameState(Status.PLAYER_NOT_FOUND, data)] if not player.alive: return [GameState(Status.PLAYER_ALREADY_KILLED, data)] return func(room_id, user_id, *args, **kwargs)
def test_alive_player_ids(): room_id = 1 user_ids = [1, 2, 3, 4] status = [True, True, False, True] roles = [ Role.CIVILIAN.name, Role.CIVILIAN.name, Role.MR_WHITE.name, Role.UNDERCOVER.name, ] for user_id, alive, role in zip(user_ids, status, roles): player = Player(user_id=user_id, alive=alive, role=role, room_id=room_id) Player.insert(player) alive_players_ids = Player.alive_player_ids(room_id) alive_civilians_ids = Player.alive_player_ids(room_id, role=Role.CIVILIAN.name) alive_undercover_ids = Player.alive_player_ids( room_id, role=Role.UNDERCOVER.name) alive_mr_white_ids = Player.alive_player_ids(room_id, role=Role.MR_WHITE.name) assert alive_players_ids == [1, 2, 4] assert alive_civilians_ids == [1, 2] assert alive_undercover_ids == [4] assert alive_mr_white_ids == []
def test_num_alive_players(): room_id = 1 user_ids = [1, 2, 3, 4] status = [True, True, False, True] roles = [ Role.CIVILIAN.name, Role.CIVILIAN.name, Role.MR_WHITE.name, Role.UNDERCOVER.name, ] for user_id, alive, role in zip(user_ids, status, roles): player = Player(user_id=user_id, alive=alive, role=role, room_id=room_id) Player.insert(player) n_alive_players = Player.num_alive_players(room_id) n_alive_civilians = Player.num_alive_players(room_id, role=Role.CIVILIAN.name) n_alive_undercover = Player.num_alive_players( room_id, role=Role.UNDERCOVER.name) n_alive_mr_white = Player.num_alive_players(room_id, role=Role.MR_WHITE.name) assert n_alive_players == 3 assert n_alive_civilians == 2 assert n_alive_undercover == 1 assert n_alive_mr_white == 0
def test_insert_player(session): playing_role = PlayingRole(1, Role.CIVILIAN.name, "civilian_word") civilian = Player( user_id=1, room_id=playing_role.room_id, role=playing_role.role, ) Player.insert(civilian) players = session.query(Player).filter_by(user_id=1).all() assert len(players) == 1 player = players[0] assert player.user_id == 1 assert player.alive assert not player.guessing assert player.role == playing_role.role assert player.room_id == playing_role.room_id assert player.playing_role.word == playing_role.word
def test_delete(session): user_ids = [1, 2, 3] room_ids = [1, 1, 2] for user_id, room_id in zip(user_ids, room_ids): player = Player(user_id=user_id, room_id=room_id, role=Role.CIVILIAN.name) Player.insert(player) to_be_deleted_room_id = 1 intact_room_id = 2 Player.delete(to_be_deleted_room_id) should_be_none = (session.query(Player).filter_by( room_id=to_be_deleted_room_id).first()) should_not_none = (session.query(Player).filter_by( room_id=intact_room_id).first()) assert should_be_none is None assert should_not_none is not None
def assign_role( room_id, user_ids, civilian_word, undercover_word, role_proportion ): num_civilians, num_undercovers, num_mr_whites = role_proportion random.shuffle(user_ids) user_words = {} mr_whites = set() for user_id in user_ids: if len(user_words) < num_civilians: user_words[user_id] = {"word": civilian_word} Player.insert(Player(user_id, room_id, Role.CIVILIAN.name)) elif len(user_words) < num_civilians + num_undercovers: user_words[user_id] = {"word": undercover_word} Player.insert(Player(user_id, room_id, Role.UNDERCOVER.name)) else: user_words[user_id] = {"word": MR_WHITE_WORD} Player.insert(Player(user_id, room_id, Role.MR_WHITE.name)) mr_whites.add(user_id) return user_words, mr_whites
def eliminate_player(room_id, user_id): kill_player(user_id) killed_player = Player.get(user_id) data = {"player": killed_player.user_id, "role": killed_player.role} game_states = [] if killed_player.role == Role.CIVILIAN.name: game_states.append(GameState(Status.CIVILIAN_ELIMINATED, data)) game_states += evaluate_game(room_id) elif killed_player.role == Role.UNDERCOVER.name: game_states.append(GameState(Status.UNDERCOVER_ELIMINATED, data)) game_states += evaluate_game(room_id) elif killed_player.role == Role.MR_WHITE.name: game_states.append(GameState(Status.MR_WHITE_ELIMINATED, data)) game_states.append(GameState(Status.ASK_GUESSED_WORD)) return game_states
def test_insert_duplicate_player(): civilian = Player( user_id=1, room_id=1, role=Role.CIVILIAN.name, ) Player.insert(civilian) with pytest.raises(Exception): undercover = Player( user_id=1, room_id=2, role=Role.UNDERCOVER.name, ) Player.insert(undercover)
def test_update(): user_id = 1 player = Player(user_id=user_id, room_id=1, role=Role.CIVILIAN.name) Player.insert(player) updated_room_id = 2 updated_role = Role.MR_WHITE.name updated_alive = False updated_guessing = True updated_attrs = { "room_id": updated_room_id, "role": updated_role, "alive": updated_alive, "guessing": updated_guessing, } Player.update(user_id, **updated_attrs) updated_player = Player.get(user_id) assert updated_player.room_id == updated_room_id assert updated_player.role == updated_role assert not updated_player.alive assert updated_player.guessing
def kill_player(user_id): player = Player.get(user_id) updated_attrs = {"alive": False} if player.role == Role.MR_WHITE.name: updated_attrs["guessing"] = True Player.update(user_id, **updated_attrs)
def test_get_non_existing_player(): # no players added previously in `populate_db()` user_id = 1 assert Player.get(user_id) is None
def test_kill_player(user_id, expected_guessing): kill_player(user_id) killed_player = Player.get(user_id) assert not killed_player.alive assert killed_player.guessing is expected_guessing
def populate_db(): PlayingRole.insert(PlayingRole(1, Role.CIVILIAN.name, "civilian_word")) PlayingRole.insert( PlayingRole(1, Role.UNDERCOVER.name, "undercover_word")) PlayingRole.insert(PlayingRole(1, Role.MR_WHITE.name)) Player.insert(Player(1, 1, Role.CIVILIAN.name)) Player.insert(Player(2, 1, Role.CIVILIAN.name)) Player.insert(Player(3, 1, Role.UNDERCOVER.name)) Player.insert(Player(4, 1, Role.MR_WHITE.name)) yield PlayingRole.delete(1) Player.delete(1)
def clear_game(room_id): Player.delete(room_id) PlayingRole.delete(room_id) Vote.delete_all(room_id) Poll.delete(room_id)
def wrapper(room_id, user_ids, *args, **kwargs): playing_users = Player.filter_exists(user_ids) if len(playing_users) > 0: data = {"playing_users": playing_users} return [GameState(Status.PLAYING_USER_FOUND, data)] return func(room_id, user_ids, *args, **kwargs)
def test_update_non_existing_player(): # no players added previously in `populate_db()` user_id = 1 with pytest.raises(Exception): Player.update(user_id, alive=False)
def start_poll(room_id, user_id, msg_id): # user_id used inside decorator alive_player_ids = Player.alive_player_ids(room_id) new_poll = Poll(room_id, msg_id) Poll.add(new_poll) data = {"players": alive_player_ids} return [GameState(Status.POLL_STARTED, data)]