View Javadoc

1   /***
2    * Jetrix TetriNET Server
3    * Copyright (C) 2001-2003  Emmanuel Bourg
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18   */
19  
20  package net.jetrix.winlist;
21  
22  import java.io.*;
23  import java.util.*;
24  import java.util.logging.*;
25  
26  import net.jetrix.messages.channel.*;
27  import net.jetrix.config.*;
28  import net.jetrix.*;
29  
30  /***
31   * A standard winlist using the same scoring as the original TetriNET : the
32   * winner gets 3 points if there was 3 or more players (or different teams)
33   * involved in the game, 2 points otherwise; the second gets 1 point if there
34   * was 5 or more players in the game. The winlist is saved in a xxxx.winlist
35   * file.
36   *
37   * @author Emmanuel Bourg
38   * @version $Revision: 812 $, $Date: 2009-09-13 23:35:55 +0200 (Sun, 13 Sep 2009) $
39   */
40  public class SimpleWinlist implements Winlist
41  {
42      private String id;
43      protected List<Score> scores;
44      protected boolean initialized = false;
45      protected boolean persistent = true;
46  
47      protected Logger log = Logger.getLogger("net.jetrix");
48      protected WinlistConfig config;
49  
50      public SimpleWinlist()
51      {
52          scores = new ArrayList<Score>();
53      }
54  
55      public String getId()
56      {
57          return id;
58      }
59  
60      public void setId(String id)
61      {
62          this.id = id;
63      }
64  
65      public void init(WinlistConfig config)
66      {
67          this.config = config;
68      }
69  
70      public WinlistConfig getConfig()
71      {
72          return config;
73      }
74  
75      public boolean isPersistent()
76      {
77          return persistent;
78      }
79  
80      public void setPersistent(boolean persistent)
81      {
82          this.persistent = persistent;
83      }
84  
85      public synchronized Score getScore(String name, int type)
86      {
87          if (!initialized && persistent)
88          {
89              load();
90          }
91  
92          Score score = null;
93  
94          Score example = new Score();
95          example.setName(name);
96          example.setType(type);
97  
98          int i = scores.indexOf(example);
99          if (i != -1)
100         {
101             score = scores.get(i);
102         }
103 
104         return score;
105     }
106 
107     public synchronized List<Score> getScores(long offset, long length)
108     {
109         if (!initialized && persistent)
110         {
111             load();
112         }
113 
114         return scores.subList(0, Math.min(scores.size(), (int) length));
115     }
116 
117     public synchronized void saveGameResult(GameResult result)
118     {
119         if (!initialized && persistent)
120         {
121             load();
122         }
123 
124         int teamCount = result.getTeamCount();
125         if (teamCount == 1)
126         {
127             return;
128         }
129 
130         // reward the winning player or team
131         Score score1 = null;
132         long previousRank1 = 0;
133         long previousScore1 = 0;
134         Collection<GamePlayer> winners = result.getPlayersAtRank(1);
135         GamePlayer winner = winners.iterator().next();
136 
137         if (winner.isWinner())
138         {
139             String name = winner.getTeamName() == null ? winner.getName() : winner.getTeamName();
140             int type = winner.getTeamName() == null ? Score.TYPE_PLAYER : Score.TYPE_TEAM;
141             score1 = getScore(name, type);
142             previousRank1 = scores.indexOf(score1) + 1;
143             previousRank1 = previousRank1 == 0 ? scores.size() + 1 : previousRank1;
144 
145             if (score1 == null)
146             {
147                 // add a new entry into the winlist
148                 score1 = new Score();
149                 score1.setName(name);
150                 score1.setType(type);
151                 scores.add(score1);
152             }
153 
154             previousScore1 = score1.getScore();
155             int points = teamCount >= 3 ? 3 : 2;
156             score1.setScore(score1.getScore() + points);
157         }
158 
159         // reward the second player or team
160         Score score2 = null;
161         long previousRank2 = 0;
162         long previousScore2 = 0;
163         Collection<GamePlayer> seconds = result.getPlayersAtRank(2);
164         GamePlayer second = seconds.iterator().next();
165 
166         if (teamCount >= 5)
167         {
168             String name = second.getTeamName() == null ? second.getName() : second.getTeamName();
169             int type = second.getTeamName() == null ? Score.TYPE_PLAYER : Score.TYPE_TEAM;
170             score2 = getScore(name, type);
171             previousRank2 = scores.indexOf(score1) + 1;
172             previousRank2 = previousRank2 == 0 ? scores.size() + 1 : previousRank2;
173 
174             if (score2 == null)
175             {
176                 // add a new entry into the winlist
177                 score2 = new Score();
178                 score2.setName(name);
179                 score2.setType(type);
180                 scores.add(score2);
181             }
182 
183             previousScore2 = score2.getScore();
184             score2.setScore(score2.getScore() + 1);
185         }
186 
187         // sort the winlist
188         Collections.sort(scores, new ScoreComparator());
189 
190         // announce the new scores of the winners
191         Channel channel = result.getChannel();
192         if (channel != null && config.getBoolean("display.score", false))
193         {
194             channel.send(getGainMessage(score1, previousScore1, previousRank1));
195             if (score2 != null)
196             {
197                 channel.send(getGainMessage(score2, previousScore2, previousRank2));
198             }
199         }
200 
201         // save the winlist to the external file
202         if (persistent)
203         {
204             save();
205         }
206     }
207 
208     public void clear()
209     {
210         scores.clear();
211         save();
212     }
213 
214     public int size()
215     {
216         return scores.size();
217     }
218 
219     /***
220      * Load the winlist from a file.
221      */
222     protected void load()
223     {
224         if (log.isLoggable(Level.FINE))
225         {
226             log.fine("loading winlist " + getId());
227         }
228 
229         if (id != null)
230         {
231             BufferedReader reader = null;
232             File file = new File(id + ".winlist");
233             if (file.exists())
234             {
235                 try
236                 {
237                     reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), ServerConfig.ENCODING));
238                     String line;
239                     while ((line = reader.readLine()) != null)
240                     {
241                         String[] fields = line.split("\t");
242                         Score score = new Score();
243                         score.setName(fields[2]);
244                         score.setScore(Long.parseLong(fields[1]));
245                         score.setType("p".equals(fields[0]) ? Score.TYPE_PLAYER : Score.TYPE_TEAM);
246                         scores.add(score);
247                     }
248                 }
249                 catch (Exception e)
250                 {
251                     log.log(Level.WARNING, "Unable to read the winlist file " + file, e);
252                 }
253                 finally
254                 {
255                     close(reader);
256                 }
257             }
258         }
259 
260         initialized = true;
261     }
262 
263     /***
264      * Save the winlist to a file.
265      */
266     protected void save()
267     {
268         if (id != null)
269         {
270             BufferedWriter writer = null;
271             File file = new File(id + ".winlist");
272             try
273             {
274                 writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), ServerConfig.ENCODING));
275 
276                 for (Score score : scores)
277                 {
278                     StringBuilder line = new StringBuilder();
279                     line.append(score.getType() == Score.TYPE_PLAYER ? "p" : "t");
280                     line.append("\t");
281                     line.append(score.getScore());
282                     line.append("\t");
283                     line.append(score.getName());
284                     line.append("\n");
285                     writer.write(line.toString());
286                 }
287                 writer.flush();
288             }
289             catch (Exception e)
290             {
291                 log.log(Level.WARNING, "Unable to write the winlist file " + file, e);
292             }
293             finally
294             {
295                 close(writer);
296             }
297         }
298     }
299 
300     /***
301      * Build a message displaying the new score and rank of a winner.
302      */
303     protected PlineMessage getGainMessage(Score score, long previousScore, long previousRank)
304     {
305         StringBuilder key = new StringBuilder();
306         key.append("channel.score.");
307         key.append(score.getType() == Score.TYPE_PLAYER ? "player" : "team");
308         key.append(".");
309         key.append(score.getScore() - previousScore > 1 ? "points" : "point");
310 
311         long rank = scores.indexOf(score) + 1;
312         if (rank == 0)
313         {
314             rank = scores.size() + 1;
315         }
316 
317         PlineMessage message = new PlineMessage();
318         message.setKey(key.toString(), score.getName(), score.getScore() - previousScore, score.getScore(), rank, previousRank - rank);
319         return message;
320     }
321 
322     /***
323      * Close quietly the specified stream or reader.
324      */
325     void close(Closeable closeable)
326     {
327         if (closeable != null)
328         {
329             try
330             {
331                 closeable.close();
332             }
333             catch (IOException e)
334             {
335             }
336         }
337     }
338 
339 }