From a0c52a56fcc5d160142359b93f6dc8c3cdf7bfdf Mon Sep 17 00:00:00 2001 From: Christian Wolf Date: Mon, 20 Nov 2023 10:22:07 +0100 Subject: [PATCH] Started to work towards new group management --- src/solo_turnier/worker.py | 115 ++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/src/solo_turnier/worker.py b/src/solo_turnier/worker.py index bee9d46..fc94abe 100644 --- a/src/solo_turnier/worker.py +++ b/src/solo_turnier/worker.py @@ -382,6 +382,7 @@ class Worker: "Slowfox", "Quickstep", ] + self._groupParser = solo_turnier.group.GroupParser() def collectAllData(self, htmlResultsFileNames: list[str]) -> types.State3: resultExtractor = ResultExtractor() @@ -393,9 +394,18 @@ class Worker: def combineData(self, importedData: types.State3): self.l.info("Starting to build data sets.") - groups = self._extractGroups(importedData) + + self.l.debug("Getting per participant groups") + groupMapping = self._getGroupMapping(importedData) + self.l.log(5, "ID-to-group mapping of the parsed data: %s", str(groupMapping)) + + # groups = self._extractGroups(importedData) + groups = self._extractGroupsFromGroupMapping(groupMapping) self.l.debug("Found groups in the dataset: %s", groups) + invertedGroupMapping = self._invertGroupMapping(groupMapping, groups) + self.l.log(5, "Inverted group maping: %s", invertedGroupMapping) + totalResult = {} for group in groups: @@ -451,6 +461,109 @@ class Worker: groups = groupParser.getGroupsAsSortedList(groupSet) return groups + def _getGroupMapping( + self, importedData: types.State3 + ) -> dict[int, solo_turnier.group.Group | None]: + groupParser = solo_turnier.group.GroupParser() + + def _getBestGroupGuess(groups, id): + counts = {} + grNones = 0 + for gr in set(groups): + length = len(list(filter(lambda x: x == gr, groups))) + if isinstance(gr, tuple) or gr is None: + grNones = grNones + length + else: + counts[gr] = length + counts[None] = grNones + candidates = list(counts.keys()) + + def ccomp(i1): + return counts[i1] + + candidates.sort(key=ccomp, reverse=True) + + if len(candidates) == 1: + self.l.warning("Unrequired group guessing started.") + return candidates[0] + if len(candidates) == 0: + self.l.error("Problem during the group guessing triggered.") + return None + + if counts[candidates[0]] > counts[candidates[1]]: + if candidates[0] is None: + self.l.error( + "Majority of guessed groups is ambigous. Guessing failed for id %d. Falling back to second best guess.", + id, + ) + return candidates[1] + + self.l.info("Using best fit %s for guessed group.", candidates[0]) + return candidates[0] + + self.l.warning("Group guessing failed.") + return None + + groupsPerId = {} + for tup in importedData.htmlResults.results: + competitionGroup = groupParser.parseClass(tup[0]) + fixture = importedData.htmlResults.tabges.get(tup, (None, None, None)) + id = int(tup[3]) + if fixture[2] is not None: + group = groupParser.parseClass(fixture[2]) + else: + containedGroups = competitionGroup.getContainedGroups() + if len(containedGroups) > 1: + self.l.error( + "The group for participant %d is ambiguous in (%s %s %s).", + id, + tup[0], + tup[1], + tup[2], + ) + group = containedGroups + else: + group = competitionGroup + + knownGroups = groupsPerId.get(id, []) + if group is not None: + knownGroups.append(group) + groupsPerId[id] = knownGroups + + ret = {} + for id in groupsPerId.keys(): + groupCandidates = groupsPerId[id] + groupSet = set(groupCandidates) + + if len(groupSet) == 1: + ret[id] = groupSet.pop() + elif len(groupSet) > 1: + self.l.warning( + "Multiple groups for id %d found: %s", id, groupsPerId[id] + ) + ret[id] = _getBestGroupGuess(groupCandidates, id) + else: + self.l.warning("No group for id %d could be found.", id) + ret[id] = None + return ret + + def _extractGroupsFromGroupMapping(self, mapping): + foundGroups = set() + for id in mapping: + foundGroups.add(mapping[id]) + sortedGroup = self._groupParser.getGroupsAsSortedList(foundGroups) + missingGroups = foundGroups.difference(sortedGroup) + sortedGroup = sortedGroup + list(missingGroups) + return sortedGroup + + def _invertGroupMapping(self, mapping, groups): + ret = {} + for group in groups: + ret[group] = [] + for id in mapping: + ret[mapping[id]].append(id) + return ret + def _extractDancesPerGroup( self, data: types.State3, group: solo_turnier.group.Group ):