diff --git a/src/main/java/wtf/beatrice/hidekobot/objects/TriviaScore.java b/src/main/java/wtf/beatrice/hidekobot/objects/TriviaScore.java new file mode 100644 index 0000000..bdba83a --- /dev/null +++ b/src/main/java/wtf/beatrice/hidekobot/objects/TriviaScore.java @@ -0,0 +1,31 @@ +package wtf.beatrice.hidekobot.objects; + +import net.dv8tion.jda.api.entities.User; + +public class TriviaScore +{ + + private final User user; + private int score = 0; + + public TriviaScore(User user) + { + this.user = user; + } + + public void changeScore(int add) + { + score += add; + } + + public int getScore() { return score; } + + public User getUser() { return user; } + + @Override + public String toString() + { + return "[" + user.getAsTag() + "," + score + "]"; + } + +} diff --git a/src/main/java/wtf/beatrice/hidekobot/objects/comparators/TriviaScoreComparator.java b/src/main/java/wtf/beatrice/hidekobot/objects/comparators/TriviaScoreComparator.java new file mode 100644 index 0000000..4af97e1 --- /dev/null +++ b/src/main/java/wtf/beatrice/hidekobot/objects/comparators/TriviaScoreComparator.java @@ -0,0 +1,18 @@ +package wtf.beatrice.hidekobot.objects.comparators; + +import wtf.beatrice.hidekobot.objects.TriviaScore; + +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +/** + * This class gets two trivia scores, and compares their score. + */ +public class TriviaScoreComparator implements Comparator { + + @Override + public int compare(TriviaScore o1, TriviaScore o2) { + return Integer.compare(o2.getScore(), o1.getScore()); // inverted, because higher number should come first + } +} diff --git a/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java b/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java index d22abec..c8a99e7 100644 --- a/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java +++ b/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java @@ -9,13 +9,12 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.json.JSONObject; import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.objects.TriviaQuestion; +import wtf.beatrice.hidekobot.objects.TriviaScore; +import wtf.beatrice.hidekobot.objects.comparators.TriviaScoreComparator; import wtf.beatrice.hidekobot.util.CommandUtil; import wtf.beatrice.hidekobot.util.TriviaUtil; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.concurrent.ScheduledFuture; public class TriviaTask implements Runnable @@ -47,12 +46,13 @@ public class TriviaTask implements Runnable } @Override - public void run() { - + public void run() + { if(previousMessage != null) { // todo: we shouldn't use this method, since it messes with the database... CommandUtil.disableExpired(previousMessage.getId()); + String previousCorrectAnswer = questions.get(iteration-1).correctAnswer(); // we need this to be thread-locking to avoid getting out of sync with the rest of the trivia features @@ -65,11 +65,73 @@ public class TriviaTask implements Runnable if(iteration >= questions.size()) { - // todo: nicer-looking embed with stats - // we need this to be thread-locking to avoid getting out of sync with the rest of the trivia features - channel.sendMessage("Trivia session is over!").complete(); + String scoreboardText = "\uD83D\uDC23 Trivia session is over!"; + + List winners = new ArrayList<>(); + int topScore = 0; + StringBuilder othersBuilder = new StringBuilder(); + + LinkedList triviaScores = new LinkedList<>(TriviaUtil.channelAndScores.get(channel.getId())); + triviaScores.sort(new TriviaScoreComparator()); + + int pos = 0; + Integer previousScore = null; + for(TriviaScore triviaScore : triviaScores) + { + if(pos > 10) break; // cap at top 10 + + String user = triviaScore.getUser().getAsMention(); + int score = triviaScore.getScore(); + if(previousScore == null) + { + previousScore = score; + topScore = score; + pos = 1; + } else { + if(score != previousScore) pos++; + } + + if(pos == 1) winners.add(user); + else { + othersBuilder.append("\n").append(pos) + .append(" | ").append(user) + .append(": ").append(score).append(" points"); + } + } + + StringBuilder winnersBuilder = new StringBuilder(); + for(int i = 0; i < winners.size(); i++) + { + String winner = winners.get(i); + winnersBuilder.append(winner); + if(i + 1 != winners.size()) + { + winnersBuilder.append(", "); // separate with comma except on last run + } else { + winnersBuilder.append(": ").append(topScore).append(" points \uD83C\uDF89"); + } + } + + String winnersTitle = "\uD83D\uDCAB "; + winnersTitle += winners.size() == 1 ? "Winner" : "Winners"; + + + EmbedBuilder scoreboardBuilder = new EmbedBuilder(); + scoreboardBuilder.setColor(Cache.getBotColor()); + scoreboardBuilder.setTitle("\uD83C\uDF1F Trivia Scoreboard"); + scoreboardBuilder.addField(winnersTitle, winnersBuilder.toString(), false); + scoreboardBuilder.addField("☁️ Others", othersBuilder.toString(), false); + + channel.sendMessage(scoreboardText).addEmbeds(scoreboardBuilder.build()).queue(); + + + + // remove all cached data TriviaUtil.channelsRunningTrivia.remove(channel.getId()); + TriviaUtil.channelAndWhoResponded.remove(channel.getId()); + TriviaUtil.channelAndScores.remove(channel.getId()); + future.cancel(false); // we didn't implement null checks on the future on purpose, because we need to know if we were unable // to cancel it (and console errors should make it clear enough). @@ -110,9 +172,9 @@ public class TriviaTask implements Runnable EmbedBuilder embedBuilder = new EmbedBuilder(); embedBuilder.setColor(Cache.getBotColor()); - embedBuilder.setTitle("Trivia (" + (iteration+1) + "/" + questions.size() + ")"); + embedBuilder.setTitle("\uD83C\uDFB2 Trivia (" + (iteration+1) + "/" + questions.size() + ")"); - embedBuilder.addField("Question", currentTriviaQuestion.question(), false); + embedBuilder.addField("❓ Question", currentTriviaQuestion.question(), false); previousMessage = channel .sendMessageEmbeds(embedBuilder.build()) diff --git a/src/main/java/wtf/beatrice/hidekobot/util/TriviaUtil.java b/src/main/java/wtf/beatrice/hidekobot/util/TriviaUtil.java index 17c89e2..f5bd950 100644 --- a/src/main/java/wtf/beatrice/hidekobot/util/TriviaUtil.java +++ b/src/main/java/wtf/beatrice/hidekobot/util/TriviaUtil.java @@ -8,6 +8,7 @@ import org.json.JSONArray; import org.json.JSONObject; import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.objects.TriviaQuestion; +import wtf.beatrice.hidekobot.objects.TriviaScore; import java.io.BufferedReader; import java.io.IOException; @@ -28,6 +29,9 @@ public class TriviaUtil // first string is the channelId, the list contain all users who responded there public static HashMap> channelAndWhoResponded = new HashMap<>(); + // first string is the channelId, the list contain all score records for that channel + public static HashMap> channelAndScores = new HashMap<>(); + public static JSONObject fetchTrivia() { try { @@ -80,19 +84,47 @@ public class TriviaUtil public static void handleAnswer(ButtonInteractionEvent event, AnswerType answerType) { - if(trackResponse(event.getUser(), event.getChannel())) + User user = event.getUser(); + String channelId = event.getChannel().getId(); + + if(trackResponse(user, event.getChannel())) { + List scores = channelAndScores.get(channelId); + if(scores == null) scores = new ArrayList<>(); + TriviaScore currentUserScore = null; + for(TriviaScore score : scores) + { + if(score.getUser().equals(user)) + { + currentUserScore = score; + scores.remove(score); + break; + } + } + + if(currentUserScore == null) + { + currentUserScore = new TriviaScore(user); + } + if(answerType.equals(AnswerType.CORRECT)) { - event.reply(event.getUser().getAsMention() + " got it right!").queue(); + + event.reply(user.getAsMention() + " got it right! \uD83E\uDD73 (**+3**)").queue(); + currentUserScore.changeScore(3); + } else { - event.reply(event.getUser().getAsMention() + ", that's not the right answer!").queue(); + event.reply("❌ " + user.getAsMention() + ", that's not the right answer! (**-1**)").queue(); + currentUserScore.changeScore(-1); } + + scores.add(currentUserScore); + channelAndScores.put(channelId, scores); } else { - event.reply(event.getUser().getAsMention() + ", you can't answer twice!") - .queue(message -> + event.reply("☹️ " + user.getAsMention() + ", you can't answer twice!") + .queue(interaction -> Cache.getTaskScheduler().schedule(() -> - message.deleteOriginal().queue(), 5, TimeUnit.SECONDS)); + interaction.deleteOriginal().queue(), 3, TimeUnit.SECONDS)); } }