Skip to content

Commit

Permalink
Fix gstats/rstats
Browse files Browse the repository at this point in the history
  • Loading branch information
skizzerz committed Dec 15, 2020
1 parent b5f8515 commit 4cf8171
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 37 deletions.
7 changes: 4 additions & 3 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@
"lover": ["lover", "lovers"],
"vg activated": ["vg activated", "vgs activated"],
"vg driven off": ["vg driven off", "vgs driven off"],
"entranced": ["entranced", "entranced"],
"****": "The following items are old roles that are no longer in use, but need to be here for legacy reasons",
"bureaucrat": ["bureaucrat", "bureaucrats"]
"entranced": ["entranced", "entranced"]
},
"_gamemodes": {
"*": "For assistance in configuring this section, please see https://werewolf.chat/Translation#Gamemodes",
Expand Down Expand Up @@ -1291,6 +1289,9 @@
"db_gstats_gm_p": "{0:bold}p: {1}",
"db_gstats_gm_all_total": "Total games: {0} | {1:join_simple}",
"db_gstats_gm_specific_total": "Total games ({0!mode:bold}): {1} | {2:join_simple}",
"db_gstats_nobody": "Nobody",
"db_gstats_no_team_wins": "No Team",
"db_gstats_everyone": "Everyone",
"db_role_stats_global": "{role!role:bold} | Team winners: {team} ({teamp:.0%}), Individual winners: {indiv} ({indivp:.0%}), Overall winners: {overall} ({overallp:.0%}), Total games: {total}.",
"db_role_stats_specific": "{role!role:bold} in {0!mode} | Team winners: {team} ({teamp:.0%}), Individual winners: {indiv} ({indivp:.0%}), Overall winners: {overall} ({overallp:.0%}), Total games: {total}.",
"db_rstats_none": "No stats for {0!role:bold}.",
Expand Down
26 changes: 16 additions & 10 deletions src/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def get_game_stats(mode, size):
conn = _conn()
c = conn.cursor()

if mode == "all":
if mode == "*":
c.execute("SELECT COUNT(1) FROM game WHERE gamesize = ?", (size,))
else:
c.execute("SELECT COUNT(1) FROM game WHERE gamemode = ? AND gamesize = ?", (mode, size))
Expand All @@ -340,7 +340,7 @@ def get_game_stats(mode, size):
if not total_games:
return messages["db_gstats_no_game"].format(size)

if mode == "all":
if mode == "*":
c.execute("""SELECT
winner AS team,
COUNT(1) AS games,
Expand Down Expand Up @@ -376,10 +376,16 @@ def get_game_stats(mode, size):

bits = []
for row in c:
winner = singular(row[0])
winner = LocalRole(winner).singular.title()
if not winner:
winner = botconfig.NICK.title()
if row[0] == "no_team_wins":
winner = messages["db_gstats_no_team_wins"]
elif not row[0]:
winner = messages["db_gstats_nobody"]
elif row[0] == "everyone":
winner = messages["db_gstats_everyone"]
else:
# FIXME: kill off singular() and convert the db to just store the role key directly instead of a plural
winner = LocalRole(singular(row[0])).singular.title()

bits.append(messages["db_gstats_win"].format(winner, row[1], row[1]/total_games))
bits.append(messages["db_gstats_total"].format(total_games))

Expand All @@ -389,18 +395,18 @@ def get_game_totals(mode):
conn = _conn()
c = conn.cursor()

if mode == "all":
if mode == "*":
c.execute("SELECT COUNT(1) FROM game")
else:
c.execute("SELECT COUNT(1) FROM game WHERE gamemode = ?", (mode,))

total_games = c.fetchone()[0]
if not total_games:
if mode == "all":
if mode == "*":
return messages["db_gstats_gm_none_all"]
return messages["db_gstats_gm_none"].format(mode)

if mode == "all":
if mode == "*":
c.execute("""SELECT
gamesize,
COUNT(1) AS games
Expand All @@ -419,7 +425,7 @@ def get_game_totals(mode):
for row in c:
totals.append(messages["db_gstats_gm_p"].format(row[0], row[1]))

if mode == "all":
if mode == "*":
return messages["db_gstats_gm_all_total"].format(total_games, totals)
return messages["db_gstats_gm_specific_total"].format(mode, total_games, totals)

Expand Down
12 changes: 10 additions & 2 deletions src/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,16 @@ def get_reveal_role(user):
else:
return "village member"

def match_role(var, role: str, remove_spaces: bool = False, allow_special: bool = True, scope: Optional[Iterable[str]] = None) -> Match[LocalRole]:
def match_role(var, role: str, remove_spaces: bool = False, allow_extra: bool = False, allow_special: bool = True, scope: Optional[Iterable[str]] = None) -> Match[LocalRole]:
""" Match a partial role or alias name into the internal role key.
:param var: Game state
:param role: Partial role to match on
:param remove_spaces: Whether or not to remove all spaces before matching.
This is meant for contexts where we truly cannot allow spaces somewhere; otherwise we should
prefer that the user matches including spaces where possible for friendlier-looking commands.
:param allow_extra: Whether to allow keys that are defined in the translation file but do not exist in the bot.
Typically these are roles that were previously removed.
:param allow_special: Whether to allow special keys (lover, vg activated, etc.).
If scope is set, this parameter is ignored.
:param scope: Limit matched roles to these explicitly passed-in roles (iterable of internal role names).
Expand All @@ -194,6 +196,8 @@ def match_role(var, role: str, remove_spaces: bool = False, allow_special: bool
filtered_matches = set()
if scope is not None:
allowed = set(scope)
elif allow_extra:
allowed = set(role_map.values()) | special_keys
else:
allowed = All.roles | special_keys

Expand All @@ -203,14 +207,16 @@ def match_role(var, role: str, remove_spaces: bool = False, allow_special: bool

return Match(filtered_matches)

def match_mode(var, mode: str, remove_spaces: bool = False, scope: Optional[Iterable[str]] = None) -> Match[LocalMode]:
def match_mode(var, mode: str, remove_spaces: bool = False, allow_extra: bool = False, scope: Optional[Iterable[str]] = None) -> Match[LocalMode]:
""" Match a partial game mode into the internal game mode key.
:param var: Game state
:param mode: Partial game mode to match on
:param remove_spaces: Whether or not to remove all spaces before matching.
This is meant for contexts where we truly cannot allow spaces somewhere; otherwise we should
prefer that the user matches including spaces where possible for friendlier-looking commands.
:param allow_extra: Whether to allow keys that are defined in the translation file but do not exist in the bot.
Typically these are game modes that were previously removed.
:param scope: Limit matched modes to these explicitly passed-in modes (iterable of internal mode names).
:return: Match object with all matches (see src.match.match_all)
"""
Expand All @@ -225,6 +231,8 @@ def match_mode(var, mode: str, remove_spaces: bool = False, scope: Optional[Iter
filtered_matches = set()
if scope is not None:
allowed = set(scope)
elif allow_extra:
allowed = set(mode_map.values())
else:
allowed = set(var.GAME_MODES)

Expand Down
40 changes: 18 additions & 22 deletions src/wolfgame.py
Original file line number Diff line number Diff line change
Expand Up @@ -3126,7 +3126,7 @@ def gamestats(var, wrapper, message):
if msg and not msg[0].isdigit():
gamemode = msg[0]
if gamemode != "*":
matches = match_mode(var, gamemode, remove_spaces=True)
matches = match_mode(var, gamemode, remove_spaces=True, allow_extra=True)
if matches:
gamemode = matches.get().key
elif len(matches) == 0:
Expand All @@ -3137,12 +3137,8 @@ def gamestats(var, wrapper, message):
return
msg.pop(0)

# Check for invalid input
if msg and msg[0].isdigit():
gamesize = int(msg[0])
if gamemode != "all" and not (var.GAME_MODES[gamemode][1] <= gamesize <= var.GAME_MODES[gamemode][2]):
wrapper.pm(messages["integer_range"].format(var.GAME_MODES[gamemode][1], var.GAME_MODES[gamemode][2]))
return

# List all games sizes and totals if no size is given
if not gamesize:
Expand Down Expand Up @@ -3200,9 +3196,9 @@ def player_stats(var, wrapper, message):
wrapper.pm(*totals, sep=", ")
else:
role = " ".join(params[1:])
matches = match_role(var, role)
matches = match_role(var, role, allow_extra=True)

if not matches:
if len(matches) == 0:
wrapper.send(messages["no_such_role"].format(role))
return
elif len(matches) > 1:
Expand All @@ -3221,7 +3217,6 @@ def my_stats(var, wrapper, message):
@command("rolestats", pm=True)
def role_stats(var, wrapper, message):
"""Gets the stats for a given role in a given gamemode or lists role totals across all games if no role is given."""
# NOTE: Need to dynamically translate roles and gamemodes
if (wrapper.public and var.LAST_RSTATS and var.RSTATS_RATE_LIMIT and
var.LAST_RSTATS + timedelta(seconds=var.RSTATS_RATE_LIMIT) > datetime.now()):
wrapper.pm(messages["command_ratelimited"])
Expand All @@ -3241,16 +3236,25 @@ def role_stats(var, wrapper, message):
wrapper.pm(*totals, sep=", ", first=first)
return

roles = match_role(var, message)
if params[-1] == "all" and not roles:
roles = match_role(var, " ".join(params[:-1]))
roles = match_role(var, message, allow_extra=True)
if params[-1] == "*" and not roles:
role = " ".join(params[:-1])
roles = match_role(var, role, allow_extra=True)
if not roles:
if len(roles) > 0:
wrapper.pm(messages["ambiguous_role"].format(roles))
else:
wrapper.pm(messages["no_such_role"].format(role))
return

if roles:
wrapper.pm(db.get_role_stats(roles.get().key))
return

gamemode = params[-1]
matches = match_mode(var, gamemode, remove_spaces=True)
if matches:
roles = match_role(var, " ".join(params[:-1]), allow_extra=True)
matches = match_mode(var, gamemode, remove_spaces=True, allow_extra=True)
if matches and roles:
gamemode = matches.get().key
else:
if len(roles) > 0:
Expand All @@ -3266,15 +3270,7 @@ def role_stats(var, wrapper, message):
wrapper.pm(*totals, sep=", ", first=first)
return

role = " ".join(params[:-1])
roles = match_role(var, role)
if not roles:
if len(roles) == 0:
wrapper.pm(messages["no_such_role"].format(role))
else:
wrapper.pm(messages["ambiguous_role"].format([r.singular for r in roles]))
return
wrapper.pm(db.get_role_stats(roles[0], gamemode))
wrapper.pm(db.get_role_stats(roles.get().key, gamemode))

@command("whoami", pm=True)
def whoami(var, wrapper, message):
Expand Down

0 comments on commit 4cf8171

Please sign in to comment.