Vereinsmeisterschaften  22aa7800eae54b428d40e835886cefe1fdefdfdf
This is a software that can be used to manage the internal competition of the swimming club Illertissen called "Vereinsmeisterschaften".
Loading...
Searching...
No Matches
ScoreService.cs
4
6{
11 {
15 public const int BEST_TIME_SCORE = 100;
16
17 private IPersonService _personService;
18 private ICompetitionService _competitionService;
19 private IWorkspaceService _workspaceService;
20
27 public ScoreService(IPersonService personService, ICompetitionService competitionService, IWorkspaceService workspaceService)
28 {
29 _personService = personService;
30 _personService.SetScoreServiceObj(this); // Dependency Injection can't be used in the constructor because of circular dependency
31 _competitionService = competitionService;
32 _workspaceService = workspaceService;
33
34 _workspaceService.PropertyChanged += (sender, e) =>
35 {
36 if (e.PropertyName == nameof(IWorkspaceService.Settings))
37 {
39 }
40 };
41 }
42
47 public void UpdateScoresForPerson(Person person)
48 {
49 _competitionService.UpdateAllCompetitionsForPerson(person);
50
51 foreach (PersonStart start in person?.Starts?.Values)
52 {
53 if (start == null) { continue; }
54
55 if (!start.IsActive)
56 {
57 // Inactive starts have no score
58 start.Score = 0;
59 }
60 else
61 {
62 Competition competition = start.CompetitionObj;
63 if (competition == null) { continue; }
64 // If the start time equals the competition best time the score will be 100
65 // If the person swims faster, the score is higher
66 if (start.Time.TotalMilliseconds == 0)
67 {
68 start.Score = 0;
69 }
70 else
71 {
72 // Original formula from old Vereinsmeisterschaften tool:
73 // score = 100 * (1 - ((start_time - competition_best_time) / competition_best_time)) = 100 * (2 - (start_time / competition_best_time))
74 // if startTime == bestTime => BEST_TIME_SCORE
75 // linear equation around this point
76 // zero points if startTime >= 2* bestTime
77 start.Score = (2 - (start.Time.TotalMilliseconds / competition.BestTime.TotalMilliseconds)) * BEST_TIME_SCORE;
78
79 ushort scoreFractionalDigits = _workspaceService?.Settings?.GetSettingValue<ushort>(WorkspaceSettings.GROUP_GENERAL, WorkspaceSettings.SETTING_GENERAL_SCORE_FRACTIONAL_DIGITS) ?? 1;
80 start.Score = Math.Round(start.Score, scoreFractionalDigits);
81
82 // Limit score to 0
83 if (start.Score < 0) { start.Score = 0; }
84 }
85 }
86 }
87 }
88
93 {
94 foreach(Person person in _personService.GetPersons())
95 {
97 }
98 }
99
104 {
105 List<Person> sortedPersons = GetPersonsSortedByScore(ResultTypes.Overall, false);
106 List<PersonStart> bestStarts = new List<PersonStart>();
107 bestStarts = sortedPersons.Where(p => p.HighestScoreStyle != SwimmingStyles.Unknown && p.Starts[p.HighestScoreStyle] != null)?.Select(p => p.Starts[p.HighestScoreStyle]).ToList();
108
109 // Group all starts by the score. It is possible to have more than one start with the same score leading to the same podium place
110 List<IGrouping<double, PersonStart>> groupedStarts = bestStarts.GroupBy(s => s.Score).ToList();
111 sortedPersons.ForEach(p => p.ResultListPlace = 0); // Reset all result list places
112 foreach (PersonStart personStart in bestStarts)
113 {
114 personStart.PersonObj.ResultListPlace = groupedStarts.IndexOf(groupedStarts.FirstOrDefault(g => g.Contains(personStart))) + 1;
115 }
116 }
117
124 public List<Person> GetPersonsSortedByScore(ResultTypes resultType, bool onlyActivePersons)
125 {
127 List<Person> persons = new List<Person>(_personService.GetPersons());
128 persons = onlyActivePersons ? persons.Where(p => p.IsActive).ToList() : persons;
129
130 if (resultType == ResultTypes.Overall)
131 {
132 return persons.OrderByDescending(p => p.HighestScore).ToList();
133 }
134 else if(resultType == ResultTypes.MaxAgeCompetitions)
135 {
136 return persons.Where(p => p.Starts[p.HighestScoreStyle].IsUsingMaxAgeCompetition).OrderByDescending(p => p.HighestScore).ToList();
137 }
138 else
139 {
140 SwimmingStyles style = getStyleFromResultType(resultType);
141 return persons.Where(p => p.Starts[style] != null).OrderByDescending(p => p.Starts[style].Score).ToList();
142 }
143 }
144
152 public List<PersonStart> GetWinnersPodiumStarts(ResultTypes resultType, ResultPodiumsPlaces podiumsPlace)
153 {
154 List<Person> sortedPersons = GetPersonsSortedByScore(resultType, true);
156 List<PersonStart> bestStarts = new List<PersonStart>();
157 if (resultType == ResultTypes.Overall || resultType == ResultTypes.MaxAgeCompetitions)
158 {
159 bestStarts = sortedPersons.Where(p => p.HighestScoreStyle != SwimmingStyles.Unknown && p.Starts[p.HighestScoreStyle] != null)?.Select(p => p.Starts[p.HighestScoreStyle]).ToList();
160 }
161 else
162 {
163 SwimmingStyles style = getStyleFromResultType(resultType);
164 bestStarts = sortedPersons.Where(p => p.Starts[style] != null)?.Select(p => p.Starts[style]).ToList();
165 }
166 bestStarts = bestStarts.Where(s => s.IsActive).ToList();
167
168 // Group all starts by the score. It is possible to have more than one start with the same score leading to the same podium place
169 List<IGrouping<double, PersonStart>> groupedStarts = bestStarts.GroupBy(s => s.Score).ToList();
170 if(podiumsPlace == ResultPodiumsPlaces.Gold && groupedStarts.Count > 0)
171 {
172 return groupedStarts[0].ToList();
173 }
174 else if (podiumsPlace == ResultPodiumsPlaces.Silver && groupedStarts.Count > 1)
175 {
176 return groupedStarts[1].ToList();
177 }
178 else if (podiumsPlace == ResultPodiumsPlaces.Bronze && groupedStarts.Count > 2)
179 {
180 return groupedStarts[2].ToList();
181 }
182 return null;
183 }
184
185 private SwimmingStyles getStyleFromResultType(ResultTypes resultType)
186 {
187 switch (resultType)
188 {
189 case ResultTypes.Overall: return SwimmingStyles.Unknown;
190 case ResultTypes.MaxAgeCompetitions: return SwimmingStyles.Unknown;
191 case ResultTypes.Breaststroke: return SwimmingStyles.Breaststroke;
192 case ResultTypes.Freestyle: return SwimmingStyles.Freestyle;
193 case ResultTypes.Backstroke: return SwimmingStyles.Backstroke;
194 case ResultTypes.Butterfly: return SwimmingStyles.Butterfly;
195 case ResultTypes.Medley: return SwimmingStyles.Medley;
196 case ResultTypes.WaterFlea: return SwimmingStyles.WaterFlea;
197 default: return SwimmingStyles.Unknown;
198 }
199 }
200 }
201}
Class describing a competition.
TimeSpan BestTime
Time for this competition to reach the maximum points.
Class describing a person.
Definition Person.cs:12
Class describing a start of a person.
Definition PersonStart.cs:9
TimeSpan Time
Time the person needed during the race of this start.
Competition CompetitionObj
Reference to the competition object to which the start belongs.
const int BEST_TIME_SCORE
Score that a person gets if the start time equals the competition best time.
List< Person > GetPersonsSortedByScore(ResultTypes resultType, bool onlyActivePersons)
Get all persons, sort them depending on the requested ResultTypes and return as new list.
ScoreService(IPersonService personService, ICompetitionService competitionService, IWorkspaceService workspaceService)
Constructor for the ScoreService
void UpdateScoresForAllPersons()
Update all scores for all Person
void UpdateScoresForPerson(Person person)
Update all scores for this Person
void UpdateResultListPlacesForAllPersons()
Update the result list places for all Person.
List< PersonStart > GetWinnersPodiumStarts(ResultTypes resultType, ResultPodiumsPlaces podiumsPlace)
Find the best starts of all persons depending on the ResultTypes and requested ResultPodiumsPlaces Th...
Interface for a service used to get and store a list of objects.
Interface for a service used to get and store a list of Person objects.
void SetScoreServiceObj(IScoreService scoreService)
Save the reference to the IScoreService object.
Interface for a service used to calculate the scores for all persons.
Interface for a service used to manage a workspace.
WorkspaceSettings Settings
Settings for the current workspace.
SwimmingStyles
Available swimming styles.
ResultTypes
Available result types.
Definition ResultTypes.cs:7
ResultPodiumsPlaces
Available result podium types.