From f2333f8186eb1e882f47f0538a5e671c417c3930 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 26 Apr 2021 18:53:35 +0100 Subject: [PATCH 01/21] Add show-match-scores command Prints ranking. league and match points for every match. Matches can be filtered to a single team. --- sr/comp/cli/command_line.py | 2 + sr/comp/cli/show_match_scores.py | 148 +++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 sr/comp/cli/show_match_scores.py diff --git a/sr/comp/cli/command_line.py b/sr/comp/cli/command_line.py index d607c58..450bfca 100644 --- a/sr/comp/cli/command_line.py +++ b/sr/comp/cli/command_line.py @@ -19,6 +19,7 @@ schedule_league, scorer, shift_matches, + show_match_scores, show_schedule, summary, top_match_points, @@ -60,6 +61,7 @@ def argument_parser() -> argparse.ArgumentParser: schedule_league.add_subparser(subparsers) scorer.add_subparser(subparsers) shift_matches.add_subparser(subparsers) + show_match_scores.add_subparser(subparsers) show_schedule.add_subparser(subparsers) summary.add_subparser(subparsers) top_match_points.add_subparser(subparsers) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py new file mode 100644 index 0000000..cc0cad2 --- /dev/null +++ b/sr/comp/cli/show_match_scores.py @@ -0,0 +1,148 @@ +__description__ = "Show the game and league points achieved for each match" + +from typing import Dict, List, Union, NamedTuple + + +DISPLAY_NAME_WIDTH = 18 +ARENA_NAME_WIDTH = 12 + + +class MatchCorner(NamedTuple): + tla: str + ranking: Union[int, str] # to allow "???" to be used for unknown scores + game: Union[int, str] + league: Union[int, str] + + +class MatchResult(NamedTuple): + num: int + arena: str + display_name: str + corners: Dict[int, MatchCorner] + + +def collect_match_info(comp, match) -> MatchResult: + from sr.comp.match_period import MatchType + from sr.comp.scores import degroup + + if match.type == MatchType.knockout: + score_data = comp.scores.knockout + elif match.type == MatchType.tiebreaker: + score_data = comp.scores.tiebreaker + elif match.type == MatchType.league: + score_data = comp.scores.league + + match_id = (match.arena, match.num) + + if match_id in score_data.game_points: + league_points = score_data.ranked_points[match_id] + game_points = score_data.game_points[match_id] + ranking = degroup(score_data.game_positions[match_id]) + else: + league_points = {} + game_points = {} + ranking = {} + for team in match.teams: + league_points[team] = "???" + game_points[team] = "???" + ranking[team] = "???" + + corner_data: Dict[int, MatchCorner] = {} + + for corner, team in enumerate(match.teams): + match_id = (match.arena, match.num) + + corner_data[corner] = MatchCorner( + tla=team, + ranking=ranking[team], + game=game_points[team], + league=league_points[team], + ) + + return MatchResult( + num=match.num, + arena=match.arena, + display_name=match.display_name, + corners=corner_data, + ) + + +def print_heading(num_corners, name_width, arena_name_width): + print(f" {' ':{name_width + 3 + arena_name_width}} |", end='') + for idx in range(num_corners): + print(f"{f'Zone {idx}':^22}|", end='') + print() + print(f" {'Display Name':^{name_width}} | {'Arena':^{arena_name_width}} |", end='') + for idx in range(num_corners): + print(f" {'TLA':<4}|{'Rank':>4}|{'Game':>4}|{'League':>6}|", end='') + print() + + +def print_match(match: MatchResult, name_width, arena_name_width): + print( + f" {match.display_name:^{name_width}} | {match.arena:^{arena_name_width}} |", + end='', + ) + for corner in match.corners.values(): + print( + f" {corner.tla:<4}|{corner.ranking:>3} |{corner.game:>3} |{corner.league:>5} |", + end='', + ) + print() + + +def command(settings): + import os.path + + from sr.comp.comp import SRComp + + comp = SRComp(os.path.realpath(settings.compstate)) + + match_results: List[MatchResult] = [] + + filter_tla = settings.tla + + for slots in comp.schedule.matches: + match_results.extend( + collect_match_info(comp, match) + for match in slots.values() + if not filter_tla or filter_tla in match.teams + ) + + if len(match_results) == 0: + print("Not matches found, TLA may be invalid") + return + + # Calculate "Display Name" and "Arena" column widths + display_name_width = 12 # start with width of label + for match in match_results: + display_name_width = max(display_name_width, len(match.display_name)) + + arena_name_width = 5 # start with width of label + for match in match_results: + arena_name_width = max(arena_name_width, len(match.arena)) + + # TODO hide arena column w/ single arena? + + print_heading(len(match_results[0].corners), display_name_width, arena_name_width) + + for match in match_results: + print_match(match, display_name_width, arena_name_width) + + +def add_subparser(subparsers): + parser = subparsers.add_parser( + 'show-match-scores', + help=__description__, + description=__description__, + ) + parser.add_argument( + 'compstate', + help="competition state repo", + ) + parser.add_argument( + 'tla', + nargs='?', + help="filter to matches containing this TLA", + ) + parser.set_defaults(func=command) From 9f4f5755af05970511b3b1f1c4250bed570c17cf Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 11:26:15 +0100 Subject: [PATCH 02/21] Make filter condition more clear --- sr/comp/cli/show_match_scores.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index cc0cad2..efc8ddc 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -101,12 +101,13 @@ def command(settings): match_results: List[MatchResult] = [] filter_tla = settings.tla + skip_filter = not filter_tla for slots in comp.schedule.matches: match_results.extend( collect_match_info(comp, match) for match in slots.values() - if not filter_tla or filter_tla in match.teams + if filter_tla in match.teams or skip_filter ) if len(match_results) == 0: From ce5c5480d169a08d787c688105d44689cacf7acd Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 11:27:30 +0100 Subject: [PATCH 03/21] Merge column width calculation loops --- sr/comp/cli/show_match_scores.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index efc8ddc..8eb8326 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -116,11 +116,9 @@ def command(settings): # Calculate "Display Name" and "Arena" column widths display_name_width = 12 # start with width of label - for match in match_results: - display_name_width = max(display_name_width, len(match.display_name)) - arena_name_width = 5 # start with width of label for match in match_results: + display_name_width = max(display_name_width, len(match.display_name)) arena_name_width = max(arena_name_width, len(match.arena)) # TODO hide arena column w/ single arena? From 3439ad5a4f3a4bfce61fe6bfba6918e8e3d0b8b1 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 11:49:06 +0100 Subject: [PATCH 04/21] Use better method for calculating number of corners --- sr/comp/cli/show_match_scores.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 8eb8326..640b027 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -123,7 +123,9 @@ def command(settings): # TODO hide arena column w/ single arena? - print_heading(len(match_results[0].corners), display_name_width, arena_name_width) + num_teams_per_arena = getattr(comp, 'num_teams_per_arena', len(comp.corners)) + + print_heading(num_teams_per_arena, display_name_width, arena_name_width) for match in match_results: print_match(match, display_name_width, arena_name_width) From e8c5ba79aad8affc03aeac6deba8341afcfc38b7 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 12:17:22 +0100 Subject: [PATCH 05/21] Imporve line formatting --- sr/comp/cli/show_match_scores.py | 36 +++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 640b027..fe00857 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -67,27 +67,35 @@ def collect_match_info(comp, match) -> MatchResult: ) +def print_col(text): + print(text, end='|') + + def print_heading(num_corners, name_width, arena_name_width): - print(f" {' ':{name_width + 3 + arena_name_width}} |", end='') + print_col("".center(name_width + 1 + arena_name_width)) for idx in range(num_corners): - print(f"{f'Zone {idx}':^22}|", end='') + print_col(f"Zone {idx}".center(22)) print() - print(f" {'Display Name':^{name_width}} | {'Arena':^{arena_name_width}} |", end='') + + print_col("Display Name".center(name_width)) + print_col("Arena".center(arena_name_width)) for idx in range(num_corners): - print(f" {'TLA':<4}|{'Rank':>4}|{'Game':>4}|{'League':>6}|", end='') + print_col("TLA".center(5)) + print_col("Rank") + print_col("Game") + print_col("League") print() def print_match(match: MatchResult, name_width, arena_name_width): - print( - f" {match.display_name:^{name_width}} | {match.arena:^{arena_name_width}} |", - end='', - ) + print_col(match.display_name.center(name_width)) + print_col(match.arena.center(arena_name_width)) + for corner in match.corners.values(): - print( - f" {corner.tla:<4}|{corner.ranking:>3} |{corner.game:>3} |{corner.league:>5} |", - end='', - ) + print_col(f" {corner.tla:<4}") + print_col(f"{corner.ranking:>3} ") + print_col(f"{corner.game:>3} ") + print_col(f"{corner.league:>5} ") print() @@ -121,6 +129,10 @@ def command(settings): display_name_width = max(display_name_width, len(match.display_name)) arena_name_width = max(arena_name_width, len(match.arena)) + # Add some padding + display_name_width += 2 + arena_name_width += 2 + # TODO hide arena column w/ single arena? num_teams_per_arena = getattr(comp, 'num_teams_per_arena', len(comp.corners)) From 1c7a01f31cda276494b07f71fc66ad59ac267b9a Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 12:27:53 +0100 Subject: [PATCH 06/21] Use srcomp types --- sr/comp/cli/show_match_scores.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index fe00857..ae671ac 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -1,6 +1,9 @@ __description__ = "Show the game and league points achieved for each match" from typing import Dict, List, Union, NamedTuple +from sr.comp.types import TLA, GamePoints, ArenaName, MatchNumber +from sr.comp.scores import LeaguePosition +from sr.comp.ranker import LeaguePoints DISPLAY_NAME_WIDTH = 18 @@ -8,15 +11,15 @@ class MatchCorner(NamedTuple): - tla: str - ranking: Union[int, str] # to allow "???" to be used for unknown scores - game: Union[int, str] - league: Union[int, str] + tla: TLA + ranking: Union[LeaguePosition, str] # to allow "???" to be used for unknown scores + game: Union[GamePoints, str] + league: Union[LeaguePoints, str] class MatchResult(NamedTuple): - num: int - arena: str + num: MatchNumber + arena: ArenaName display_name: str corners: Dict[int, MatchCorner] From e0ce60b9bacea353d60e0b6a94ffba7e40697ab4 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 12:43:20 +0100 Subject: [PATCH 07/21] Remove failing import --- sr/comp/cli/show_match_scores.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index ae671ac..4f9d72f 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -3,7 +3,6 @@ from typing import Dict, List, Union, NamedTuple from sr.comp.types import TLA, GamePoints, ArenaName, MatchNumber from sr.comp.scores import LeaguePosition -from sr.comp.ranker import LeaguePoints DISPLAY_NAME_WIDTH = 18 @@ -14,7 +13,7 @@ class MatchCorner(NamedTuple): tla: TLA ranking: Union[LeaguePosition, str] # to allow "???" to be used for unknown scores game: Union[GamePoints, str] - league: Union[LeaguePoints, str] + league: Union[int, str] class MatchResult(NamedTuple): From 5de19d09aa8b14490065499c8c725b5c1f9f9453 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 12:43:40 +0100 Subject: [PATCH 08/21] Remove unused constants --- sr/comp/cli/show_match_scores.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 4f9d72f..858ffd1 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -5,10 +5,6 @@ from sr.comp.scores import LeaguePosition -DISPLAY_NAME_WIDTH = 18 -ARENA_NAME_WIDTH = 12 - - class MatchCorner(NamedTuple): tla: TLA ranking: Union[LeaguePosition, str] # to allow "???" to be used for unknown scores From 7a11ba100512ca49c920641564839472e7535c4e Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 27 Apr 2021 12:56:36 +0100 Subject: [PATCH 09/21] Add handling for empty corners --- sr/comp/cli/show_match_scores.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 858ffd1..b363bb7 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -50,12 +50,20 @@ def collect_match_info(comp, match) -> MatchResult: for corner, team in enumerate(match.teams): match_id = (match.arena, match.num) - corner_data[corner] = MatchCorner( - tla=team, - ranking=ranking[team], - game=game_points[team], - league=league_points[team], - ) + if team: # corner occupied + corner_data[corner] = MatchCorner( + tla=team, + ranking=ranking[team], + game=game_points[team], + league=league_points[team], + ) + else: + corner_data[corner] = MatchCorner( + tla='', + ranking='', + game='', + league='', + ) return MatchResult( num=match.num, From 4d06c95714e3be4a7efd2793c44921a385549aac Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 20:04:18 +0100 Subject: [PATCH 10/21] Correct typo --- sr/comp/cli/show_match_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index b363bb7..d1b70cb 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -125,7 +125,7 @@ def command(settings): ) if len(match_results) == 0: - print("Not matches found, TLA may be invalid") + print("No matches found, TLA may be invalid") return # Calculate "Display Name" and "Arena" column widths From 8afa4be9a494538e31c431f114bbca95b2888a2b Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 20:58:49 +0100 Subject: [PATCH 11/21] is None --- sr/comp/cli/show_match_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index d1b70cb..6740e06 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -115,7 +115,7 @@ def command(settings): match_results: List[MatchResult] = [] filter_tla = settings.tla - skip_filter = not filter_tla + skip_filter = filter_tla is None for slots in comp.schedule.matches: match_results.extend( From 07f25920e39c35e81e73ed614482369d3ec9662a Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 20:59:16 +0100 Subject: [PATCH 12/21] Remove unneeded getattr --- sr/comp/cli/show_match_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 6740e06..6e828c6 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -141,7 +141,7 @@ def command(settings): # TODO hide arena column w/ single arena? - num_teams_per_arena = getattr(comp, 'num_teams_per_arena', len(comp.corners)) + num_teams_per_arena = comp.num_teams_per_arena print_heading(num_teams_per_arena, display_name_width, arena_name_width) From 14e0af3d04629926b57f751aedcc75eb88e8cddf Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 21:06:59 +0100 Subject: [PATCH 13/21] Use Optional types instead of Union --- sr/comp/cli/show_match_scores.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 6e828c6..6a72e96 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -1,15 +1,15 @@ __description__ = "Show the game and league points achieved for each match" -from typing import Dict, List, Union, NamedTuple +from typing import Dict, List, Optional, NamedTuple from sr.comp.types import TLA, GamePoints, ArenaName, MatchNumber from sr.comp.scores import LeaguePosition class MatchCorner(NamedTuple): tla: TLA - ranking: Union[LeaguePosition, str] # to allow "???" to be used for unknown scores - game: Union[GamePoints, str] - league: Union[int, str] + ranking: Optional[LeaguePosition] + game: Optional[GamePoints] + league: Optional[int] class MatchResult(NamedTuple): @@ -41,9 +41,9 @@ def collect_match_info(comp, match) -> MatchResult: game_points = {} ranking = {} for team in match.teams: - league_points[team] = "???" - game_points[team] = "???" - ranking[team] = "???" + league_points[team] = None + game_points[team] = None + ranking[team] = None corner_data: Dict[int, MatchCorner] = {} @@ -97,11 +97,11 @@ def print_match(match: MatchResult, name_width, arena_name_width): print_col(match.display_name.center(name_width)) print_col(match.arena.center(arena_name_width)) - for corner in match.corners.values(): - print_col(f" {corner.tla:<4}") - print_col(f"{corner.ranking:>3} ") - print_col(f"{corner.game:>3} ") - print_col(f"{corner.league:>5} ") + for tla, ranking, game, league in match.corners.values(): + print_col(f" {tla:<4}") + print_col(f"{'??' if ranking is None else ranking:>3} ") + print_col(f"{'???' if game is None else game:>3} ") + print_col(f"{'??' if league is None else league:>5} ") print() From be28fd738e27e17895f666f5fd564a03352ca573 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 21:31:44 +0100 Subject: [PATCH 14/21] Solve linting and typing errors --- sr/comp/cli/show_match_scores.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 6a72e96..6089475 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -1,8 +1,9 @@ -__description__ = "Show the game and league points achieved for each match" +from typing import Dict, List, NamedTuple, Optional -from typing import Dict, List, Optional, NamedTuple -from sr.comp.types import TLA, GamePoints, ArenaName, MatchNumber from sr.comp.scores import LeaguePosition +from sr.comp.types import ArenaName, GamePoints, MatchNumber, TLA + +__description__ = "Show the game and league points achieved for each match" class MatchCorner(NamedTuple): @@ -19,7 +20,7 @@ class MatchResult(NamedTuple): corners: Dict[int, MatchCorner] -def collect_match_info(comp, match) -> MatchResult: +def collect_match_info(comp, match): from sr.comp.match_period import MatchType from sr.comp.scores import degroup @@ -74,7 +75,7 @@ def collect_match_info(comp, match) -> MatchResult: def print_col(text): - print(text, end='|') + print(text, end='|') def print_heading(num_corners, name_width, arena_name_width): @@ -85,7 +86,7 @@ def print_heading(num_corners, name_width, arena_name_width): print_col("Display Name".center(name_width)) print_col("Arena".center(arena_name_width)) - for idx in range(num_corners): + for _ in range(num_corners): print_col("TLA".center(5)) print_col("Rank") print_col("Game") @@ -93,7 +94,7 @@ def print_heading(num_corners, name_width, arena_name_width): print() -def print_match(match: MatchResult, name_width, arena_name_width): +def print_match(match: MatchResult, name_width: int, arena_name_width: int) -> None: print_col(match.display_name.center(name_width)) print_col(match.arena.center(arena_name_width)) From 8bde289db696a2afd6ca97141f3feecf352ec890 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 23:42:19 +0100 Subject: [PATCH 15/21] Use tabulate for table display --- sr/comp/cli/show_match_scores.py | 68 ++++++++++++++------------------ 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 6089475..8921bea 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -74,41 +74,35 @@ def collect_match_info(comp, match): ) -def print_col(text): - print(text, end='|') +def generate_displayed_headings(num_corners: int) -> List[str]: + displayed_heading = ["Display Name", "Arena"] - -def print_heading(num_corners, name_width, arena_name_width): - print_col("".center(name_width + 1 + arena_name_width)) for idx in range(num_corners): - print_col(f"Zone {idx}".center(22)) - print() + displayed_heading.append(f"TLA {idx}") + displayed_heading.append("Rank") + displayed_heading.append("Game") + displayed_heading.append("League") - print_col("Display Name".center(name_width)) - print_col("Arena".center(arena_name_width)) - for _ in range(num_corners): - print_col("TLA".center(5)) - print_col("Rank") - print_col("Game") - print_col("League") - print() + return displayed_heading -def print_match(match: MatchResult, name_width: int, arena_name_width: int) -> None: - print_col(match.display_name.center(name_width)) - print_col(match.arena.center(arena_name_width)) +def generate_displayed_match(match: MatchResult) -> List[str]: + displayed_match: List[str] = [match.display_name, match.arena] for tla, ranking, game, league in match.corners.values(): - print_col(f" {tla:<4}") - print_col(f"{'??' if ranking is None else ranking:>3} ") - print_col(f"{'???' if game is None else game:>3} ") - print_col(f"{'??' if league is None else league:>5} ") - print() + displayed_match.append(tla) + displayed_match.append("??" if ranking is None else str(ranking)) + displayed_match.append("???" if game is None else str(game)) + displayed_match.append("??" if league is None else str(league)) + + return displayed_match def command(settings): import os.path + from tabulate import tabulate + from sr.comp.comp import SRComp comp = SRComp(os.path.realpath(settings.compstate)) @@ -129,25 +123,23 @@ def command(settings): print("No matches found, TLA may be invalid") return - # Calculate "Display Name" and "Arena" column widths - display_name_width = 12 # start with width of label - arena_name_width = 5 # start with width of label - for match in match_results: - display_name_width = max(display_name_width, len(match.display_name)) - arena_name_width = max(arena_name_width, len(match.arena)) - - # Add some padding - display_name_width += 2 - arena_name_width += 2 - # TODO hide arena column w/ single arena? num_teams_per_arena = comp.num_teams_per_arena - print_heading(num_teams_per_arena, display_name_width, arena_name_width) - - for match in match_results: - print_match(match, display_name_width, arena_name_width) + displayed_matches = [ + generate_displayed_match(match) + for match in match_results + ] + + print(tabulate( + displayed_matches, + headers=generate_displayed_headings(num_teams_per_arena), + tablefmt='pretty', + colalign=( + ('center', 'center') + ('center', 'right', 'right', 'right') * num_teams_per_arena + ), + )) def add_subparser(subparsers): From 52931ce15f79b651ad4ad36c8261ce46b1422713 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Mon, 3 May 2021 23:51:08 +0100 Subject: [PATCH 16/21] Make the table more compact The table now wraps corners at 2, displaying them on the following line. With dummy-comp thins produces a table width of 100. --- sr/comp/cli/show_match_scores.py | 56 ++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 8921bea..a9c78a8 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -4,6 +4,7 @@ from sr.comp.types import ArenaName, GamePoints, MatchNumber, TLA __description__ = "Show the game and league points achieved for each match" +DISPLAYED_ZONES = 2 class MatchCorner(NamedTuple): @@ -75,10 +76,11 @@ def collect_match_info(comp, match): def generate_displayed_headings(num_corners: int) -> List[str]: - displayed_heading = ["Display Name", "Arena"] + displayed_heading = ["Match"] - for idx in range(num_corners): - displayed_heading.append(f"TLA {idx}") + for _ in range(num_corners): + displayed_heading.append("Zone") + displayed_heading.append("TLA") displayed_heading.append("Rank") displayed_heading.append("Game") displayed_heading.append("League") @@ -86,14 +88,34 @@ def generate_displayed_headings(num_corners: int) -> List[str]: return displayed_heading -def generate_displayed_match(match: MatchResult) -> List[str]: - displayed_match: List[str] = [match.display_name, match.arena] +def generate_displayed_match(match: MatchResult, num_corners: int) -> List[List[str]]: + displayed_match = [] + displayed_corners = [] - for tla, ranking, game, league in match.corners.values(): - displayed_match.append(tla) - displayed_match.append("??" if ranking is None else str(ranking)) - displayed_match.append("???" if game is None else str(game)) - displayed_match.append("??" if league is None else str(league)) + for zone, (tla, ranking, game, league) in match.corners.items(): + displayed_corner: List[str] = [] + + displayed_corner.append(str(zone)) + displayed_corner.append(tla) + displayed_corner.append("??" if ranking is None else str(ranking)) + displayed_corner.append("??" if game is None else str(game)) + displayed_corner.append("??" if league is None else str(league)) + + displayed_corners.append(displayed_corner) + + for corner in range(0, num_corners, DISPLAYED_ZONES): + if corner == 0: + match_row = [f"{match.display_name} in {match.arena}"] + else: + match_row = [""] + + for idx in range(DISPLAYED_ZONES): + try: + match_row.extend(displayed_corners[corner + idx]) + except IndexError: + match_row.extend(['', '', '', '']) + + displayed_match.append(match_row) return displayed_match @@ -123,21 +145,19 @@ def command(settings): print("No matches found, TLA may be invalid") return - # TODO hide arena column w/ single arena? - num_teams_per_arena = comp.num_teams_per_arena - displayed_matches = [ - generate_displayed_match(match) - for match in match_results - ] + displayed_matches: List[List[str]] = [] + + for match in match_results: + displayed_matches.extend(generate_displayed_match(match, num_teams_per_arena)) print(tabulate( displayed_matches, - headers=generate_displayed_headings(num_teams_per_arena), + headers=generate_displayed_headings(DISPLAYED_ZONES), tablefmt='pretty', colalign=( - ('center', 'center') + ('center', 'right', 'right', 'right') * num_teams_per_arena + ('center',) + ('right', 'center', 'right', 'right', 'right') * DISPLAYED_ZONES ), )) From fbbb3bc3ab162348dccde8f45478d1d6c3847bad Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 4 May 2021 12:41:14 +0100 Subject: [PATCH 17/21] Add option to limit output to a number of recent matches --- sr/comp/cli/show_match_scores.py | 37 ++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index a9c78a8..7c0ecc7 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -75,6 +75,17 @@ def collect_match_info(comp, match): ) +def match_index(matches, match_num): + "Returns the index of the first slot that contains the given match number" + for idx, slots in enumerate(matches): + for match in slots.values(): + if match.num == match_num: + return idx + + # if no match is found use the last one + return idx + + def generate_displayed_headings(num_corners: int) -> List[str]: displayed_heading = ["Match"] @@ -134,7 +145,19 @@ def command(settings): filter_tla = settings.tla skip_filter = filter_tla is None - for slots in comp.schedule.matches: + if not settings.all and skip_filter: + # get the index of the last scored match + end_match = match_index( + comp.schedule.matches, + comp.scores.last_scored_match, + ) + 1 # include last scored match in results + scan_matches = comp.schedule.matches[ + max(0, end_match-int(settings.limit)):end_match + ] + else: + scan_matches = comp.schedule.matches + + for slots in scan_matches: match_results.extend( collect_match_info(comp, match) for match in slots.values() @@ -175,6 +198,16 @@ def add_subparser(subparsers): parser.add_argument( 'tla', nargs='?', - help="filter to matches containing this TLA", + help="filter to matches containing this TLA (ignores --limit)", + ) + parser.add_argument( + '--all', + action='store_true', + help="show all matches (overrides --limit)", + ) + parser.add_argument( + '--limit', + default=15, + help="how many recently scored matches to show (default: %(default)s)", ) parser.set_defaults(func=command) From 46cc13d3bbfae2c964ae450dcc11373c53085cbb Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 4 May 2021 12:58:49 +0100 Subject: [PATCH 18/21] Add some comments --- sr/comp/cli/show_match_scores.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index 7c0ecc7..a79af1b 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -114,7 +114,10 @@ def generate_displayed_match(match: MatchResult, num_corners: int) -> List[List[ displayed_corners.append(displayed_corner) + # wrap the number of zones to the DISPLAYED_ZONES constant for corner in range(0, num_corners, DISPLAYED_ZONES): + # first row displays the match and arena information, + # any extra rows leave this field blank if corner == 0: match_row = [f"{match.display_name} in {match.arena}"] else: @@ -124,6 +127,7 @@ def generate_displayed_match(match: MatchResult, num_corners: int) -> List[List[ try: match_row.extend(displayed_corners[corner + idx]) except IndexError: + # pad the number of corners out to a multiple of DISPLAYED_ZONES match_row.extend(['', '', '', '']) displayed_match.append(match_row) From b5d4c8d35d4b54f4112cf34e33bce3f80ad2676b Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 4 May 2021 12:58:58 +0100 Subject: [PATCH 19/21] Linting --- sr/comp/cli/show_match_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index a79af1b..ce066f5 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -156,7 +156,7 @@ def command(settings): comp.scores.last_scored_match, ) + 1 # include last scored match in results scan_matches = comp.schedule.matches[ - max(0, end_match-int(settings.limit)):end_match + max(0, end_match - int(settings.limit)):end_match ] else: scan_matches = comp.schedule.matches From e0a900a0aa3a4d5db9791bafe02334bf57082d37 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 4 May 2021 13:21:10 +0100 Subject: [PATCH 20/21] Add typing --- sr/comp/cli/show_match_scores.py | 45 +++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index ce066f5..b420abd 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -1,6 +1,8 @@ -from typing import Dict, List, NamedTuple, Optional +from typing import Dict, List, Mapping, NamedTuple, Optional -from sr.comp.scores import LeaguePosition +from sr.comp.comp import SRComp +from sr.comp.match_period import Match, MatchSlot +from sr.comp.scores import BaseScores, LeaguePosition from sr.comp.types import ArenaName, GamePoints, MatchNumber, TLA __description__ = "Show the game and league points achieved for each match" @@ -8,7 +10,7 @@ class MatchCorner(NamedTuple): - tla: TLA + tla: Optional[TLA] ranking: Optional[LeaguePosition] game: Optional[GamePoints] league: Optional[int] @@ -21,10 +23,15 @@ class MatchResult(NamedTuple): corners: Dict[int, MatchCorner] -def collect_match_info(comp, match): +def collect_match_info(comp: SRComp, match: Match) -> MatchResult: from sr.comp.match_period import MatchType from sr.comp.scores import degroup + score_data: BaseScores + league_points: Mapping[TLA, Optional[int]] + game_points: Mapping[TLA, Optional[GamePoints]] + ranking: Mapping[TLA, Optional[LeaguePosition]] + if match.type == MatchType.knockout: score_data = comp.scores.knockout elif match.type == MatchType.tiebreaker: @@ -43,9 +50,10 @@ def collect_match_info(comp, match): game_points = {} ranking = {} for team in match.teams: - league_points[team] = None - game_points[team] = None - ranking[team] = None + if team is not None: + league_points[team] = None + game_points[team] = None + ranking[team] = None corner_data: Dict[int, MatchCorner] = {} @@ -61,10 +69,10 @@ def collect_match_info(comp, match): ) else: corner_data[corner] = MatchCorner( - tla='', - ranking='', - game='', - league='', + tla=None, + ranking=None, + game=None, + league=None, ) return MatchResult( @@ -75,7 +83,7 @@ def collect_match_info(comp, match): ) -def match_index(matches, match_num): +def match_index(matches: List[MatchSlot], match_num: int) -> int: "Returns the index of the first slot that contains the given match number" for idx, slots in enumerate(matches): for match in slots.values(): @@ -107,10 +115,13 @@ def generate_displayed_match(match: MatchResult, num_corners: int) -> List[List[ displayed_corner: List[str] = [] displayed_corner.append(str(zone)) - displayed_corner.append(tla) - displayed_corner.append("??" if ranking is None else str(ranking)) - displayed_corner.append("??" if game is None else str(game)) - displayed_corner.append("??" if league is None else str(league)) + if tla is not None: + displayed_corner.append(tla) + displayed_corner.append("??" if ranking is None else str(ranking)) + displayed_corner.append("??" if game is None else str(game)) + displayed_corner.append("??" if league is None else str(league)) + else: + displayed_corner.extend(['', '', '', '']) displayed_corners.append(displayed_corner) @@ -140,8 +151,6 @@ def command(settings): from tabulate import tabulate - from sr.comp.comp import SRComp - comp = SRComp(os.path.realpath(settings.compstate)) match_results: List[MatchResult] = [] From c682c2e8111c45c054293601026fbdfc04e13f04 Mon Sep 17 00:00:00 2001 From: WillB97 Date: Tue, 4 May 2021 13:59:29 +0100 Subject: [PATCH 21/21] Validate TLA --- sr/comp/cli/show_match_scores.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sr/comp/cli/show_match_scores.py b/sr/comp/cli/show_match_scores.py index b420abd..977495d 100644 --- a/sr/comp/cli/show_match_scores.py +++ b/sr/comp/cli/show_match_scores.py @@ -156,7 +156,14 @@ def command(settings): match_results: List[MatchResult] = [] filter_tla = settings.tla - skip_filter = filter_tla is None + skip_filter = True + + if filter_tla is not None: + skip_filter = False + # validate TLA exists + if filter_tla not in comp.teams.keys(): + print('TLA not found') + return if not settings.all and skip_filter: # get the index of the last scored match @@ -178,7 +185,7 @@ def command(settings): ) if len(match_results) == 0: - print("No matches found, TLA may be invalid") + print("No matches found for current filters") return num_teams_per_arena = comp.num_teams_per_arena