Skip to content

Commit 769527a

Browse files
committed
Calculate PPM and add support for getting data as JSON
1 parent e33e18c commit 769527a

File tree

10 files changed

+101
-24
lines changed

10 files changed

+101
-24
lines changed

Arctic.Puzzlers.Objects/CompetitionObjects/CompetitionRound.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class CompetitionRound
1717
public List<Puzzle> Puzzles { get; set; } = new List<Puzzle>();
1818
public DateTime Time { get; set; } = new DateTime();
1919

20-
public TimeSpan MaxTime { get; set; } = new TimeSpan();
20+
public TimeSpan MaxTime { get; set; } = TimeSpan.Zero;
2121
public int NumberOfPieces { get; set; } = 0;
2222
public string Location { get; set; } = string.Empty;
2323
public string Url { get; set; } = string.Empty;

Arctic.Puzzlers.Objects/CompetitionObjects/ParticipantResult.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ public ParticipantResult()
1111
public bool? Qualified { get; set; }
1212

1313
public int Rank { get; set; } = 0;
14-
14+
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
15+
public long FinishedPieces { get; set; } = 0;
16+
1517
public List<Participant> Participants { get; set; }
1618
public List<Result> Results { get; set; }
1719

Arctic.Puzzlers.Objects/CompetitionObjects/Result.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace Arctic.Puzzlers.Objects.CompetitionObjects
44
{
55
public class Result
66
{
7-
private TimeSpan m_time;
7+
private TimeSpan m_time = TimeSpan.Zero;
88
public TimeSpan Time
99
{
1010
get
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace Arctic.Puzzlers.Objects.Misc
22
{
33
////date, player(s) name event name, piece count, rank, time, and remaining pieces
4-
public class CompetitionCSV
4+
public class CompetitionResult
55
{
66
public DateTime Date { get; set; }
77
public string PlayersName { get; set; } = string.Empty;
@@ -10,5 +10,7 @@ public class CompetitionCSV
1010

1111
public long Rank { get; set; }
1212
public TimeSpan Time { get; set; }
13+
public double PiecesPerMinute { get; set; }
14+
public double SimplifiedJpar { get; set; }
1315
}
1416
}

Arctic.Puzzlers.Parsers/CompetitionParsers/AepuzzParser.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public async Task Parse(string url)
111111
var competitionGroup = new CompetitionGroup { ContestType = competitionSingleRound.ContestType };
112112
competitionGroup.Rounds.Add(competitionSingleRound);
113113
competition.CompetitionGroups.Add(competitionGroup);
114+
competition.SetTotalResults();
114115
var addedSingleCompetition = await m_store.Store(competition);
115116
if (addedSingleCompetition)
116117
{
@@ -137,6 +138,7 @@ public async Task Parse(string url)
137138
competitionGroup.Rounds.Add(competitionSingleRound);
138139
competition.CompetitionGroups.Add(competitionGroup);
139140
}
141+
competition.SetTotalResults();
140142
var added = await m_store.Store(competition);
141143
if (added)
142144
{
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Arctic.Puzzlers.Objects.CompetitionObjects;
2+
using System.Text;
3+
4+
namespace Arctic.Puzzlers.Parsers.CompetitionParsers
5+
{
6+
public static class CompetitionExtensions
7+
{
8+
public static void SetTotalResults(this Competition competition)
9+
{
10+
competition.CompetitionGroups.ForEach(t => t.Rounds.ForEach(k => k.Participants.ForEach(participant => SetResults(participant,k))));
11+
}
12+
private static void SetResults(ParticipantResult participant, CompetitionRound round)
13+
{
14+
TimeSpan totalResults = TimeSpan.Zero;
15+
long finishedPieces = 0;
16+
foreach (var result in participant.Results)
17+
{
18+
totalResults = totalResults.Add(result.Time);
19+
finishedPieces += result.FinishedPieces;
20+
}
21+
participant.FinishedPieces = finishedPieces == 0 ? round.NumberOfPieces : finishedPieces;
22+
23+
participant.TotalTime = totalResults;
24+
}
25+
}
26+
}

Arctic.Puzzlers.Parsers/CompetitionParsers/CompetitionRoundExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ internal static void SetContestType(this CompetitionRound competitionObject)
2323
competitionObject.ContestType = ContestType.Unknown;
2424
}
2525
}
26+
2627
}
2728
}

Arctic.Puzzlers.Parsers/CompetitionParsers/SpeedPuzzlingParser.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public async Task Parse(string url)
6565

6666
var competitionGroup = await ParsePdf(stream);
6767
competition.CompetitionGroups.Add(competitionGroup);
68+
competition.SetTotalResults();
6869
var stored = await m_store.Store(competition);
6970
if (stored)
7071
{

Arctic.Puzzlers.Parsers/CompetitionParsers/WorldJigsawPuzzleOrgParser.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
using Arctic.Puzzlers.Stores;
44
using HtmlAgilityPack;
55
using Microsoft.Extensions.Logging;
6-
using System.Diagnostics;
76
using System.Globalization;
7+
using System.Text;
88
using System.Text.RegularExpressions;
9-
using System.Xml.Linq;
109

1110
namespace Arctic.Puzzlers.Parsers.CompetitionParsers
1211
{
@@ -83,6 +82,7 @@ public async Task Parse(string baseurl)
8382
competition.CompetitionGroups.Add(teamGroup);
8483
}
8584
}
85+
competition.SetTotalResults();
8686
await m_store.Store(competition);
8787
}
8888
catch (Exception ex)
@@ -140,12 +140,14 @@ internal async Task AddResult(CompetitionRound competitionRound, HtmlNodeCollect
140140
singlePuzzleResult.Puzzle = competitionRound.Puzzles.First();
141141
if (Regex.IsMatch(result, @"\d\d:\d\d:\d\d"))
142142
{
143-
singlePuzzleResult.Time = TimeSpan.Parse(Regex.Match(result, @"\d\d:\d\d:\d\d").Value);
143+
singlePuzzleResult.Time = TimeSpan.Parse(Regex.Match(result, @"\d\d:\d\d:\d\d").Value);
144144
}
145145
else
146146
{
147147
singlePuzzleResult.FinishedPieces = long.Parse(Regex.Match(result, @"\d+").Value);
148148
}
149+
150+
149151
if(int.TryParse(values[rankField].InnerText,out int rank))
150152
{
151153
participantResult.Rank = rank;
@@ -298,6 +300,7 @@ private string CleanUpString(string value)
298300
{
299301
value = value.Replace("&nbsp;", string.Empty);
300302
value = value.Replace(" ", string.Empty);
303+
value = value.Replace(".", string.Empty);
301304
return value;
302305
}
303306
}

Arctic.Puzzlers.Webapi/Controllers/CompetitionController.cs

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public async Task<ActionResult<IEnumerable<Competition>>> Get()
2828
}
2929

3030
[HttpGet]
31-
[Route("CSV/ListOfCompetitions")]
31+
[Route("ListOfCompetitions")]
3232
public async Task<ContentResult> GetAllCompetitions()
3333
{
3434
var html = "<p>List of competitions</p>";
@@ -39,8 +39,7 @@ public async Task<ContentResult> GetAllCompetitions()
3939
foreach (var competitionGroups in result.CompetitionGroups)
4040
{
4141
foreach (var round in competitionGroups.Rounds) {
42-
html += "<br/> ";
43-
html += $"<a href=\"/api/Competition/CSV?competition={result.CompetitionId}&round={round.RoundId} \">{result.Name + " " + competitionGroups.ContestType + " " + round.RoundName} </a>";
42+
html += $"<p>{result.Name + " " + competitionGroups.ContestType + " " + round.RoundName} <a href=\"/api/Competition/Simplified?competition={result.CompetitionId}&round={round.RoundId}&format=csv \">CSV </a> <a href=\"/api/Competition/Simplified?competition={result.CompetitionId}&round={round.RoundId}&format=json \">JSON</a></p>";
4443
}
4544
}
4645

@@ -54,9 +53,8 @@ public async Task<ContentResult> GetAllCompetitions()
5453

5554

5655
[HttpGet]
57-
[Route("CSV")]
58-
[Produces("text/csv")]
59-
public async Task<ActionResult> GetCsv(Guid competition, Guid round)
56+
[Route("Simplified")]
57+
public async Task<ActionResult> GetCsv(Guid competition, Guid round, string format)
6058
{
6159

6260
var data = await m_store.Get(competition);
@@ -74,7 +72,7 @@ public async Task<ActionResult> GetCsv(Guid competition, Guid round)
7472
{
7573
return NotFound();
7674
}
77-
var competitionCSVs = new List<CompetitionCSV>();
75+
var competitionCSVs = new List<CompetitionResult>();
7876

7977
foreach(var result in rounddata.Participants)
8078
{
@@ -84,26 +82,68 @@ public async Task<ActionResult> GetCsv(Guid competition, Guid round)
8482
{
8583
playersName = result.GroupName + "(" + playersName + ")";
8684
}
87-
var competitionCSV = new CompetitionCSV()
85+
86+
var competitionCSV = new CompetitionResult()
8887
{
8988
Date = rounddata.Time,
9089
EventName = data.Name + " " + groupData.ContestType + " " + rounddata.RoundName,
9190
PlayersName = playersName,
92-
Rank = result.Rank
91+
Rank = result.Rank,
92+
PieceCount = result.FinishedPieces,
93+
Time = result.TotalTime
9394
};
94-
95+
9596
competitionCSVs.Add(competitionCSV);
9697
}
97-
using (var memoryStream = new MemoryStream())
98-
{
99-
using (var streamWriter = new StreamWriter(memoryStream))
100-
using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture))
98+
99+
if(rounddata.MaxTime != TimeSpan.Zero)
100+
{
101+
int playerCounter = 0;
102+
double totalPiecesPerMinute = 0.0;
103+
competitionCSVs.ForEach(compCSV =>
101104
{
102-
csvWriter.WriteRecords(competitionCSVs);
103-
}
105+
var timespent = compCSV.Time == TimeSpan.Zero ? rounddata.MaxTime : compCSV.Time;
106+
var piecesPerMinute = (compCSV.PieceCount / timespent.TotalSeconds) * 60;
107+
compCSV.PiecesPerMinute = Math.Round(piecesPerMinute, 2);
108+
if(piecesPerMinute >0)
109+
{
110+
totalPiecesPerMinute += piecesPerMinute;
111+
playerCounter++;
112+
}
113+
114+
});
115+
116+
var averagePiecesPerMinute = totalPiecesPerMinute / playerCounter;
117+
if(averagePiecesPerMinute > 0)
118+
{
119+
competitionCSVs.ForEach(compCSV =>
120+
{
121+
compCSV.SimplifiedJpar = Math.Round(averagePiecesPerMinute / compCSV.PiecesPerMinute, 8);
122+
});
123+
}
124+
125+
}
104126

105-
return File(memoryStream.ToArray(), "text/csv", $"Export-{DateTime.Now.ToString("s")}.csv");
127+
128+
switch (format)
129+
{
130+
case "json":
131+
return Ok(competitionCSVs);
132+
case "csv":
133+
using (var memoryStream = new MemoryStream())
134+
{
135+
using (var streamWriter = new StreamWriter(memoryStream))
136+
using (var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture))
137+
{
138+
csvWriter.WriteRecords(competitionCSVs);
139+
}
140+
141+
return File(memoryStream.ToArray(), "text/csv", $"Export-{DateTime.Now.ToString("s")}.csv");
142+
}
143+
default:
144+
return Ok(competitionCSVs);
106145
}
146+
107147
}
108148

109149
}

0 commit comments

Comments
 (0)