Add route for groups leaderboard

This commit is contained in:
Francois G 2023-04-08 17:33:19 +02:00
parent e5794f382d
commit 14905a489a
5 changed files with 206 additions and 23 deletions

View file

@ -1,11 +1,17 @@
package be.jeffcheasey88.peeratcode.model;
import java.sql.Timestamp;
import java.util.*;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class Group {
public class Group implements Comparable<Group> {
private String name;
private int linkToChapter;
private int linkToPuzzle;
private List<Player> players;
private Timestamp endDate;
public Group(JSONObject json){
this.name = (String)json.get("name");
@ -14,9 +20,53 @@ public class Group {
}
public Group(String name, int initChap, int initPuzz) {
this(name, initChap, initPuzz, null);
}
public Group(String name, int initChap, int initPuzz, Timestamp initEnd) {
this.name = name;
this.linkToChapter = initChap;
this.linkToPuzzle = initPuzz;
this.endDate = initEnd;
}
public void addPlayer(Player newPlayer) {
if (newPlayer != null) {
if (players == null)
players = new ArrayList<Player>();
int pPosition = players.indexOf(newPlayer);
if (pPosition < 0) {
players.add(newPlayer);
}
else {
players.get(pPosition).addScore(newPlayer.getTotalScore(), newPlayer.getTotalTries());
}
}
}
public SortedSet<Player> getPlayers() {
return new TreeSet<Player>(players);
}
public int getScore() {
int score = 0;
if (players != null) {
for (Player p: players) {
score = score + p.getTotalScore();
}
}
return score;
}
public int getTries() {
int tries = 0;
if (players != null) {
for (Player p: players) {
tries = tries + p.getTotalTries();
}
}
return tries;
}
public String getName() {
@ -44,10 +94,61 @@ public class Group {
}
public JSONObject toJson() {
return this.toJson(null);
}
public JSONObject toJson(Integer rank) {
JSONObject groupJSON = new JSONObject();
groupJSON.put("name", name);
if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter);
if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle);
if (rank != null) groupJSON.put("rank", rank);
else if (linkToChapter > 0) groupJSON.put("chapter", linkToChapter);
else if (linkToPuzzle > 0) groupJSON.put("puzzle", linkToPuzzle);
if (endDate != null) groupJSON.put("end_date", endDate.toString());
if (players != null) {
JSONArray groupsPlayerJSON = new JSONArray();
for (Player p:players) {
JSONObject playerJSON = new JSONObject();
playerJSON.put("pseudo", p.getPseudo());
playerJSON.put("score", p.getTotalScore());
playerJSON.put("completion", p.getTotalCompletion());
playerJSON.put("tries", p.getTotalTries());
groupsPlayerJSON.add(playerJSON);
}
groupJSON.put("players", groupsPlayerJSON);
}
return groupJSON;
}
@Override
public int compareTo(Group arg0) {
int comparo = arg0.getScore() - getScore();
if (comparo == 0) {
comparo = players.size() - arg0.players.size();
if (comparo == 0) {
comparo = getTries() - arg0.getTries();
if (comparo == 0) {
comparo = name.compareTo(arg0.name);
}
}
}
return comparo;
}
@Override
public int hashCode() {
return Objects.hash(name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Group other = (Group) obj;
return Objects.equals(name, other.name);
}
}

View file

@ -1,16 +1,9 @@
package be.jeffcheasey88.peeratcode.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
@ -43,6 +36,18 @@ public class Player implements Comparable<Player> {
totalTries = 0;
}
public Player(String pseudo, int score, int tries) {
// For groups leaderboard
this.pseudo = pseudo;
totalScore = score;
totalTries = tries;
if (totalTries > 0)
totalCompletion = totalTries;
else
totalCompletion = 0;
email = ""; // TO make compareTo and equals works as usual
}
public String getPseudo() {
return this.pseudo;
}
@ -115,6 +120,12 @@ public class Player implements Comparable<Player> {
this.totalScore = totalScore;
}
public void addScore(int addScore, int tries) {
totalScore = totalScore + addScore;
totalTries = totalTries + tries;
totalCompletion++;
}
public int getTotalCompletion() {
return totalCompletion;
}

View file

@ -11,7 +11,10 @@ public enum DatabaseQuery {
PUZZLES_IN_CHAPTER_QUERY("SELECT p.*, GROUP_CONCAT(t.name) AS tags FROM puzzles p LEFT JOIN containsTags ct ON ct.fk_puzzle = p.id_puzzle LEFT JOIN tags t ON t.id_tag = ct.fk_tag WHERE fk_chapter = ? GROUP BY p.id_puzzle"),
ALL_CHAPTERS_QUERY("SELECT * FROM chapters WHERE id_chapter > 0"),
ALL_GROUPS("SELCT * FROM groups"),
ALL_PLAYERS_FOR_LEADERBOARD("select p.*, scores.*, g.* from players p ,(SELECT fk_player, SUM(c.score) AS score, COUNT(c.id_completion) AS completions, SUM(c.tries) AS tries, rank() over(ORDER BY score DESC) AS rank FROM completions c GROUP BY c.fk_player) AS scores LEFT JOIN containsGroups cg ON scores.fk_player = cg.fk_player LEFT JOIN groups g ON cg.fk_group = g.id_group WHERE p.id_player = scores.fk_player ORDER BY g.fk_chapter, g.fk_puzzle"),
ALL_GROUP_FOR_CHAPTER_LEADERBOARD("SELECT g.*, pl.pseudo, co.score, co.tries, ch.end_date FROM groups g LEFT JOIN containsGroups cg ON g.id_group = cg.fk_group LEFT JOIN players pl ON cg.fk_player = pl.id_player LEFT JOIN completions co ON pl.id_player = co.fk_player LEFT JOIN chapters ch ON g.fk_chapter = ch.id_chapter WHERE fk_chapter = ? AND (co.fk_puzzle IN (SELECT id_puzzle FROM puzzles puz WHERE puz.fk_chapter = g.fk_chapter) OR co.score IS NULL);"),
CHECK_PSEUDO_AVAILABLE_QUERY("SELECT * FROM players WHERE pseudo = ?"),
CHECK_EMAIL_AVAILABLE_QUERY("SELECT * FROM players WHERE email = ?"),
REGISTER_QUERY("INSERT INTO players (pseudo, email, passwd, firstname, lastname, description, avatar) VALUES (?, ?, ?, ?, ?, ?, ?)"),

View file

@ -80,8 +80,14 @@ public class DatabaseRepository {
}
private Group makeGroup(ResultSet result) throws SQLException {
if (hasColumn(result, "end_date"))
return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"), result.getTimestamp("end_date"));
else
return new Group(result.getString("name"), result.getInt("fk_chapter"), result.getInt("fk_puzzle"));
}
private Player makeGroupPlayer(ResultSet result) throws SQLException {
return new Player(result.getString("pseudo"), result.getInt("score"), result.getInt("tries"));
}
private Badge makeBadge(ResultSet rs) throws SQLException {
return new Badge(rs.getString("name"), rs.getBytes("logo"), rs.getInt("level"));
@ -91,8 +97,9 @@ public class DatabaseRepository {
// Found on StackOverflow
ResultSetMetaData rsmd = rs.getMetaData();
int columns = rsmd.getColumnCount();
for(int x = 1; x <= columns; x++){
if(columnName.equals(rsmd.getColumnName(x))) return true;
for (int x = 1; x <= columns; x++) {
if (columnName.equals(rsmd.getColumnName(x)))
return true;
}
return false;
}
@ -238,6 +245,33 @@ public class DatabaseRepository {
return null;
}
public SortedSet<Group> getAllGroupForChapterLeaderboard(int chapterId) {
try {
ensureConnection();
PreparedStatement groupsStmt = DatabaseQuery.ALL_GROUP_FOR_CHAPTER_LEADERBOARD.prepare(this.con);
groupsStmt.setInt(1, chapterId);
ResultSet result = groupsStmt.executeQuery();
List<Group> groups = new ArrayList<Group>();
Group tmpGroup;
while (result.next()) {
tmpGroup = makeGroup(result);
if (tmpGroup != null) {
int gPosition = groups.indexOf(tmpGroup);
if (gPosition < 0) {
tmpGroup.addPlayer(makeGroupPlayer(result));
groups.add(tmpGroup);
} else {
groups.get(gPosition).addPlayer(makeGroupPlayer(result));
}
}
}
return new TreeSet<Group>(groups);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Badge getBadge(int badgeId) {
try {
ensureConnection();
@ -380,7 +414,8 @@ public class DatabaseRepository {
ResultSet inserted = playerStatement.getGeneratedKeys();
if (inserted.next()) {
int newPlayerId = inserted.getInt(1);
try (PreparedStatement containsGroupsStatement = con.prepareStatement(DatabaseQuery.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) {
try (PreparedStatement containsGroupsStatement = con
.prepareStatement(DatabaseQuery.REGISTER_PLAYER_IN_EXISTING_GROUP.toString())) {
containsGroupsStatement.setInt(1, newPlayerId);
containsGroupsStatement.setString(2, sgroup);
containsGroupsStatement.executeUpdate();
@ -390,8 +425,7 @@ public class DatabaseRepository {
}
}
}
}
catch (SQLException e) {
} catch (SQLException e) {
con.rollback();
con.setAutoCommit(true);
}
@ -454,7 +488,7 @@ public class DatabaseRepository {
statement.executeUpdate();
}
public boolean insertGroup(Group group){
public boolean insertGroup(Group group) {
try {
ensureConnection();
PreparedStatement statement = DatabaseQuery.INSERT_GROUP.prepare(this.con);
@ -462,7 +496,8 @@ public class DatabaseRepository {
statement.setInt(2, group.getLinkToChapter());
statement.setInt(3, group.getLinkToPuzzle());
return statement.executeUpdate() >= 0;
}catch(Exception e){}
} catch (Exception e) {
}
return false;
}

View file

@ -1,5 +1,6 @@
package be.jeffcheasey88.peeratcode.routes;
import java.io.IOException;
import java.util.Base64;
import java.util.SortedSet;
import java.util.regex.Matcher;
@ -7,6 +8,7 @@ import java.util.regex.Matcher;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import be.jeffcheasey88.peeratcode.model.Group;
import be.jeffcheasey88.peeratcode.model.Player;
import be.jeffcheasey88.peeratcode.repository.DatabaseRepository;
import be.jeffcheasey88.peeratcode.webserver.HttpReader;
@ -24,10 +26,41 @@ public class Leaderboard implements Response {
this.databaseRepo = databaseRepo;
}
@Route(path = "^\\/leaderboard$")
@Route(path = "^\\/leaderboard\\/?(\\d+)?$")
@Override
public void exec(Matcher matcher, User user, HttpReader reader, HttpWriter writer) throws Exception {
HttpUtil.responseHeaders(writer, 200, "Access-Control-Allow-Origin: *");
if (matcher.group(1) != null){
groupsLeaderboard(Integer.parseInt(matcher.group(1)), writer);
} else {
playersLeaderboard(writer);
}
}
private void groupsLeaderboard(int chapterId, HttpWriter writer) throws IOException {
SortedSet<Group> allGroupsForChapter = databaseRepo.getAllGroupForChapterLeaderboard(chapterId);
JSONArray groupsJSON = new JSONArray();
if (allGroupsForChapter != null) {
int rank = 1;
int sameRankCount = 1;
Group previousGroup = null;
for (Group g: allGroupsForChapter) {
if (previousGroup != null) {
if (g.compareTo(previousGroup) == 0) {
sameRankCount++;
} else {
rank = rank + sameRankCount;
sameRankCount = 1;
}
}
groupsJSON.add(g.toJson(rank));
previousGroup = g;
}
}
writer.write(groupsJSON.toJSONString().replace("\\", ""));
}
private void playersLeaderboard(HttpWriter writer) throws IOException {
SortedSet<Player> allPlayers = databaseRepo.getAllPlayerForLeaderboard();
JSONArray playersJSON = new JSONArray();
if (allPlayers != null) {