Subversion Repositories sokoban

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 daniel-mar 1
package gdi1sokoban.highscores;
2
 
3
import gdi1sokoban.exceptions.InternalFailureException;
4
 
5
import java.io.BufferedReader;
6
import java.io.BufferedWriter;
7
import java.io.File;
8
import java.io.FileNotFoundException;
9
import java.io.FileReader;
10
import java.io.FileWriter;
11
import java.io.IOException;
12
import java.lang.Math;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.util.ArrayList;
16
import java.util.Collections;
17
import java.util.Comparator;
18
import java.util.HashMap;
19
 
20
/**
21
 * Highscore class
22
 *
23
 * manages a highscore list
24
 * @author Victor
25
 */
26
public class Highscores {
27
        private int MAX_HIGHSCORES = 10; // max. number of highscores
28
        private final HashMap<Integer, ArrayList<HighscoreEntry>> highscores = new HashMap<Integer, ArrayList<HighscoreEntry>>(); // array list for saving level specific highscores
29
        private File hsFile; // file handle of highscores.txt
30
 
31
        /**
32
         * Highscores constructor
33
         *
34
         * @param hsFilename the file in which highscores are saved
35
         * @throws InternalFailureException
36
         */
37
        public Highscores(final String hsFilename) throws InternalFailureException {
38
                try {
39
                        hsFile = new File(new URI(hsFilename));
40
                } catch (final URISyntaxException e) {
41
                        throw new InternalFailureException("Highscore file I/O error");
42
                }
43
                if (! hsFile.exists())
44
                        try {
45
                                hsFile.createNewFile();
46
                        } catch (final IOException e) {
47
                                throw new InternalFailureException("Highscore file I/O error");
48
                        }
49
                try {
50
                        loadHighscores();
51
                } catch (final FileNotFoundException e) {
52
                        throw new InternalFailureException("Highscore file not found");
53
                } catch (final IOException e) {
54
                        throw new InternalFailureException("Highscore file I/O error");
55
                }
56
        }
57
 
58
        /**
59
         * Highscores constructor
60
         *
61
         * @param hsFilename the file in which highscores are saved
62
         * @param maxHighscores max. number of highscores in list
63
         * @throws InternalFailureException
64
         */
65
        public Highscores(final String hsFilename, final int maxHighscores) throws InternalFailureException {
66
                this(hsFilename);
67
                MAX_HIGHSCORES = maxHighscores; // max. no. of highscores foreach level
68
        }
69
 
70
        /**
71
         * processes the highscore data file and transforms it into the internal format
72
         * @throws IOException
73
         * @throws FileNotFoundException
74
         */
75
        private void loadHighscores() throws IOException, FileNotFoundException {
76
                final BufferedReader in = new BufferedReader(new FileReader(hsFile));
77
                String line = null;
78
                while ((line = in.readLine()) != null) { // read highscore file line by line
79
                        if (line.trim().isEmpty())
80
                                break;
81
                        final String[] hsData = line.split("\t"); // split highscore line
82
                        String myLevel = "";
83
                        String myPlayerName = "";
84
                        String mySteps = "0";
85
                        String myTime = "0";
86
                        if (hsData.length >= 1) myLevel = hsData[0];
87
                        if (hsData.length >= 2) myPlayerName = hsData[1];
88
                        if (hsData.length >= 3) mySteps = hsData[2];
89
                        if (hsData.length >= 4) myTime = hsData[3];
90
                        try {
91
                                addHighscore(Integer.valueOf(myLevel), myPlayerName, mySteps, myTime); // add the highscore into internal format
92
                        } catch (final NumberFormatException e) { // wrong number format
93
                                System.err.println("Fehler: Falscher Eingabewert! Eingabe muss eine gültige Zahl sein!");
94
                        }
95
                }
96
                in.close();
97
                try {
98
                        saveHighscores(); // save the highscore list
99
                } catch (final InternalFailureException e) {
100
                        System.err.println("Interner Fehler: Konnte Highscoredatei nicht speichern");
101
                }
102
        }
103
 
104
        /**
105
         * adds a highscore data structure into the highscore list
106
         * @param levelNr level no.
107
         * @param hsRow highscore row to be added
108
         */
109
        private void addHighscore(final int levelNr, final HighscoreEntry hsRow) {
110
                if (highscores.get(levelNr) == null)
111
                        highscores.put(levelNr, new ArrayList<HighscoreEntry>(0));
112
                highscores.get(levelNr).add(hsRow); // add the highscore
113
                sortHighscores(); // sort the highscore list
114
        }
115
 
116
        /**
117
         * creates a highscore data structure out of a set of strings
118
         * and adds the structure to the highscore list
119
         * @param myLevel game level
120
         * @param myPlayerName player name
121
         * @param mySteps steps made
122
         * @param myTime time passed by (in sec.)
123
         */
124
        public void addHighscore(final int myLevel, String myPlayerName, final String mySteps, final String myTime) {
125
                if (myPlayerName == null) // abort if player name is null
126
                        return;
127
                if (myPlayerName.isEmpty()) // set to default if player name is empty
128
                        myPlayerName = "Dabbes";
129
                try {
130
                        final HighscoreEntry hsRow = new HighscoreEntry(myPlayerName, mySteps, myTime); // create a highscore entry structure
131
                        addHighscore(myLevel, hsRow); // add the highscore
132
                } catch (final NumberFormatException e) { // wrong number format
133
                        System.err.println("Highscore-Fehler: Falscher Eingabewert! Eingabe muss eine gültige Zahl sein!");
134
                }
135
        }
136
 
137
        /**
138
         * sorts the highscore lists of every level with help of
139
         * an instance of HighscoreEntryComparator
140
         */
141
        private void sortHighscores() {
142
                final Comparator<HighscoreEntry> hsComp = new HighscoreEntryComparator(); // create an instance of the highscore entry comparator
143
                // loop every level
144
                for (final Integer hsLevel : highscores.keySet()) {
145
                        Collections.sort(highscores.get(hsLevel), hsComp); // sort the highscore list for this level
146
                        // loop all highscore entries for this level
147
                        for (int i = MAX_HIGHSCORES; i < highscores.get(hsLevel).size(); i++)
148
                                        // every level may have MAX_HIGHSCORE highscore entries, cut elements
149
                                        highscores.get(hsLevel).remove(i);
150
                }              
151
        }
152
 
153
        /**
154
         * resets the highscore list
155
         */
156
        public void resetHighscores() {
157
                highscores.clear();
158
                try {
159
                        saveHighscores();
160
                } catch (final InternalFailureException e) {
161
                        System.err.println("Interner Fehler: Konnte Highscoredatei nicht speichern");
162
                }
163
        }
164
 
165
        /**
166
         * transforms a list of level highscores into an array of strings
167
         * @param levelNo level number
168
         * @return string table
169
         */
170
        public String[][] toStringArray(final int levelNo) {
171
                final ArrayList<HighscoreEntry> lvlHighscores = highscores.get(levelNo); // get level-specific highscores
172
                if (lvlHighscores == null)
173
                        return new String[0][0]; // no highscores available
174
                final int arraySize = Math.min(MAX_HIGHSCORES, lvlHighscores.size()); // ensure that only MAX_HIGHSCORES highscores are processed
175
                final String[][] ret = new String[arraySize][4];
176
                for (int i = 0; i < arraySize; i++) { // loop every higscore, build the string array
177
                ret[i][0] = Integer.valueOf(i+1).toString();
178
                ret[i][1] = lvlHighscores.get(i).getPlayerName();
179
                ret[i][2] = Integer.valueOf(lvlHighscores.get(i).getSteps()).toString();
180
                ret[i][3] = Integer.valueOf(lvlHighscores.get(i).getTime()).toString();
181
                }
182
                return ret;
183
        }
184
 
185
        /**
186
         * returns all available levels in a sorted string list
187
         * @return level list
188
         */
189
        public String[] getLevels() {
190
                final ArrayList<Integer> levelList = new ArrayList<Integer>(0);
191
                levelList.addAll(highscores.keySet()); // put the hashmap's keys (level no.) into a list and sort it
192
                Collections.sort(levelList); // sort level numbers
193
                final String [] levelArray = new String[levelList.size()];
194
                for (int i = 0; i < levelList.size(); i++)
195
                        levelArray[i] = Integer.valueOf(levelList.get(i)).toString();
196
                return levelArray;
197
        }
198
 
199
        /**
200
         * transforms the highscores into the highscore file format
201
         */
202
        @Override
203
        public String toString() {
204
                final StringBuffer retStr = new StringBuffer(100);
205
                final ArrayList<Integer> levelList = new ArrayList<Integer>(0);
206
                levelList.addAll(highscores.keySet()); // put the hashmap's keys (level no.) into a list and sort it
207
                Collections.sort(levelList);
208
                for (final int hsLevel : levelList)
209
                        for (final HighscoreEntry row : highscores.get(hsLevel))
210
                                retStr.append(hsLevel).append("\t").append(row.toString()).append("\n");
211
                return retStr.toString().trim();
212
        }
213
 
214
        /**
215
         * saves the highscore list into file
216
         * @throws InternalFailureException
217
         */
218
        public void saveHighscores() throws InternalFailureException {
219
                final String hsContent = this.toString();      
220
            FileWriter fw;
221
            BufferedWriter bw;
222
            try {
223
              fw = new FileWriter(hsFile);
224
              bw = new BufferedWriter(fw);
225
              bw.write(hsContent); // write file content
226
              bw.close();
227
              fw.close();
228
            } catch (final IOException e) {
229
                throw new InternalFailureException("Highscore file I/O error");
230
            } catch (final NullPointerException e) {
231
                throw new InternalFailureException("Highscore file I/O error");
232
            }          
233
        }
234
 
235
        /**
236
         * checks if a given combination of level no. and steps count
237
         * is better or equal than a given existing highscore entry
238
         * @param steps steps made
239
         * @param time time needed to solve level
240
         * @param existingEntry existing highscore entry
241
         * @return false if existing highscore is better or equal than given highscore
242
         */
243
        private boolean checkHighscore(final int steps, final int time, final HighscoreEntry existingEntry) {
244
                // transform level and steps information into highscore entry structure
245
                final HighscoreEntry checkEntry = new HighscoreEntry("", String.valueOf(steps), String.valueOf(time));
246
                final Comparator<HighscoreEntry> hsComp = new HighscoreEntryComparator();
247
                // return the comparison result
248
                return (hsComp.compare(existingEntry, checkEntry) > 0);
249
        }
250
 
251
        /**
252
         * checks if a given combination of level no. and steps count
253
         * leads to a new highscore
254
         * @param level game level no.
255
         * @param steps steps count
256
         * @param time time needed to solve level
257
         * @return true if new highscore, false if not
258
         */
259
        public boolean isHighscore(final int level, final int steps, final int time) {
260
                if (highscores.get(level) == null)
261
                        return true;
262
                if (highscores.get(level).size() < MAX_HIGHSCORES) // if highscore count is less than MAX_HIGHSCORES
263
                        return true;
264
                return checkHighscore(steps, time, highscores.get(level).get(MAX_HIGHSCORES - 1)); // return the comparison result
265
        }
266
 
267
        /**
268
         * calculates the place of a combination of
269
         * level no. and steps count in highscore list
270
         * @param level game level no.
271
         * @param steps steps made
272
         * @param time time needed to solve level
273
         * @return calculated ranking in highscore list
274
         */
275
        public int getPlace(final int level, final int steps, final int time) {
276
                int place = 1; // initial ranking
277
                if (highscores.get(level) == null)
278
                        return place;
279
                for (final HighscoreEntry row: highscores.get(level)) {
280
                        if (checkHighscore(steps, time, row)) // level+steps combination is better than actual row?
281
                                return place; // return this rank
282
                        place++;
283
                }
284
                return place; // if no highscores were made we assume 1st place, else last place
285
        }
286
 
287
        /**
288
         * returns the highscore count for a specified level
289
         * @param level level no.
290
         * @return highscore count
291
         */
292
        public int getHighscoreCount(final int level) {
293
                if (highscores.get(level) == null)
294
                        return 0;
295
                return highscores.get(level).size();
296
        }
297
 
298
        /**
299
         * counts ALL global highscore entries
300
         * @return
301
         */
302
        public int getAllHighscoresCount() {
303
                int count = 0;
304
                for (final ArrayList<HighscoreEntry> hsData : highscores.values())
305
                        count += hsData.size();
306
                return count;
307
        }
308
}