@@ -282,9 +282,10 @@ class RoboScoutAPI {
282
282
}
283
283
284
284
suspend fun roboteventsCompetitionScraper (params : MutableMap <String , Any > = mutableMapOf()): List <String > {
285
- var requestUrl = " https://www.robotevents.com/robot-competitions/vex-robotics-competition"
286
285
var params = params
287
286
287
+ println (params)
288
+
288
289
if (! params.containsKey(" page" )) {
289
290
params[" page" ] = 1
290
291
}
@@ -299,10 +300,9 @@ class RoboScoutAPI {
299
300
6 -> params[" level_class_id" ] = 13
300
301
}
301
302
302
- when (params[" grade_level_id" ] as ? Int ) {
303
- 1 -> params[" grade_level_id" ] = 2
304
- 2 -> params[" grade_level_id" ] = 3
305
- }
303
+ val competition = if (API .seasonIdMap[0 ].find { it.id == params[" seasonId" ]} != null ) " vex-robotics-competition" else " college-competition"
304
+
305
+ val requestUrl = " https://www.robotevents.com/robot-competitions/$competition "
306
306
307
307
val skuArray = mutableListOf<String >()
308
308
@@ -327,12 +327,12 @@ class RoboScoutAPI {
327
327
println (" RobotEvents Scraper (page ${params[" page" ] as ? Int ? : 0 } ): ${response.call.request.url} " )
328
328
// println(response.bodyAsText())
329
329
330
- val pattern = " https://www \\ .robotevents \\ .com/robot-competitions/vex-robotics-competition/RE-VRC ([+-]?(?=\\ .\\ d|\\ d)(?:\\ d+)?(?: \\ .?\\ d*)) (?:[Ee]([+-]?\\ d+))?([+-]?(?=\\ .\\ d|\\ d)(?:\\ d+)?(?: \\ .?\\ d*) )(?:[Ee]([+-]?\\ d+))?\\ .html"
330
+ val pattern = " $requestUrl /RE-[A-Z0-9]* ([+-]?(?=\\ .\\ d|\\ d)(?:\\ d+)?\\ .?\\ d*)(?:[Ee]([+-]?\\ d+))?([+-]?(?=\\ .\\ d|\\ d)(?:\\ d+)?\\ .?\\ d*)(?:[Ee]([+-]?\\ d+))?\\ .html"
331
331
val regex = Regex (pattern, RegexOption .IGNORE_CASE )
332
332
val matches = regex.findAll(response.bodyAsText())
333
333
334
334
for (match in matches) {
335
- skuArray.add(match.value.replace(" https://www.robotevents.com/robot-competitions/vex-robotics-competition /" , " " ).replace(" .html" , " " ))
335
+ skuArray.add(match.value.replace(" $requestUrl /" , " " ).replace(" .html" , " " ))
336
336
}
337
337
println (" Matches: $skuArray " )
338
338
@@ -405,7 +405,7 @@ class RoboScoutAPI {
405
405
try {
406
406
val response = client.get(" https://www.robotevents.com/api/seasons/${season ? : API .selectedSeasonId()} /skills" ) {
407
407
url {
408
- parameters.append(" grade_level" , " High School " )
408
+ parameters.append(" grade_level" , gradeLevel )
409
409
}
410
410
}
411
411
@@ -440,7 +440,6 @@ class RoboScoutAPI {
440
440
val json = Json .parseToJsonElement(response.bodyAsText())
441
441
442
442
json.jsonArray.forEach { element ->
443
- // println("Element: $element")
444
443
val vdaEntry: VDAEntry = jsonWorker.decodeFromJsonElement(element)
445
444
this .vdaCache.add(vdaEntry)
446
445
}
@@ -463,14 +462,56 @@ class RoboScoutAPI {
463
462
}
464
463
}
465
464
466
- fun vdaFor (team : Team ): VDAEntry {
467
- return try {
465
+ suspend fun vdaFor (team : Team , fetchRobotEventsMatchStatistics : Boolean = false ): VDAEntry {
466
+ val vda = try {
468
467
this .vdaCache.first {
469
468
it.teamNumber == team.number
470
469
}
471
470
} catch (e: NoSuchElementException ) {
472
471
VDAEntry ()
473
472
}
473
+ if (fetchRobotEventsMatchStatistics) {
474
+ var totalWins = 0
475
+ var totalLosses = 0
476
+ var totalTies = 0
477
+ var totalAP = 0
478
+ var totalWP = 0
479
+
480
+ val seasonIndex = API .seasonIdMap[if (API .selectedProgramId() == 4 ) 1 else 0 ].indexOfFirst { it.id == API .selectedSeasonId() }
481
+ val season = API .seasonIdMap[if (team.grade == " College" ) 1 else 0 ][seasonIndex]
482
+
483
+ val reRankingsData = roboteventsRequest(" /teams/${team.id} /rankings" , mapOf (" season" to season.id))
484
+ val reRankings = reRankingsData.map { jsonWorker.decodeFromJsonElement<TeamRanking >(it) }
485
+ for (eventRankings in reRankings) {
486
+ println (" ${eventRankings.event.name} : ${eventRankings.wins} wins, ${eventRankings.losses} losses, ${eventRankings.ties} ties, ${eventRankings.ap} AP, ${eventRankings.wp} WP" )
487
+ totalWins + = eventRankings.wins
488
+ totalLosses + = eventRankings.losses
489
+ totalTies + = eventRankings.ties
490
+ totalAP + = eventRankings.ap
491
+ totalWP + = eventRankings.wp
492
+ }
493
+
494
+ val matches = team.matchesForSeason(season.id)
495
+ for (match in matches.filterNot { listOf (Round .PRACTICE , Round .QUALIFICATION ).contains(it.roundType) }) {
496
+ if (match.winningAlliance() == match.allianceFor(team)) {
497
+ totalWins + = 1
498
+ } else if (match.winningAlliance() != null ) {
499
+ totalLosses + = 1
500
+ } else {
501
+ totalTies + = 1
502
+ }
503
+ }
504
+
505
+ vda.totalWins = totalWins.toDouble()
506
+ vda.totalLosses = totalLosses.toDouble()
507
+ vda.totalTies = totalTies.toDouble()
508
+ vda.totalMatches = (totalWins + totalLosses + totalTies).toDouble()
509
+ vda.totalWinningPercent = (totalWins / vda.totalMatches) * 100
510
+ vda.apPerMatch = totalAP / vda.totalMatches
511
+ vda.wpPerMatch = totalWP / vda.totalMatches
512
+ vda.awpPerMatch = (totalWP - 2 * totalWins - totalTies) / vda.totalMatches
513
+ }
514
+ return vda
474
515
}
475
516
476
517
}
@@ -479,6 +520,7 @@ class RoboScoutAPI {
479
520
class Program {
480
521
var id: Int = 0
481
522
var name: String = " "
523
+ var code: String = " "
482
524
}
483
525
484
526
@Serializable
@@ -681,6 +723,7 @@ class Event {
681
723
var end: String = " "
682
724
@kotlinx.serialization.Transient var endDate: Date ? = null
683
725
var season: ShortSeason = ShortSeason ()
726
+ var program: Program = Program ()
684
727
var location: Location = Location ()
685
728
@kotlinx.serialization.Transient var matches: MutableMap <Division , MutableList <Match >> = mutableMapOf<Division , MutableList <Match >>()
686
729
var teams: MutableList <Team > = mutableListOf<Team >()
@@ -694,8 +737,11 @@ class Event {
694
737
@kotlinx.serialization.Transient var livestreamLink: String? = null
695
738
696
739
init {
697
- this .startDate = RoboScoutAPI .roboteventsDate(this .start, true )
698
- this .endDate = RoboScoutAPI .roboteventsDate(this .end, true )
740
+ try {
741
+ this .startDate = RoboScoutAPI .roboteventsDate(this .start, true )
742
+ this .endDate = RoboScoutAPI .roboteventsDate(this .end, true )
743
+ }
744
+ catch (_: java.text.ParseException ) { }
699
745
}
700
746
701
747
constructor (id: Int = 0 , fetch: Boolean = true ) {
@@ -937,16 +983,30 @@ class Event {
937
983
}
938
984
939
985
companion object {
940
- fun sortTeamsByNumber (teams : List <Team >): List <Team > {
941
- // Teams can be:
942
- // 229V, 4082B, 10C, 2775V, 9364C, 9364A
943
- // These teams are first sorted by the letter part of their team.number, then by the number part
944
- // The sorted list for the above teams:
945
- // 10C, 229V, 2775V, 4082B, 9364A, 9364C
946
- // Sort by letter part (remove all non-letter characters and sort)
947
- val sortedTeams = teams.sortedBy { it.number.replace(Regex (" [^A-Za-z]" ), " " ) }
948
- // Sort by number part (remove all non-number characters and sort)
949
- return sortedTeams.sortedBy { it.number.replace(Regex (" [^0-9]" ), " " ).toInt() }
986
+ fun sortTeamsByNumber (teams : List <Team >, gradeLevel : String ): List <Team > {
987
+ if (gradeLevel != " College" ) {
988
+ // Teams can be:
989
+ // 229V, 4082B, 10C, 2775V, 9364C, 9364A
990
+ // These teams are first sorted by the letter part of their team.number, then by the number part
991
+ // The sorted list for the above teams:
992
+ // 10C, 229V, 2775V, 4082B, 9364A, 9364C
993
+ // Sort by letter part (remove all non-letter characters and sort)
994
+ val sortedTeams = teams.sortedBy { it.number.replace(Regex (" [^A-Za-z]" ), " " ) }
995
+ // Sort by number part (remove all non-number characters and sort)
996
+ return sortedTeams.sortedBy { it.number.replace(Regex (" [^0-9]" ), " " ).toIntOrNull() }
997
+ }
998
+ else {
999
+ // Teams can be:
1000
+ // UCF, GATR1, GATR2, BLRS2, PYRO
1001
+ // These teams are first sorted by the number part of their team.number, then by the letter part
1002
+ // The sorted list for the above teams:
1003
+ // BLRS2, GATR1, GATR2, PYRO, UCF
1004
+ // Sort by number part (remove all non-number characters and sort)
1005
+ // If there is no number part, the team should go above all teams with the same letter part that have a number part
1006
+ val sortedTeams = teams.sortedBy { it.number.replace(Regex (" [^0-9]" ), " " ).toIntOrNull() }
1007
+ // Sort by letter part (remove all non-letter characters and sort)
1008
+ return sortedTeams.sortedBy { it.number.replace(Regex (" [^A-Za-z]" ), " " ) }
1009
+ }
950
1010
}
951
1011
}
952
1012
@@ -1007,12 +1067,12 @@ class Team : MutableState<Team> {
1007
1067
1008
1068
if (this .id != 0 ) {
1009
1069
runBlocking {
1010
- res = RoboScoutAPI .roboteventsRequest(" /teams/$id " , mapOf ( " program " to 1 ) )
1070
+ res = RoboScoutAPI .roboteventsRequest(" /teams/$id " )
1011
1071
}
1012
1072
}
1013
1073
else if (this .number.isNotEmpty()) {
1014
1074
runBlocking {
1015
- res = RoboScoutAPI .roboteventsRequest(" /teams" , mapOf (" number" to number, " program " to 1 ))
1075
+ res = RoboScoutAPI .roboteventsRequest(" /teams" , mapOf (" number" to number, " grade " to listOf ( " Middle School " , " High School " , " College " ) ))
1016
1076
}
1017
1077
}
1018
1078
else {
@@ -1047,8 +1107,27 @@ class Team : MutableState<Team> {
1047
1107
return matches
1048
1108
}
1049
1109
1050
- suspend fun fetchEvents (season : Int? = null) {
1051
- val data = RoboScoutAPI .roboteventsRequest(" /events" , mapOf (" team" to id, " season" to (season ? : API .selectedSeasonId())))
1110
+ suspend fun matchesForSeason (season : Int ): List <Match > {
1111
+ val data = RoboScoutAPI .roboteventsRequest(" /teams/${this .id} /matches" , mapOf (" season" to season))
1112
+ val matches = mutableListOf<Match >()
1113
+ for (match in data) {
1114
+ val fetchedMatch: Match = jsonWorker.decodeFromJsonElement(match)
1115
+ matches.add(fetchedMatch)
1116
+ }
1117
+ matches.sortBy { it.instance }
1118
+ matches.sortBy { it.roundType }
1119
+ return matches
1120
+ }
1121
+
1122
+ suspend fun fetchEvents (season : Int? = null) {
1123
+ val data: List <JsonObject >
1124
+ if (season == null ) {
1125
+ val seasonIndex = API .seasonIdMap[if (API .selectedProgramId() == 4 ) 1 else 0 ].indexOfFirst { it.id == API .selectedSeasonId() }
1126
+ data = RoboScoutAPI .roboteventsRequest(" /events" , mapOf (" team" to id, " season" to (API .seasonIdMap[if (this .grade == " College" ) 1 else 0 ][seasonIndex].id)))
1127
+ }
1128
+ else {
1129
+ data = RoboScoutAPI .roboteventsRequest(" /events" , mapOf (" team" to id, " season" to season))
1130
+ }
1052
1131
events.clear()
1053
1132
for (event in data) {
1054
1133
val fetchedEvent: Event = jsonWorker.decodeFromJsonElement(event)
0 commit comments