Skip to content

Commit

Permalink
Create commands for old leaderboards, implement the changes for tests…
Browse files Browse the repository at this point in the history
…v2 (#76)

and usersv2, and add some more indexes
  • Loading branch information
VanillaViking authored Aug 10, 2023
1 parent 87182c3 commit a27ef54
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 83 deletions.
6 changes: 3 additions & 3 deletions src/main/java/asynchronous/typing/AddTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import dataStructures.InfoCard;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import zyenyo.Database;

public class AddTest implements Runnable
{
Expand All @@ -28,8 +27,9 @@ public void run()
long userID;
if (args.length == 4) {userID = event.getAuthor().getIdLong();}
else {userID = Long.parseLong(args[4].substring(2, args[4].length() - 1));} // Only other case possible is args.length == 5.

Database.addTest(userID, wpm, accuracy, tp);

// this command is never used anyway
// Database.addTest(userID, wpm, accuracy, tp);

channel.sendMessageFormat("_`[SA] Successfully added test.`_").queue();
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/asynchronous/typing/Leaderboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public void run()
LeaderboardStatisticType lbStat = LeaderboardStatisticType.TP;
LeaderboardScope lbScope = LeaderboardScope.SUM;
int lbPage = 1;
Boolean old = false;

for (String cmd : args) {
switch (cmd.toLowerCase()) {
Expand All @@ -51,10 +52,11 @@ public void run()
case "-p": lbPage = getValueArg(args, "-p"); break;
case "-page": lbPage = getValueArg(args, "-page"); break;
case "-tests": lbStat = LeaderboardStatisticType.TESTS; break;
case "-old": old = true; break;
}
}

LeaderboardConfig lbConfig = new LeaderboardConfig(lbStat, lbScope);
LeaderboardConfig lbConfig = new LeaderboardConfig(lbStat, lbScope, old);

AggregateIterable<Document> lbList = Database.getLeaderboards(lbConfig);

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/asynchronous/typing/TypeStats.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ else if (args.length == 3 && args[2].equals("-g"))
}
else
{
json = new JSONObject(Database.getStats(idStr));
json = new JSONObject(Database.getStats(idStr, false));
title = "Recent Typing Statistics for " + event.getJDA().retrieveUserById(id).submit().get().getAsTag();
}

Expand All @@ -74,7 +74,7 @@ else if (args.length == 3 && args[2].equals("-g"))
double bestWpm = Double.parseDouble(json.get("bestWpm").toString());
double deviation = Double.parseDouble(json.get("deviation").toString());
double typingPoints = Double.parseDouble(json.get("weightedTp").toString());
// double playtime = Double.parseDouble(json.get("playtime").toString());
double playtime = Double.parseDouble(json.get("playtime").toString());
String rank = getRank(averageWpm);

channel.sendMessageEmbeds(new EmbedBuilder()
Expand All @@ -85,9 +85,9 @@ else if (args.length == 3 && args[2].equals("-g"))
+ "Average WPM: **`%.2f`**%n"
+ "Deviation: **`%.2f`**%n"
+ "Average Accuracy: **`%.2f%%`**%n"
// + "Playtime: **`%.0f hours %.0f minutes`**%n"
+ "Playtime: **`%.0f hours %.0f minutes`**%n"
+ "Rank: **`%s`**",
testsTaken, typingPoints, bestWpm, averageWpm, deviation, averageAcc, /* playtime / (1000 * 60 * 60), playtime / (1000 * 60), */ rank), false)
testsTaken, typingPoints, bestWpm, averageWpm, deviation, averageAcc, playtime / (1000 * 60 * 60), playtime / (1000 * 60), rank), false)
.setColor(new Color(180, 50, 80))
.build())
.queue();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/asynchronous/typing/TypingTestTeam.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ else if (Arrays.asList(teamBlue).contains(String.format("<@%s>", s.userID())))
}
else {continue;}

Database.addTest(s.userID(), s.wordsPerMinute(), s.accuracy(), s.typingPoints());
Database.addTestV2(s);
}

int i = 0;
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/asynchronous/typing/TypingTestTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,7 @@ public void run()
for (int i = 0; i < submissions.getNumSubmissions(); i++)
{
TypingSubmission s = submissions.getSubmission(lbOrder.get(i));
AddTestResult result = Database.addTest(s.userID(), s.wordsPerMinute(), s.accuracy(), s.typingPoints());
// TODO: replace with this after tpv2
// AddTestResult result = Database.addTestV2(s)
AddTestResult result = Database.addTestV2(s);
String dailyStreak = "";
if (result.dailyStreak() > 0) {
dailyStreak = String.format("Daily Streak: **`%d`**", result.dailyStreak());
Expand All @@ -232,4 +230,4 @@ public void run()
};
}

record TpCalculation(double typingPoints, double wordsPerMinute, double accuracy) {}
record TpCalculation(double typingPoints, double wordsPerMinute, double accuracy) {}
12 changes: 8 additions & 4 deletions src/main/java/dataStructures/LeaderboardConfig.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dataStructures;

import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.BsonField;

import java.util.ArrayList;
Expand All @@ -15,19 +16,22 @@
public class LeaderboardConfig {
private LeaderboardScope lbScope;
private String lbStatistic;
private String collection = "tests";
private String collection;
Boolean old;
private ArrayList<BsonField> accumulators = new ArrayList<BsonField>();

public LeaderboardConfig(LeaderboardStatisticType lbStatistic, LeaderboardScope lbScope) {
public LeaderboardConfig(LeaderboardStatisticType lbStatistic, LeaderboardScope lbScope, Boolean old) {
this.lbScope = lbScope;
this.old = old;
this.collection = old ? "tests" : "testsv2";

switch (lbStatistic) {
case TP:
this.lbStatistic = "tp";
switch(lbScope) {
case SUM:
this.lbStatistic = "totalTp";
this.collection = "users";
this.collection = old ?"users" : "usersv2";
this.accumulators.add(Accumulators.sum(this.lbStatistic, "$" + this.lbStatistic));
this.accumulators.add(Accumulators.first("userTag", "$userTag"));
break;
Expand Down Expand Up @@ -85,7 +89,7 @@ public List<BsonField> getAccumulationStrategies() {
}

public String getLeaderboardTitle() {
return String.format("Global %s %s Leaderboards", StringUtils.capitalize(lbScope.toString().toLowerCase()), StringUtils.capitalize(String.join(" ", StringUtils.splitByCharacterTypeCamelCase(this.lbStatistic))));
return String.format("Global %s %s Leaderboards %s", StringUtils.capitalize(lbScope.toString().toLowerCase()), StringUtils.capitalize(String.join(" ", StringUtils.splitByCharacterTypeCamelCase(this.lbStatistic))), this.old ? "(old)" : "");
}

}
85 changes: 19 additions & 66 deletions src/main/java/zyenyo/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class Database
private static MongoClient client;
private static MongoCollection<Document> tests;
private static MongoCollection<Document> testsV2;
private static MongoCollection<Document> usersV2;
private static MongoCollection<Document> users;
private static MongoCollection<Document> prompts;

Expand All @@ -76,74 +77,23 @@ public static void connect(String uri, String ENVIRONMENT)

tests = client.getDatabase(DB_NAME).getCollection("tests");
testsV2 = client.getDatabase(DB_NAME).getCollection("testsv2");
// tests will be queried very often for a user's top 100 tp scores. This needs to be fast.
testsV2.createIndex(Indexes.descending("tp"));

users = client.getDatabase(DB_NAME).getCollection("users");
users.createIndex(Indexes.descending("totalTp"));
usersV2 = client.getDatabase(DB_NAME).getCollection("usersv2");

prompts = client.getDatabase(DB_NAME).getCollection("prompts");
}

public static AddTestResult addTest(long discordId, double wpm, double accuracy, double tp)
{
double initialWeightedTp = getWeightedTp(discordId);
ArrayList<Bson> userUpdates = new ArrayList<Bson>();

InsertOneResult result = tests.insertOne(new Document()
.append("_id", new ObjectId())
.append("discordId", String.valueOf(discordId))
.append("wpm", wpm)
.append("accuracy", accuracy)
.append("tp", tp)
.append("date", LocalDateTime.now())
);

double newWeightedTp = getWeightedTp(discordId);
userUpdates.add(Updates.set("totalTp", newWeightedTp));

streakStatusResult streak = getStreakStatus(String.valueOf(discordId));
switch (streak.status()) {
case AVAILABLE:
userUpdates.add(Updates.inc("daily.currentStreak", 1));
// some other time :)
// userUpdates.add(Updates.max("daily.maxStreak", ));
userUpdates.add(Updates.set("daily.test", result.getInsertedId()));
// storing an instant instead of a normal date here otherwise it would push the server's local timezone to the db instead of UTC.
userUpdates.add(Updates.set("daily.updatedAt", new Date().toInstant().toString()));
break;
case CLAIMED:
break;
case INITIAL:
userUpdates.add(Updates.set("daily", new Document()
.append("currentStreak", 1)
.append("maxStreak", 1)
.append("test", result.getInsertedId())
.append("updatedAt", new Date().toInstant().toString())
));
break;
case MISSED:
userUpdates.add(Updates.set("daily.currentStreak", 1));
userUpdates.add(Updates.set("daily.test", result.getInsertedId()));
userUpdates.add(Updates.set("daily.updatedAt", new Date().toInstant().toString()));
break;
default:
break;

}

// Indexes for common statistics in order to speed up leaderboard commands
testsV2.createIndex(Indexes.descending("tp"));
testsV2.createIndex(Indexes.descending("wpm"));
testsV2.createIndex(Indexes.descending("accuracy"));
testsV2.createIndex(Indexes.descending("date"));

users.updateOne(
Filters.eq("discordId", String.valueOf(discordId)),
Updates.combine(
userUpdates
),
upsertTrue
);
usersV2.createIndex(Indexes.descending("totalTp"));
usersV2.createIndex(Indexes.descending("playtime"));

return new AddTestResult(newWeightedTp - initialWeightedTp, streak.currentStreak());
}


// TODO: make this the default addtest when tpv2 is done
public static AddTestResult addTestV2(TypingSubmission submission) {
double initialWeightedTp = getWeightedTp(submission.userID());
Expand Down Expand Up @@ -196,7 +146,7 @@ public static AddTestResult addTestV2(TypingSubmission submission) {

userUpdates.add(Updates.inc("playtime", submission.timeTakenMillis()));

users.updateOne(
usersV2.updateOne(
Filters.eq("discordId", String.valueOf(submission.userID())),
Updates.combine(
userUpdates
Expand Down Expand Up @@ -287,8 +237,12 @@ public static RefreshUserNamesResult refreshUserNames(MessageReceivedEvent event
return new RefreshUserNamesResult(timeTakenMillis, outdatedTagsCount);
}

public static String getStats(String discordId)
public static String getStats(String discordId, Boolean old)
{

MongoCollection<Document> tests = client.getDatabase(DB_NAME).getCollection(old ? "tests" : "testsv2");
MongoCollection<Document> users = client.getDatabase(DB_NAME).getCollection(old ? "users" : "usersv2");

tests.find(Filters.eq("discordId", discordId)).sort(descending("tp"));

Document stats = tests.aggregate(Arrays.asList(
Expand All @@ -301,9 +255,8 @@ public static String getStats(String discordId)
Accumulators.max("bestWpm", "$wpm"),
Accumulators.stdDevPop("deviation", "$wpm")
),
Aggregates.set(new Field<Double>("weightedTp", getWeightedTp(Long.valueOf(discordId))))
// For TPv2:
// Aggregates.set(new Field<Double>("playtime", users.find(Filters.eq("discordId", discordId)).first().getDouble("playtime")))
Aggregates.set(new Field<Double>("weightedTp", getWeightedTp(Long.valueOf(discordId)))),
Aggregates.set(new Field<Double>("playtime", users.find(Filters.eq("discordId", discordId)).first().getDouble("playtime")))
)).first();


Expand All @@ -327,7 +280,7 @@ public static AggregateIterable<Document> getLeaderboards(LeaderboardConfig lbCo

private static double getWeightedTp(long id)
{
AggregateIterable<Document> tpList = tests.aggregate(Arrays.asList(
AggregateIterable<Document> tpList = testsV2.aggregate(Arrays.asList(
Aggregates.match(Filters.eq("discordId", String.valueOf(id))),
Aggregates.match(Filters.exists("tp")),
Aggregates.sort(descending("tp")),
Expand Down

0 comments on commit a27ef54

Please sign in to comment.