1 /** 2 * The freechess.org connection library. 3 * More information is available at http://www.jinchess.com/. 4 * Copyright (C) 2002 Alexander Maryanovsky. 5 * All rights reserved. 6 * 7 * The freechess.org connection library is free software; you can redistribute 8 * it and/or modify it under the terms of the GNU Lesser General Public License 9 * as published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * The freechess.org connection library is distributed in the hope that it will 13 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with the freechess.org connection library; if not, write to the Free 19 * Software Foundation, Inc., 20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23 package free.freechess; 24 25 import free.util.Struct; 26 import java.util.StringTokenizer; 27 28 29 /** 30 * A structure holding parsed information from a seekinfo line. More information 31 * about the format is available in the "help iv_seekinfo" file on the Free 32 * Internet Chess Server (http://www.freechess.org). 33 */ 34 35 public class SeekInfoStruct extends Struct{ 36 37 38 39 /** 40 * The bit mask for an unregistered player. 41 */ 42 43 public static final int UNREGISTERED = 0x1; 44 45 46 47 48 /** 49 * The bit mask for a computer player. 50 */ 51 52 public static final int COMPUTER = 0x2; 53 54 55 56 57 /** 58 * The bit mask for a GM. 59 */ 60 61 public static final int GM = 0x4; 62 63 64 65 66 /** 67 * The bit mask for an IM. 68 */ 69 70 public static final int IM = 0x8; 71 72 73 74 75 /** 76 * The bit mask for an FM. 77 */ 78 79 public static final int FM = 0x10; 80 81 82 83 84 /** 85 * The bit mask for a WGM. 86 */ 87 88 public static final int WGM = 0x20; 89 90 91 92 93 /** 94 * The bit mask for a WIM. 95 */ 96 97 public static final int WIM = 0x40; 98 99 100 101 102 /** 103 * The bit mask for a WFM. 104 */ 105 106 public static final int WFM = 0x80; 107 108 109 110 111 /** 112 * Creates a new SeekInfoStruct with the specified arguments. 113 * 114 * @param canAcceptSeek <code>true</code> if the user can accept the seek, 115 * <code>false</code> otherwise. 116 * @param index The seek index. 117 * @param name The handle of the seeking player. 118 * @param titles The titles of the player, ORed into an int. 119 * @param rating The rating of the player. 120 * @param provShow The seeker's rating provshow character, 'E' is estimated, 121 * 'P' if provisional and ' ' if neither. 122 * @param time The time of the sought game, in minutes. 123 * @param inc The increment of the sought game, in seconds. 124 * @param isRated The ratedness of the sought game. 125 * @param matchType The type of the match (either variant or rating type - 126 * "suicide", "lightning", "blitz" etc.). 127 * @param color The requested color. 'W' if white, 'B' if black and '?' if 128 * doesn't care. 129 * @param minRating The minimum rating of the sought opponent. 130 * @param maxRating The maximum rating of the sought opponent. 131 * @param isAutomaticAccept <code>true</code> if the acceptance of the seek is 132 * automatic, <code>false</code> if manual. 133 * @param isFormulaUsed <code>true</code> if the you must pass the seeker's 134 * formula to accept the offer. 135 */ 136 SeekInfoStruct(boolean canAcceptSeek, int index, String name, int titles, int rating, char provshow, int time, int inc, boolean isRated, String matchType, char color, int minRating, int maxRating, boolean isAutomaticAccept, boolean isFormulaUsed)137 public SeekInfoStruct(boolean canAcceptSeek, int index, String name, int titles, int rating, 138 char provshow, int time, int inc, boolean isRated, String matchType, char color, 139 int minRating, int maxRating, boolean isAutomaticAccept, boolean isFormulaUsed){ 140 141 if (time < 0) 142 throw new IllegalArgumentException("The game's initial time ("+time+") may not be negative"); 143 144 if (inc < 0) 145 throw new IllegalArgumentException("The game's increment ("+inc+") may not be negative"); 146 147 switch (color){ 148 case '?': 149 case 'W': 150 case 'B': 151 break; 152 default: 153 throw new IllegalArgumentException("Bad color character: "+color); 154 } 155 156 setBooleanProperty("CanAcceptSeek", canAcceptSeek); 157 setIntegerProperty("Index", index); 158 setStringProperty("Name", name); 159 setIntegerProperty("Titles", titles); 160 setIntegerProperty("Rating", rating); 161 setCharProperty("ProvShow", provshow); 162 setIntegerProperty("Time", time); 163 setIntegerProperty("Increment", inc); 164 setBooleanProperty("IsRated", isRated); 165 setStringProperty("MatchType", matchType); 166 setCharProperty("RequestedColor", color); 167 setIntegerProperty("MinRating", minRating); 168 setIntegerProperty("MaxRating", maxRating); 169 setBooleanProperty("IsAutomaticAccept", isAutomaticAccept); 170 setBooleanProperty("IsFormulaUsed", isFormulaUsed); 171 } 172 173 174 175 176 /** 177 * Parses the given seekinfo line and returns a corresponding SeekInfoStruct 178 * object. Here's an example seekinfo line:<PRE> 179 * <s> 29 w=Snaps ti=02 rt=1532 t=1 i=0 r=r tp=lightning c=? rr=0-9999 a=t f=t 180 * </PRE> 181 * If the seek cannot be accepted by the user, the line identifier is "<sn>" 182 * and not "<s>". 183 * More information about the format is available in the FICS iv_seekinfo 184 * help file. 185 */ 186 parseSeekInfoLine(String line)187 public static SeekInfoStruct parseSeekInfoLine(String line){ 188 StringTokenizer tokens = new StringTokenizer(line, " -="); 189 190 boolean canAcceptSeek; 191 String identifier = tokens.nextToken(); 192 if (identifier.equals("<s>")) // Skip the <s> identifier 193 canAcceptSeek = true; 194 else if (identifier.equals("<sn>")) 195 canAcceptSeek = false; 196 else 197 throw new IllegalArgumentException("Missing \"<s>\" or \"<sn>\" identifier"); 198 199 int index = Integer.parseInt(tokens.nextToken()); 200 201 assertToken(tokens, "w"); // w= 202 String name = tokens.nextToken(); 203 204 assertToken(tokens, "ti"); // ti= 205 int titles = Integer.parseInt(tokens.nextToken(), 16); 206 207 assertToken(tokens, "rt"); // rt= 208 String ratingString = tokens.nextToken(); 209 char provShow = ' '; 210 if (!Character.isDigit(ratingString.charAt(ratingString.length() - 1))){ 211 provShow = ratingString.charAt(ratingString.length() - 1); 212 ratingString = ratingString.substring(0, ratingString.length() - 1); 213 } 214 int rating = Integer.parseInt(ratingString); 215 216 assertToken(tokens, "t"); // t= 217 int time = Integer.parseInt(tokens.nextToken()); 218 219 assertToken(tokens, "i"); // i= 220 int inc = Integer.parseInt(tokens.nextToken()); 221 222 assertToken(tokens, "r"); // r= 223 boolean isRated = tokens.nextToken().equals("r"); 224 225 assertToken(tokens, "tp"); // tp= 226 String matchType = tokens.nextToken(); 227 228 assertToken(tokens, "c"); // c= 229 char requestedColor = tokens.nextToken().charAt(0); 230 231 assertToken(tokens, "rr"); // rr= 232 int minRating = Integer.parseInt(tokens.nextToken()); 233 int maxRating = Integer.parseInt(tokens.nextToken()); 234 235 assertToken(tokens, "a"); // a= 236 boolean isAutomaticAccept = tokens.nextToken().equals("t"); 237 238 assertToken(tokens, "f"); // f= 239 boolean isFormulaUsed = tokens.nextToken().equals("t"); 240 241 return new SeekInfoStruct(canAcceptSeek, index, name, titles, rating, provShow, 242 time, inc, isRated, matchType, requestedColor, minRating, maxRating, 243 isAutomaticAccept, isFormulaUsed); 244 } 245 246 247 248 249 /** 250 * Checks that the next token for the given StringTokenizer is the specified 251 * String. Throws an IllegalArgumentException if it isn't. 252 */ 253 assertToken(StringTokenizer tokenizer, String token)254 private static void assertToken(StringTokenizer tokenizer, String token){ 255 String realToken = tokenizer.nextToken(); 256 if (!realToken.equals(token)) 257 throw new IllegalArgumentException("Bad token \""+realToken+"\", expected \""+token+"\" instead"); 258 } 259 260 261 262 263 /** 264 * Returns <code>true</code> if the user account can accept the seek, returns 265 * <code>false</code> otherwise. 266 */ 267 canAcceptSeek()268 public boolean canAcceptSeek(){ 269 return getBooleanProperty("CanAcceptSeek"); 270 } 271 272 273 274 275 /** 276 * Returns the index of the seek. 277 */ 278 getSeekIndex()279 public int getSeekIndex(){ 280 return getIntegerProperty("Index"); 281 } 282 283 284 285 286 /** 287 * Returns the handle of the seeking player. 288 */ 289 getSeekerHandle()290 public String getSeekerHandle(){ 291 return getStringProperty("Name"); 292 } 293 294 295 296 297 /** 298 * Returns the titles of the seeking player, ORed into an int. To find whether 299 * the player is GM, for example, use 300 * <code>(getSeekerTitles() & SeekInfoStruct.GM) != 0</code>. 301 */ 302 getSeekerTitles()303 public int getSeekerTitles(){ 304 return getIntegerProperty("Titles"); 305 } 306 307 308 309 310 /** 311 * Returns the seeker's rating. 312 */ 313 getSeekerRating()314 public int getSeekerRating(){ 315 return getIntegerProperty("Rating"); 316 } 317 318 319 320 321 /** 322 * Returns the seeker rating's provshow character. 'E' if the rating is 323 * estimated, 'P' if provisional, and ' ' if neither. 324 */ 325 getSeekerProvShow()326 public char getSeekerProvShow(){ 327 return getCharProperty("ProvShow"); 328 } 329 330 331 332 333 /** 334 * Returns the initial time of the sought match, in minutes. 335 */ 336 getMatchTime()337 public int getMatchTime(){ 338 return getIntegerProperty("Time"); 339 } 340 341 342 343 344 /** 345 * Returns the increment of the sought match, in seconds. 346 */ 347 getMatchIncrement()348 public int getMatchIncrement(){ 349 return getIntegerProperty("Increment"); 350 } 351 352 353 354 355 /** 356 * Returns <code>true</code> if the sought match is rated, <code>false</code> 357 * otherwise. 358 */ 359 isMatchRated()360 public boolean isMatchRated(){ 361 return getBooleanProperty("IsRated"); 362 } 363 364 365 366 367 /** 368 * Returns the sought game type. Either the name of the wild variant, or the 369 * rating type, if the variant is chess. For example - "suicide", "lightning", 370 * "blitz" etc. 371 */ 372 getMatchType()373 public String getMatchType(){ 374 return getStringProperty("MatchType"); 375 } 376 377 378 379 380 /** 381 * Returns a character specifying the desired color for the seeker. 'W' if 382 * white, 'B' if black, and '?' if the seeker doesn't care. 383 */ 384 getSeekerColor()385 public char getSeekerColor(){ 386 return getCharProperty("RequestedColor"); 387 } 388 389 390 391 392 /** 393 * Returns the minimum rating of the desired opponent. 394 */ 395 getOpponentMinRating()396 public int getOpponentMinRating(){ 397 return getIntegerProperty("MinRating"); 398 } 399 400 401 402 403 /** 404 * Returns the maximum rating of the desired opponent. 405 */ 406 getOpponentMaxRating()407 public int getOpponentMaxRating(){ 408 return getIntegerProperty("MaxRating"); 409 } 410 411 412 413 414 /** 415 * Returns <code>true</code> if the match will be accepted automatically, 416 * <code>false</code> if the seeker must confirm it manually. 417 */ 418 isAutomaticAccept()419 public boolean isAutomaticAccept(){ 420 return getBooleanProperty("IsAutomaticAccept"); 421 } 422 423 424 425 426 /** 427 * Returns <code>true</code> if in order to accept the seek, one must pass 428 * the formula of the seeker. Returns <code>false</code> otherwise. 429 */ 430 isFormulaUsed()431 public boolean isFormulaUsed(){ 432 return getBooleanProperty("IsFormulaUsed"); 433 } 434 435 436 } 437