package gdi1sokoban.highscores;
import gdi1sokoban.exceptions.InternalFailureException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.Math;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
/**
* Highscore class
*
* manages a highscore list
* @author Victor
*/
public class Highscores {
private int MAX_HIGHSCORES = 10; // max. number of highscores
private File hsFile
; // file handle of highscores.txt
/**
* Highscores constructor
*
* @param hsFilename the file in which highscores are saved
* @throws InternalFailureException
*/
public Highscores
(final String hsFilename
) throws InternalFailureException
{
try {
hsFile =
new File(new URI(hsFilename
));
throw new InternalFailureException("Highscore file I/O error");
}
if (! hsFile.exists())
try {
hsFile.createNewFile();
throw new InternalFailureException("Highscore file I/O error");
}
try {
loadHighscores();
throw new InternalFailureException("Highscore file not found");
throw new InternalFailureException("Highscore file I/O error");
}
}
/**
* Highscores constructor
*
* @param hsFilename the file in which highscores are saved
* @param maxHighscores max. number of highscores in list
* @throws InternalFailureException
*/
public Highscores
(final String hsFilename,
final int maxHighscores
) throws InternalFailureException
{
this(hsFilename);
MAX_HIGHSCORES = maxHighscores; // max. no. of highscores foreach level
}
/**
* processes the highscore data file and transforms it into the internal format
* @throws IOException
* @throws FileNotFoundException
*/
while ((line = in.readLine()) != null) { // read highscore file line by line
if (line.trim().isEmpty())
break;
final String[] hsData = line.
split("\t"); // split highscore line
if (hsData.length >= 1) myLevel = hsData[0];
if (hsData.length >= 2) myPlayerName = hsData[1];
if (hsData.length >= 3) mySteps = hsData[2];
if (hsData.length >= 4) myTime = hsData[3];
try {
addHighscore
(Integer.
valueOf(myLevel
), myPlayerName, mySteps, myTime
); // add the highscore into internal format
System.
err.
println("Fehler: Falscher Eingabewert! Eingabe muss eine gültige Zahl sein!");
}
}
in.close();
try {
saveHighscores(); // save the highscore list
} catch (final InternalFailureException e) {
System.
err.
println("Interner Fehler: Konnte Highscoredatei nicht speichern");
}
}
/**
* adds a highscore data structure into the highscore list
* @param levelNr level no.
* @param hsRow highscore row to be added
*/
private void addHighscore(final int levelNr, final HighscoreEntry hsRow) {
if (highscores.get(levelNr) == null)
highscores.
put(levelNr,
new ArrayList<HighscoreEntry
>(0));
highscores.get(levelNr).add(hsRow); // add the highscore
sortHighscores(); // sort the highscore list
}
/**
* creates a highscore data structure out of a set of strings
* and adds the structure to the highscore list
* @param myLevel game level
* @param myPlayerName player name
* @param mySteps steps made
* @param myTime time passed by (in sec.)
*/
public void addHighscore
(final int myLevel,
String myPlayerName,
final String mySteps,
final String myTime
) {
if (myPlayerName == null) // abort if player name is null
return;
if (myPlayerName.isEmpty()) // set to default if player name is empty
myPlayerName = "Dabbes";
try {
final HighscoreEntry hsRow = new HighscoreEntry(myPlayerName, mySteps, myTime); // create a highscore entry structure
addHighscore(myLevel, hsRow); // add the highscore
System.
err.
println("Highscore-Fehler: Falscher Eingabewert! Eingabe muss eine gültige Zahl sein!");
}
}
/**
* sorts the highscore lists of every level with help of
* an instance of HighscoreEntryComparator
*/
private void sortHighscores() {
final Comparator<HighscoreEntry
> hsComp =
new HighscoreEntryComparator
(); // create an instance of the highscore entry comparator
// loop every level
for (final Integer hsLevel : highscores.
keySet()) {
Collections.
sort(highscores.
get(hsLevel
), hsComp
); // sort the highscore list for this level
// loop all highscore entries for this level
for (int i = MAX_HIGHSCORES; i < highscores.get(hsLevel).size(); i++)
// every level may have MAX_HIGHSCORE highscore entries, cut elements
highscores.get(hsLevel).remove(i);
}
}
/**
* resets the highscore list
*/
public void resetHighscores() {
highscores.clear();
try {
saveHighscores();
} catch (final InternalFailureException e) {
System.
err.
println("Interner Fehler: Konnte Highscoredatei nicht speichern");
}
}
/**
* transforms a list of level highscores into an array of strings
* @param levelNo level number
* @return string table
*/
public String[][] toStringArray
(final int levelNo
) {
final ArrayList<HighscoreEntry
> lvlHighscores = highscores.
get(levelNo
); // get level-specific highscores
if (lvlHighscores == null)
return new String[0][0]; // no highscores available
final int arraySize =
Math.
min(MAX_HIGHSCORES, lvlHighscores.
size()); // ensure that only MAX_HIGHSCORES highscores are processed
for (int i = 0; i < arraySize; i++) { // loop every higscore, build the string array
ret
[i
][0] =
Integer.
valueOf(i+
1).
toString();
ret[i][1] = lvlHighscores.get(i).getPlayerName();
ret
[i
][2] =
Integer.
valueOf(lvlHighscores.
get(i
).
getSteps()).
toString();
ret
[i
][3] =
Integer.
valueOf(lvlHighscores.
get(i
).
getTime()).
toString();
}
return ret;
}
/**
* returns all available levels in a sorted string list
* @return level list
*/
levelList.addAll(highscores.keySet()); // put the hashmap's keys (level no.) into a list and sort it
for (int i = 0; i < levelList.size(); i++)
levelArray
[i
] =
Integer.
valueOf(levelList.
get(i
)).
toString();
return levelArray;
}
/**
* transforms the highscores into the highscore file format
*/
levelList.addAll(highscores.keySet()); // put the hashmap's keys (level no.) into a list and sort it
for (final int hsLevel : levelList)
for (final HighscoreEntry row : highscores.get(hsLevel))
retStr.append(hsLevel).append("\t").append(row.toString()).append("\n");
return retStr.toString().trim();
}
/**
* saves the highscore list into file
* @throws InternalFailureException
*/
public void saveHighscores() throws InternalFailureException {
final String hsContent =
this.
toString();
try {
bw.write(hsContent); // write file content
bw.close();
fw.close();
throw new InternalFailureException("Highscore file I/O error");
throw new InternalFailureException("Highscore file I/O error");
}
}
/**
* checks if a given combination of level no. and steps count
* is better or equal than a given existing highscore entry
* @param steps steps made
* @param time time needed to solve level
* @param existingEntry existing highscore entry
* @return false if existing highscore is better or equal than given highscore
*/
private boolean checkHighscore(final int steps, final int time, final HighscoreEntry existingEntry) {
// transform level and steps information into highscore entry structure
final HighscoreEntry checkEntry =
new HighscoreEntry
("",
String.
valueOf(steps
),
String.
valueOf(time
));
final Comparator<HighscoreEntry
> hsComp =
new HighscoreEntryComparator
();
// return the comparison result
return (hsComp.compare(existingEntry, checkEntry) > 0);
}
/**
* checks if a given combination of level no. and steps count
* leads to a new highscore
* @param level game level no.
* @param steps steps count
* @param time time needed to solve level
* @return true if new highscore, false if not
*/
public boolean isHighscore(final int level, final int steps, final int time) {
if (highscores.get(level) == null)
return true;
if (highscores.get(level).size() < MAX_HIGHSCORES) // if highscore count is less than MAX_HIGHSCORES
return true;
return checkHighscore(steps, time, highscores.get(level).get(MAX_HIGHSCORES - 1)); // return the comparison result
}
/**
* calculates the place of a combination of
* level no. and steps count in highscore list
* @param level game level no.
* @param steps steps made
* @param time time needed to solve level
* @return calculated ranking in highscore list
*/
public int getPlace(final int level, final int steps, final int time) {
int place = 1; // initial ranking
if (highscores.get(level) == null)
return place;
for (final HighscoreEntry row: highscores.get(level)) {
if (checkHighscore(steps, time, row)) // level+steps combination is better than actual row?
return place; // return this rank
place++;
}
return place; // if no highscores were made we assume 1st place, else last place
}
/**
* returns the highscore count for a specified level
* @param level level no.
* @return highscore count
*/
public int getHighscoreCount(final int level) {
if (highscores.get(level) == null)
return 0;
return highscores.get(level).size();
}
/**
* counts ALL global highscore entries
* @return
*/
public int getAllHighscoresCount() {
int count = 0;
for (final ArrayList<HighscoreEntry
> hsData : highscores.
values())
count += hsData.size();
return count;
}
}