/*
* opsu! - an open-source osu! client
* Copyright (C) 2014-2017 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see <http://www.gnu.org/licenses/>.
*/
package itdelatrisu.opsu.user;
/**
* User profile.
*/
public class User implements Comparable<User> {
/** Display name. */
private String name;
/** Total score. */
private long score;
/** Total accuracy. */
private double accuracy;
/** Total number of plays passed. */
private int playsPassed;
/** Total number of plays. */
private int playsTotal;
/** Current level. */
private int level;
/** Next level progress. */
private double levelProgress;
/** Profile icon identifier. */
private int icon;
/**
* Creates a new user with the given name and icon.
* @param name the user's name
* @param icon the user's icon
*/
public User(String name, int icon) { this(name, 0L, 0.0, 0, 0, icon); }
/**
* Creates a user with existing stats.
* @param name the user's name
* @param score the user's total score
* @param accuracy the user's total accuracy
* @param playsPassed the user's total passed play count
* @param playsTotal the user's total play count
* @param icon the user's icon identifier
*/
public User(String name, long score, double accuracy, int playsPassed, int playsTotal, int icon) {
this.name = name;
this.score = score;
this.accuracy = accuracy;
this.playsPassed = playsPassed;
this.playsTotal = playsTotal;
this.icon = icon;
calculateLevel();
}
/**
* Adds stats from a play (passed).
* @param score the score for the game
* @param accuracy the accuracy for the game
*/
public void add(long score, double accuracy) {
this.score += score;
this.accuracy = ((this.accuracy * this.playsPassed) + accuracy) / (this.playsPassed + 1);
this.playsPassed++;
this.playsTotal++;
calculateLevel();
}
/**
* Adds stats from a play (failed).
* @param score the score for the game
*/
public void add(long score) {
this.score += score;
this.playsTotal++;
calculateLevel();
}
/** Returns the user's name. */
public String getName() { return name; }
/** Returns the user's total score. */
public long getScore() { return score; }
/** Returns the user's total accuracy. */
public double getAccuracy() { return accuracy; }
/** Returns the user's total passed play count. */
public int getPassedPlays() { return playsPassed; }
/** Returns the user's total play count. */
public int getTotalPlays() { return playsTotal; }
/** Returns the user's icon identifier. */
public int getIconId() { return icon; }
/** Returns the user's level. */
public int getLevel() { return level; }
/** Returns the progress to the next level in [0,1). */
public double getNextLevelProgress() { return levelProgress; }
/** Calculates the user's current level and next level progress. */
private void calculateLevel() {
if (score == 0) {
this.level = 1;
this.levelProgress = 0.0;
return;
}
int l;
for (l = 1; this.score >= getScoreForLevel(l); l++) {}
l--;
this.level = l;
long baseScore = getScoreForLevel(l);
this.levelProgress = (double) (this.score - baseScore) / (getScoreForLevel(l + 1) - baseScore);
}
/**
* Returns the total score needed for a given level:
* <ul>
* <li><strong>Level <= 100:</strong>
* <p>5,000 / 3 * (4n^3 - 3n^2 - n) + 1.25 * 1.8^(n - 60)
* <li><strong>Level > 100:</strong>
* <p>26,931,190,829 + 100,000,000,000 * (n - 100)
* </ul>
* @param level the level
* @return the total score needed
* @see <a href="https://osu.ppy.sh/wiki/Score#Level">https://osu.ppy.sh/wiki/Score#Level</a>
*/
private static long getScoreForLevel(int level) {
if (level <= 1)
return 1L;
else if (level <= 100)
return (long) (5000.0 / 3 * (4 * Math.pow(level, 3) - 3 * Math.pow(level, 2) - level) + 1.25 * Math.pow(1.8, level - 60));
else
return 26_931_190_829L + 100_000_000_000L * (level - 100);
}
/** Sets the user's name. */
public void setName(String name) { this.name = name; }
/** Sets the user's icon identifier. */
public void setIconId(int id) { this.icon = id; }
@Override
public int compareTo(User other) {
return this.getName().compareToIgnoreCase(other.getName());
}
}